]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'mfd-lj/for-mfd-next'
authorStephen Rothwell <sfr@canb.auug.org.au>
Fri, 2 Aug 2013 05:00:48 +0000 (15:00 +1000)
committerStephen Rothwell <sfr@canb.auug.org.au>
Fri, 2 Aug 2013 05:00:48 +0000 (15:00 +1000)
1474 files changed:
.gitignore
Documentation/DocBook/device-drivers.tmpl
Documentation/DocBook/drm.tmpl
Documentation/DocBook/media/v4l/lirc_device_interface.xml
Documentation/DocBook/media/v4l/vidioc-g-jpegcomp.xml
Documentation/DocBook/media_api.tmpl
Documentation/devicetree/bindings/hid/hid-over-i2c.txt [new file with mode: 0644]
Documentation/devicetree/bindings/media/i2c/adv7343.txt [new file with mode: 0644]
Documentation/devicetree/bindings/media/i2c/ths8200.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/atmel-nand.txt
Documentation/devicetree/bindings/mtd/fsmc-nand.txt
Documentation/devicetree/bindings/sound/ak4554.c [new file with mode: 0644]
Documentation/devicetree/bindings/sound/atmel-wm8904.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/fsl,ssi.txt [moved from Documentation/devicetree/bindings/powerpc/fsl/ssi.txt with 100% similarity]
Documentation/devicetree/bindings/sound/ti,pcm1681.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/tlv320aic3x.txt
Documentation/devicetree/bindings/sound/wm8994.txt
Documentation/devicetree/bindings/tty/serial/renesas,sci-serial.txt [new file with mode: 0644]
Documentation/filesystems/ext3.txt
Documentation/filesystems/f2fs.txt
Documentation/hid/uhid.txt
Documentation/hwmon/w83791d
Documentation/hwmon/w83792d
Documentation/kbuild/kconfig.txt
Documentation/kernel-parameters.txt
Documentation/laptops/asus-laptop.txt
Documentation/laptops/sony-laptop.txt
Documentation/laptops/thinkpad-acpi.txt
Documentation/networking/00-INDEX
Documentation/networking/ip-sysctl.txt
Documentation/networking/netdev-FAQ.txt [new file with mode: 0644]
Documentation/networking/sctp.txt
Documentation/sound/alsa/HD-Audio-Models.txt
Documentation/sound/alsa/HD-Audio.txt
Documentation/sysctl/net.txt
MAINTAINERS
arch/arc/boot/.gitignore [new file with mode: 0644]
arch/arc/include/asm/entry.h
arch/arc/include/asm/irqflags.h
arch/arc/include/asm/mmu.h
arch/arc/include/asm/mmu_context.h
arch/arc/include/asm/pgtable.h
arch/arc/include/asm/ptrace.h
arch/arc/include/asm/tlbflush.h
arch/arc/kernel/.gitignore [new file with mode: 0644]
arch/arc/kernel/entry.S
arch/arc/kernel/smp.c
arch/arc/mm/Makefile
arch/arc/mm/tlb.c
arch/arc/mm/tlbex.S
arch/arc/mm/tlbflush.c [new file with mode: 0644]
arch/arm/Kconfig
arch/arm/Kconfig.debug
arch/arm/Makefile
arch/arm/include/asm/a.out-core.h [deleted file]
arch/arm/include/asm/cputype.h
arch/arm/include/asm/hardware/debug-8250.S [deleted file]
arch/arm/include/asm/mach/arch.h
arch/arm/include/asm/memblock.h
arch/arm/include/asm/mmu.h
arch/arm/include/asm/mmu_context.h
arch/arm/include/asm/neon.h [new file with mode: 0644]
arch/arm/include/asm/processor.h
arch/arm/include/asm/prom.h
arch/arm/include/asm/thread_info.h
arch/arm/include/asm/tlbflush.h
arch/arm/include/asm/virt.h
arch/arm/include/asm/xor.h
arch/arm/include/debug/8250.S [new file with mode: 0644]
arch/arm/include/debug/8250_32.S [deleted file]
arch/arm/include/debug/bcm2835.S [deleted file]
arch/arm/include/debug/cns3xxx.S [deleted file]
arch/arm/include/debug/highbank.S [deleted file]
arch/arm/include/debug/keystone.S [deleted file]
arch/arm/include/debug/mvebu.S [deleted file]
arch/arm/include/debug/mxs.S [deleted file]
arch/arm/include/debug/nomadik.S [deleted file]
arch/arm/include/debug/nspire.S [deleted file]
arch/arm/include/debug/picoxcell.S [deleted file]
arch/arm/include/debug/pl01x.S [moved from arch/arm/include/asm/hardware/debug-pl01x.S with 78% similarity]
arch/arm/include/debug/pxa.S [deleted file]
arch/arm/include/debug/rockchip.S [deleted file]
arch/arm/include/debug/socfpga.S [deleted file]
arch/arm/include/debug/sunxi.S [deleted file]
arch/arm/include/debug/u300.S [deleted file]
arch/arm/include/debug/ux500.S
arch/arm/include/debug/vexpress.S
arch/arm/include/uapi/asm/Kbuild
arch/arm/include/uapi/asm/a.out.h [deleted file]
arch/arm/kernel/atags.h
arch/arm/kernel/atags_parse.c
arch/arm/kernel/devtree.c
arch/arm/kernel/entry-v7m.S
arch/arm/kernel/head-nommu.S
arch/arm/kernel/head.S
arch/arm/kernel/hyp-stub.S
arch/arm/kernel/process.c
arch/arm/kernel/setup.c
arch/arm/kernel/smp_tlb.c
arch/arm/lib/Makefile
arch/arm/lib/xor-neon.c [new file with mode: 0644]
arch/arm/mach-davinci/board-da850-evm.c
arch/arm/mach-davinci/cpuidle.c
arch/arm/mach-davinci/include/mach/debug-macro.S [deleted file]
arch/arm/mach-dove/include/mach/debug-macro.S [deleted file]
arch/arm/mach-ebsa110/include/mach/debug-macro.S [deleted file]
arch/arm/mach-ep93xx/Kconfig
arch/arm/mach-ep93xx/include/mach/debug-macro.S [deleted file]
arch/arm/mach-ep93xx/include/mach/uncompress.h
arch/arm/mach-footbridge/include/mach/debug-macro.S
arch/arm/mach-gemini/include/mach/debug-macro.S [deleted file]
arch/arm/mach-integrator/include/mach/debug-macro.S [deleted file]
arch/arm/mach-iop13xx/include/mach/debug-macro.S [deleted file]
arch/arm/mach-iop32x/include/mach/debug-macro.S [deleted file]
arch/arm/mach-iop33x/include/mach/debug-macro.S [deleted file]
arch/arm/mach-ixp4xx/include/mach/debug-macro.S [deleted file]
arch/arm/mach-kirkwood/include/mach/debug-macro.S [deleted file]
arch/arm/mach-lpc32xx/include/mach/debug-macro.S [deleted file]
arch/arm/mach-mv78xx0/include/mach/debug-macro.S [deleted file]
arch/arm/mach-orion5x/include/mach/debug-macro.S [deleted file]
arch/arm/mach-realview/include/mach/debug-macro.S [deleted file]
arch/arm/mach-rpc/include/mach/debug-macro.S [deleted file]
arch/arm/mach-spear/include/mach/debug-macro.S [deleted file]
arch/arm/mach-spear/include/mach/spear.h
arch/arm/mach-ux500/Makefile
arch/arm/mach-versatile/include/mach/debug-macro.S [deleted file]
arch/arm/mm/context.c
arch/arm/mm/hugetlbpage.c
arch/arm/mm/init.c
arch/arm/mm/mmu.c
arch/arm/mm/nommu.c
arch/arm/mm/proc-v7-2level.S
arch/arm/mm/proc-v7-3level.S
arch/arm/mm/proc-v7.S
arch/arm/vfp/vfphw.S
arch/arm/vfp/vfpmodule.c
arch/arm/xen/enlighten.c
arch/avr32/mach-at32ap/at32ap700x.c
arch/cris/Kconfig
arch/cris/arch-v10/drivers/Kconfig
arch/cris/arch-v10/drivers/Makefile
arch/cris/arch-v32/drivers/Kconfig
arch/cris/arch-v32/mach-a3/Kconfig
arch/cris/include/asm/processor.h
arch/cris/include/uapi/asm/kvm_para.h [new file with mode: 0644]
arch/frv/mb93090-mb00/pci-vdk.c
arch/ia64/configs/generic_defconfig
arch/ia64/configs/gensparse_defconfig
arch/ia64/configs/tiger_defconfig
arch/ia64/configs/xen_domu_defconfig
arch/ia64/include/asm/dmi.h
arch/ia64/kernel/elfcore.c
arch/m68k/kernel/setup_no.c
arch/m68k/kernel/signal.c
arch/m68k/platform/68000/m68328.c
arch/m68k/platform/68000/m68EZ328.c
arch/m68k/platform/68000/m68VZ328.c
arch/m68k/platform/68360/commproc.c
arch/m68k/platform/68360/config.c
arch/metag/Kconfig.soc
arch/metag/boot/dts/tz1090.dtsi
arch/microblaze/pci/pci-common.c
arch/mips/Kconfig
arch/mips/bcm47xx/Kconfig
arch/mips/bcm63xx/nvram.c
arch/mips/cavium-octeon/setup.c
arch/mips/include/asm/Kbuild
arch/mips/include/asm/cpu.h
arch/mips/include/asm/cputime.h [deleted file]
arch/mips/include/asm/current.h [deleted file]
arch/mips/include/asm/emergency-restart.h [deleted file]
arch/mips/include/asm/local64.h [deleted file]
arch/mips/include/asm/mach-bcm63xx/bcm63xx_nvram.h
arch/mips/include/asm/mach-generic/spaces.h
arch/mips/include/asm/mutex.h [deleted file]
arch/mips/include/asm/parport.h [deleted file]
arch/mips/include/asm/percpu.h [deleted file]
arch/mips/include/asm/scatterlist.h [deleted file]
arch/mips/include/asm/sections.h [deleted file]
arch/mips/include/asm/segment.h [deleted file]
arch/mips/include/asm/serial.h [deleted file]
arch/mips/include/asm/ucontext.h [deleted file]
arch/mips/include/asm/xor.h [deleted file]
arch/mips/include/uapi/asm/Kbuild
arch/mips/include/uapi/asm/auxvec.h [deleted file]
arch/mips/include/uapi/asm/ipcbuf.h [deleted file]
arch/mips/include/uapi/asm/siginfo.h
arch/mips/kernel/bmips_vec.S
arch/mips/kernel/cpu-probe.c
arch/mips/kernel/idle.c
arch/mips/kernel/smp-bmips.c
arch/mips/mm/c-octeon.c
arch/mips/mm/tlb-funcs.S
arch/mips/mm/tlbex.c
arch/mips/netlogic/xlp/usb-init.c
arch/mips/pci/pci-octeon.c
arch/mips/pnx833x/common/platform.c
arch/mips/powertv/asic/asic_devices.c
arch/powerpc/configs/ppc64_defconfig
arch/powerpc/configs/ppc64e_defconfig
arch/powerpc/configs/pseries_defconfig
arch/powerpc/include/asm/perf_event_server.h
arch/powerpc/include/asm/smp.h
arch/powerpc/include/asm/spu.h
arch/powerpc/include/uapi/asm/Kbuild
arch/powerpc/include/uapi/asm/perf_event.h [new file with mode: 0644]
arch/powerpc/kernel/irq.c
arch/powerpc/mm/numa.c
arch/powerpc/perf/core-book3s.c
arch/powerpc/perf/power8-pmu.c
arch/powerpc/platforms/cell/spu_syscalls.c
arch/powerpc/platforms/cell/spufs/coredump.c
arch/powerpc/platforms/cell/spufs/spufs.h
arch/s390/Kconfig
arch/s390/boot/compressed/Makefile
arch/s390/boot/compressed/misc.c
arch/s390/include/asm/airq.h
arch/s390/include/asm/bitops.h
arch/s390/include/asm/hardirq.h
arch/s390/include/asm/hugetlb.h
arch/s390/include/asm/hw_irq.h
arch/s390/include/asm/irq.h
arch/s390/include/asm/page.h
arch/s390/include/asm/pci.h
arch/s390/include/asm/pci_insn.h
arch/s390/include/asm/pci_io.h
arch/s390/include/asm/pgtable.h
arch/s390/include/asm/serial.h [new file with mode: 0644]
arch/s390/kernel/entry.S
arch/s390/kernel/entry64.S
arch/s390/kernel/irq.c
arch/s390/kernel/perf_event.c
arch/s390/kernel/ptrace.c
arch/s390/kernel/setup.c
arch/s390/kernel/vdso.c
arch/s390/lib/uaccess_pt.c
arch/s390/mm/dump_pagetables.c
arch/s390/mm/gup.c
arch/s390/mm/hugetlbpage.c
arch/s390/mm/init.c
arch/s390/mm/pageattr.c
arch/s390/mm/pgtable.c
arch/s390/mm/vmem.c
arch/s390/oprofile/init.c
arch/s390/pci/Makefile
arch/s390/pci/pci.c
arch/s390/pci/pci_dma.c
arch/s390/pci/pci_insn.c
arch/s390/pci/pci_msi.c [deleted file]
arch/sh/configs/sh03_defconfig
arch/sh/include/asm/hw_breakpoint.h
arch/sh/include/cpu-common/cpu/ubc.h [new file with mode: 0644]
arch/sh/include/cpu-sh2a/cpu/ubc.h [new file with mode: 0644]
arch/sh/kernel/cpu/sh2a/Makefile
arch/sh/kernel/cpu/sh2a/ubc.c [new file with mode: 0644]
arch/sh/kernel/hw_breakpoint.c
arch/sparc/include/asm/switch_to_64.h
arch/sparc/kernel/cpumap.c
arch/sparc/kernel/entry.S
arch/sparc/kernel/kgdb_64.c
arch/sparc/kernel/ptrace_64.c
arch/sparc/kernel/setup_64.c
arch/sparc/kernel/syscalls.S
arch/tile/gxio/iorpc_mpipe.c
arch/tile/gxio/iorpc_mpipe_info.c
arch/tile/gxio/mpipe.c
arch/tile/include/asm/cacheflush.h
arch/tile/include/asm/cmpxchg.h
arch/tile/include/asm/string.h
arch/tile/include/asm/uaccess.h
arch/tile/include/gxio/iorpc_mpipe.h
arch/tile/include/gxio/iorpc_mpipe_info.h
arch/tile/include/gxio/mpipe.h
arch/tile/include/hv/drv_mpipe_intf.h
arch/tile/include/uapi/asm/cachectl.h
arch/tile/kernel/hardwall.c
arch/tile/kernel/head_32.S
arch/tile/kernel/head_64.S
arch/tile/kernel/process.c
arch/tile/lib/Makefile
arch/tile/lib/cacheflush.c
arch/tile/lib/exports.c
arch/tile/lib/memchr_64.c
arch/tile/lib/memcpy_64.c
arch/tile/lib/memset_32.c
arch/tile/lib/memset_64.c
arch/tile/lib/strchr_32.c
arch/tile/lib/strchr_64.c
arch/tile/lib/string-endian.h
arch/tile/lib/strlen_32.c
arch/tile/lib/strnlen_32.c [new file with mode: 0644]
arch/tile/lib/strnlen_64.c [new file with mode: 0644]
arch/tile/lib/usercopy_32.S
arch/tile/lib/usercopy_64.S
arch/x86/ia32/ia32_aout.c
arch/x86/include/asm/processor.h
arch/x86/kernel/tboot.c
arch/x86/lguest/boot.c
arch/x86/pci/i386.c
arch/x86/pci/mmconfig-shared.c
arch/x86/pci/mrst.c
arch/x86/platform/ce4100/ce4100.c
arch/x86/um/elfcore.c
crypto/testmgr.c
drivers/accessibility/braille/braille_console.c
drivers/acpi/Kconfig
drivers/acpi/ac.c
drivers/acpi/acpi_pad.c
drivers/acpi/acpi_platform.c
drivers/acpi/acpica/aclocal.h
drivers/acpi/acpica/actables.h
drivers/acpi/acpica/acutils.h
drivers/acpi/acpica/evgpeinit.c
drivers/acpi/acpica/exdump.c
drivers/acpi/acpica/hwesleep.c
drivers/acpi/acpica/nsxfname.c
drivers/acpi/acpica/tbxfroot.c
drivers/acpi/acpica/uteval.c
drivers/acpi/acpica/utosi.c
drivers/acpi/acpica/utstring.c
drivers/acpi/acpica/utxface.c
drivers/acpi/battery.c
drivers/acpi/blacklist.c
drivers/acpi/bus.c
drivers/acpi/button.c
drivers/acpi/device_pm.c
drivers/acpi/dock.c
drivers/acpi/ec.c
drivers/acpi/event.c
drivers/acpi/fan.c
drivers/acpi/internal.h
drivers/acpi/osl.c
drivers/acpi/pci_irq.c
drivers/acpi/pci_slot.c
drivers/acpi/power.c
drivers/acpi/processor_driver.c
drivers/acpi/processor_perflib.c
drivers/acpi/resource.c
drivers/acpi/sbs.c
drivers/acpi/scan.c
drivers/acpi/sleep.c
drivers/acpi/thermal.c
drivers/acpi/utils.c
drivers/acpi/video.c
drivers/acpi/video_detect.c
drivers/ata/libata-acpi.c
drivers/ata/libata.h
drivers/ata/pata_at32.c
drivers/ata/pata_at91.c
drivers/ata/pata_imx.c
drivers/ata/pata_ixp4xx_cf.c
drivers/ata/pata_octeon_cf.c
drivers/ata/pata_platform.c
drivers/ata/pata_pxa.c
drivers/ata/pata_samsung_cf.c
drivers/ata/sata_mv.c
drivers/base/power/main.c
drivers/bcma/Kconfig
drivers/bcma/main.c
drivers/bcma/scan.c
drivers/bluetooth/ath3k.c
drivers/bluetooth/btmrvl_debugfs.c
drivers/bluetooth/btusb.c
drivers/char/hw_random/mxc-rnga.c
drivers/char/sonypi.c
drivers/char/virtio_console.c
drivers/cpufreq/Makefile
drivers/cpufreq/acpi-cpufreq.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_governor.c
drivers/cpufreq/cpufreq_governor.h
drivers/cpufreq/cpufreq_ondemand.c
drivers/cpufreq/cpufreq_stats.c
drivers/cpufreq/mperf.c [deleted file]
drivers/cpufreq/mperf.h [deleted file]
drivers/cpuidle/Kconfig
drivers/cpuidle/Kconfig.arm [new file with mode: 0644]
drivers/cpuidle/Makefile
drivers/cpuidle/cpuidle-ux500.c [moved from arch/arm/mach-ux500/cpuidle.c with 90% similarity]
drivers/cpuidle/cpuidle.c
drivers/cpuidle/governors/ladder.c
drivers/cpuidle/governors/menu.c
drivers/cpuidle/sysfs.c
drivers/crypto/Kconfig
drivers/crypto/caam/caamalg.c
drivers/crypto/caam/caamhash.c
drivers/crypto/caam/ctrl.c
drivers/crypto/caam/desc_constr.h
drivers/crypto/caam/intern.h
drivers/crypto/caam/jr.c
drivers/crypto/caam/jr.h
drivers/crypto/caam/regs.h
drivers/crypto/omap-sham.c
drivers/crypto/ux500/hash/hash_core.c
drivers/dma/acpi-dma.c
drivers/dma/dw/core.c
drivers/dma/dw/platform.c
drivers/dma/edma.c
drivers/dma/ep93xx_dma.c
drivers/dma/fsldma.c
drivers/dma/imx-sdma.c
drivers/dma/ipu/ipu_idmac.c
drivers/dma/mmp_pdma.c
drivers/dma/mmp_tdma.c
drivers/dma/mpc512x_dma.c
drivers/dma/mxs-dma.c
drivers/dma/pch_dma.c
drivers/dma/pl330.c
drivers/dma/tegra20-apb-dma.c
drivers/dma/txx9dmac.c
drivers/edac/tile_edac.c
drivers/firewire/core-cdev.c
drivers/firewire/core-transaction.c
drivers/firewire/ohci.c
drivers/firmware/dmi_scan.c
drivers/gpu/drm/Makefile
drivers/gpu/drm/ast/ast_main.c
drivers/gpu/drm/cirrus/cirrus_main.c
drivers/gpu/drm/drm_bufs.c
drivers/gpu/drm/drm_context.c
drivers/gpu/drm/drm_drv.c
drivers/gpu/drm/drm_fops.c
drivers/gpu/drm/drm_gem.c
drivers/gpu/drm/drm_gem_cma_helper.c
drivers/gpu/drm/drm_mm.c
drivers/gpu/drm/drm_pci.c
drivers/gpu/drm/drm_scatter.c
drivers/gpu/drm/drm_vma_manager.c [new file with mode: 0644]
drivers/gpu/drm/exynos/exynos_ddc.c
drivers/gpu/drm/exynos/exynos_drm_fimc.c
drivers/gpu/drm/exynos/exynos_drm_fimd.c
drivers/gpu/drm/exynos/exynos_drm_g2d.c
drivers/gpu/drm/exynos/exynos_drm_gem.c
drivers/gpu/drm/exynos/exynos_drm_gsc.c
drivers/gpu/drm/exynos/exynos_drm_hdmi.c
drivers/gpu/drm/exynos/exynos_drm_ipp.c
drivers/gpu/drm/exynos/exynos_drm_rotator.c
drivers/gpu/drm/exynos/exynos_drm_vidi.c
drivers/gpu/drm/exynos/exynos_hdmi.c
drivers/gpu/drm/exynos/exynos_hdmiphy.c
drivers/gpu/drm/exynos/exynos_mixer.c
drivers/gpu/drm/gma500/framebuffer.c
drivers/gpu/drm/gma500/gem.c
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/dvo_ch7xxx.c
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_dma.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_debug.c
drivers/gpu/drm/i915/i915_gem_dmabuf.c
drivers/gpu/drm/i915/i915_gem_evict.c
drivers/gpu/drm/i915/i915_gem_execbuffer.c
drivers/gpu/drm/i915/i915_gem_gtt.c
drivers/gpu/drm/i915/i915_gem_stolen.c
drivers/gpu/drm/i915/i915_gem_tiling.c
drivers/gpu/drm/i915/i915_gpu_error.c [new file with mode: 0644]
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_sysfs.c
drivers/gpu/drm/i915/i915_trace.h
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_ddi.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_dvo.c
drivers/gpu/drm/i915/intel_fb.c
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_overlay.c
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_ringbuffer.h
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/i915/intel_sprite.c
drivers/gpu/drm/i915/intel_tv.c
drivers/gpu/drm/i915/intel_uncore.c [new file with mode: 0644]
drivers/gpu/drm/mgag200/mgag200_main.c
drivers/gpu/drm/mgag200/mgag200_mode.c
drivers/gpu/drm/mgag200/mgag200_ttm.c
drivers/gpu/drm/nouveau/core/engine/disp/hdanva3.c
drivers/gpu/drm/nouveau/core/engine/disp/hdanvd0.c
drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c
drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c
drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c
drivers/gpu/drm/nouveau/core/engine/xtensa.c
drivers/gpu/drm/nouveau/core/include/subdev/vm.h
drivers/gpu/drm/nouveau/core/subdev/fb/priv.h
drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c
drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c
drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c
drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c
drivers/gpu/drm/nouveau/core/subdev/vm/base.c
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_display.c
drivers/gpu/drm/nouveau/nouveau_drm.c
drivers/gpu/drm/nouveau/nouveau_fbcon.c
drivers/gpu/drm/nouveau/nouveau_gem.c
drivers/gpu/drm/nouveau/nv17_fence.c
drivers/gpu/drm/nouveau/nv50_fence.c
drivers/gpu/drm/omapdrm/omap_gem.c
drivers/gpu/drm/omapdrm/omap_gem_helpers.c
drivers/gpu/drm/qxl/qxl_object.h
drivers/gpu/drm/qxl/qxl_release.c
drivers/gpu/drm/r128/r128_cce.c
drivers/gpu/drm/radeon/atom.c
drivers/gpu/drm/radeon/cik.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/evergreen_hdmi.c
drivers/gpu/drm/radeon/ni.c
drivers/gpu/drm/radeon/ni_dpm.c
drivers/gpu/drm/radeon/r100.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/r600_cp.c
drivers/gpu/drm/radeon/radeon_atombios.c
drivers/gpu/drm/radeon/radeon_cp.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_kms.c
drivers/gpu/drm/radeon/radeon_object.h
drivers/gpu/drm/radeon/si.c
drivers/gpu/drm/radeon/si_dpm.c
drivers/gpu/drm/ttm/ttm_bo.c
drivers/gpu/drm/ttm/ttm_bo_util.c
drivers/gpu/drm/ttm/ttm_bo_vm.c
drivers/gpu/drm/udl/udl_gem.c
drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
drivers/gpu/host1x/drm/gem.c
drivers/hid/Kconfig
drivers/hid/Makefile
drivers/hid/hid-a4tech.c
drivers/hid/hid-apple.c
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-magicmouse.c
drivers/hid/hid-multitouch.c
drivers/hid/hid-ntrig.c
drivers/hid/hid-picolcd_debugfs.c
drivers/hid/hid-roccat-arvo.c
drivers/hid/hid-roccat-isku.c
drivers/hid/hid-roccat-kone.c
drivers/hid/hid-roccat-koneplus.c
drivers/hid/hid-roccat-kovaplus.c
drivers/hid/hid-sony.c
drivers/hid/hid-xinmo.c [new file with mode: 0644]
drivers/hid/hid-zydacron.c
drivers/hid/i2c-hid/i2c-hid.c
drivers/hid/uhid.c
drivers/hid/usbhid/hid-core.c
drivers/hid/usbhid/usbhid.h
drivers/hwmon/ads7828.c
drivers/hwmon/coretemp.c
drivers/hwmon/ds620.c
drivers/hwmon/f71805f.c
drivers/hwmon/f71882fg.c
drivers/hwmon/f75375s.c
drivers/hwmon/g762.c
drivers/hwmon/gpio-fan.c
drivers/hwmon/ina2xx.c
drivers/hwmon/it87.c
drivers/hwmon/lm87.c
drivers/hwmon/max197.c
drivers/hwmon/max6639.c
drivers/hwmon/max6697.c
drivers/hwmon/mcp3021.c
drivers/hwmon/nct6775.c
drivers/hwmon/ntc_thermistor.c
drivers/hwmon/pc87427.c
drivers/hwmon/pmbus/pmbus_core.c
drivers/hwmon/s3c-hwmon.c
drivers/hwmon/sht15.c
drivers/hwmon/smsc47m1.c
drivers/hwmon/w83627ehf.c
drivers/hwmon/w83627hf.c
drivers/hwmon/w83792d.c
drivers/ide/ide-acpi.c
drivers/infiniband/core/cma.c
drivers/infiniband/core/mad.c
drivers/infiniband/hw/cxgb3/iwch_provider.c
drivers/infiniband/hw/cxgb4/qp.c
drivers/infiniband/hw/mlx4/mad.c
drivers/infiniband/hw/mlx5/main.c
drivers/infiniband/hw/mlx5/qp.c
drivers/infiniband/hw/nes/nes_hw.c
drivers/infiniband/hw/nes/nes_verbs.c
drivers/infiniband/hw/ocrdma/ocrdma_ah.c
drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
drivers/infiniband/hw/qib/qib_iba7322.c
drivers/infiniband/hw/qib/qib_sdma.c
drivers/infiniband/ulp/ipoib/ipoib_ib.c
drivers/infiniband/ulp/ipoib/ipoib_main.c
drivers/infiniband/ulp/ipoib/ipoib_netlink.c
drivers/isdn/hardware/mISDN/hfcpci.c
drivers/macintosh/windfarm_rm31.c
drivers/md/md.c
drivers/md/md.h
drivers/md/raid5.c
drivers/md/raid5.h
drivers/media/dvb-core/dvb-usb-ids.h
drivers/media/i2c/adv7343.c
drivers/media/i2c/ml86v7667.c
drivers/media/i2c/ths8200.c
drivers/media/i2c/tvp514x.c
drivers/media/i2c/tvp7002.c
drivers/media/pci/bt8xx/bttv-cards.c
drivers/media/pci/bt8xx/bttvp.h
drivers/media/pci/cx23885/cx23885-av.c
drivers/media/pci/cx23885/cx23885-dvb.c
drivers/media/pci/cx23885/cx23885-video.c
drivers/media/pci/cx23885/cx23885-video.h [new file with mode: 0644]
drivers/media/platform/coda.c
drivers/media/platform/coda.h
drivers/media/platform/davinci/vpbe_display.c
drivers/media/platform/davinci/vpbe_osd.c
drivers/media/platform/davinci/vpbe_venc.c
drivers/media/platform/davinci/vpif_capture.c
drivers/media/platform/davinci/vpif_capture.h
drivers/media/platform/davinci/vpif_display.c
drivers/media/platform/davinci/vpif_display.h
drivers/media/platform/davinci/vpss.c
drivers/media/platform/marvell-ccic/cafe-driver.c
drivers/media/platform/marvell-ccic/mcam-core.c
drivers/media/platform/marvell-ccic/mcam-core.h
drivers/media/platform/marvell-ccic/mmp-driver.c
drivers/media/platform/s5p-g2d/g2d.c
drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
drivers/media/platform/soc_camera/soc_camera.c
drivers/media/radio/radio-aztech.c
drivers/media/radio/radio-maxiradio.c
drivers/media/rc/ene_ir.c
drivers/media/rc/ene_ir.h
drivers/media/rc/iguanair.c
drivers/media/rc/ir-lirc-codec.c
drivers/media/rc/lirc_dev.c
drivers/media/rc/rc-main.c
drivers/media/rc/redrat3.c
drivers/media/usb/dvb-usb-v2/Kconfig
drivers/media/usb/dvb-usb/dib0700_devices.c
drivers/media/usb/dvb-usb/m920x.c
drivers/media/usb/em28xx/em28xx-i2c.c
drivers/media/usb/em28xx/em28xx-video.c
drivers/media/usb/hdpvr/hdpvr-core.c
drivers/media/usb/s2255/s2255drv.c
drivers/media/usb/stk1160/Kconfig
drivers/media/usb/stk1160/stk1160-v4l.c
drivers/media/usb/tlg2300/pd-main.c
drivers/media/usb/usbtv/Kconfig
drivers/media/usb/usbtv/usbtv.c
drivers/media/v4l2-core/v4l2-async.c
drivers/media/v4l2-core/v4l2-mem2mem.c
drivers/mfd/db8500-prcmu.c
drivers/mmc/host/tmio_mmc_pio.c
drivers/mtd/bcm63xxpart.c
drivers/mtd/chips/cfi_cmdset_0002.c
drivers/mtd/devices/bcm47xxsflash.c
drivers/mtd/devices/bcm47xxsflash.h
drivers/mtd/devices/block2mtd.c
drivers/mtd/devices/elm.c
drivers/mtd/devices/m25p80.c
drivers/mtd/devices/mtd_dataflash.c
drivers/mtd/devices/spear_smi.c
drivers/mtd/devices/sst25l.c
drivers/mtd/maps/ixp4xx.c
drivers/mtd/maps/latch-addr-flash.c
drivers/mtd/maps/physmap.c
drivers/mtd/maps/plat-ram.c
drivers/mtd/maps/pxa2xx-flash.c
drivers/mtd/maps/rbtx4939-flash.c
drivers/mtd/maps/sa1100-flash.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/ams-delta.c
drivers/mtd/nand/atmel_nand.c
drivers/mtd/nand/bf5xx_nand.c
drivers/mtd/nand/davinci_nand.c
drivers/mtd/nand/docg4.c
drivers/mtd/nand/fsl_ifc_nand.c
drivers/mtd/nand/fsmc_nand.c
drivers/mtd/nand/gpio.c
drivers/mtd/nand/gpmi-nand/gpmi-nand.c
drivers/mtd/nand/jz4740_nand.c
drivers/mtd/nand/lpc32xx_mlc.c
drivers/mtd/nand/lpc32xx_slc.c
drivers/mtd/nand/mxc_nand.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/nuc900_nand.c
drivers/mtd/nand/omap2.c
drivers/mtd/nand/orion_nand.c
drivers/mtd/nand/plat_nand.c
drivers/mtd/nand/pxa3xx_nand.c
drivers/mtd/nand/r852.c
drivers/mtd/nand/s3c2410.c
drivers/mtd/nand/sharpsl.c
drivers/mtd/nand/txx9ndfmc.c
drivers/mtd/onenand/generic.c
drivers/mtd/onenand/omap2.c
drivers/mtd/onenand/samsung.c
drivers/mtd/tests/mtd_oobtest.c
drivers/mtd/tests/mtd_pagetest.c
drivers/mtd/tests/mtd_readtest.c
drivers/mtd/tests/mtd_speedtest.c
drivers/mtd/tests/mtd_stresstest.c
drivers/mtd/tests/mtd_subpagetest.c
drivers/net/arcnet/arcnet.c
drivers/net/bonding/bond_3ad.c
drivers/net/bonding/bond_alb.c
drivers/net/bonding/bond_main.c
drivers/net/bonding/bond_procfs.c
drivers/net/bonding/bond_sysfs.c
drivers/net/bonding/bonding.h
drivers/net/can/flexcan.c
drivers/net/can/usb/esd_usb2.c
drivers/net/can/usb/usb_8dev.c
drivers/net/ethernet/allwinner/Kconfig
drivers/net/ethernet/atheros/atl1c/atl1c.h
drivers/net/ethernet/atheros/atl1c/atl1c_main.c
drivers/net/ethernet/broadcom/Kconfig
drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
drivers/net/ethernet/broadcom/cnic.c
drivers/net/ethernet/broadcom/cnic.h
drivers/net/ethernet/broadcom/cnic_defs.h
drivers/net/ethernet/broadcom/cnic_if.h
drivers/net/ethernet/broadcom/tg3.c
drivers/net/ethernet/broadcom/tg3.h
drivers/net/ethernet/cisco/enic/Makefile
drivers/net/ethernet/cisco/enic/enic.h
drivers/net/ethernet/cisco/enic/enic_dev.h
drivers/net/ethernet/cisco/enic/enic_ethtool.c [new file with mode: 0644]
drivers/net/ethernet/cisco/enic/enic_main.c
drivers/net/ethernet/emulex/benet/be_cmds.c
drivers/net/ethernet/emulex/benet/be_cmds.h
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/freescale/fec.h
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/freescale/gianfar.c
drivers/net/ethernet/freescale/gianfar.h
drivers/net/ethernet/intel/e100.c
drivers/net/ethernet/intel/e1000e/82571.c
drivers/net/ethernet/intel/e1000e/e1000.h
drivers/net/ethernet/intel/e1000e/ethtool.c
drivers/net/ethernet/intel/e1000e/hw.h
drivers/net/ethernet/intel/e1000e/ich8lan.c
drivers/net/ethernet/intel/e1000e/ich8lan.h
drivers/net/ethernet/intel/e1000e/netdev.c
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe.h
drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c
drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
drivers/net/ethernet/marvell/mvneta.c
drivers/net/ethernet/mellanox/mlx4/cmd.c
drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
drivers/net/ethernet/mellanox/mlx4/en_netdev.c
drivers/net/ethernet/mellanox/mlx4/en_tx.c
drivers/net/ethernet/mellanox/mlx4/eq.c
drivers/net/ethernet/mellanox/mlx4/fw.c
drivers/net/ethernet/mellanox/mlx4/fw.h
drivers/net/ethernet/mellanox/mlx4/main.c
drivers/net/ethernet/mellanox/mlx4/mcg.c
drivers/net/ethernet/mellanox/mlx4/mlx4.h
drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
drivers/net/ethernet/mellanox/mlx5/core/cmd.c
drivers/net/ethernet/mellanox/mlx5/core/main.c
drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c
drivers/net/ethernet/mellanox/mlx5/core/uar.c
drivers/net/ethernet/oki-semi/pch_gbe/Kconfig
drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h
drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_phy.c
drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_phy.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
drivers/net/ethernet/realtek/8139cp.c
drivers/net/ethernet/realtek/r8169.c
drivers/net/ethernet/renesas/Kconfig
drivers/net/ethernet/renesas/sh_eth.c
drivers/net/ethernet/renesas/sh_eth.h
drivers/net/ethernet/sfc/filter.c
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
drivers/net/ethernet/ti/cpsw.c
drivers/net/ethernet/tile/Kconfig
drivers/net/ethernet/tile/tilegx.c
drivers/net/ethernet/tile/tilepro.c
drivers/net/ethernet/via/via-velocity.c
drivers/net/macvlan.c
drivers/net/phy/mdio-sun4i.c
drivers/net/team/team.c
drivers/net/tun.c
drivers/net/usb/asix_devices.c
drivers/net/usb/ax88179_178a.c
drivers/net/usb/r8152.c
drivers/net/usb/r815x.c
drivers/net/usb/smsc75xx.c
drivers/net/usb/usbnet.c
drivers/net/veth.c
drivers/net/virtio_net.c
drivers/net/vxlan.c
drivers/net/wireless/ath/ath10k/Kconfig
drivers/net/wireless/ath/ath5k/mac80211-ops.c
drivers/net/wireless/ath/ath9k/Kconfig
drivers/net/wireless/ath/ath9k/antenna.c
drivers/net/wireless/ath/ath9k/ar5008_phy.c
drivers/net/wireless/ath/ath9k/ar9002_phy.h
drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
drivers/net/wireless/ath/ath9k/ar9003_phy.c
drivers/net/wireless/ath/ath9k/ar9003_phy.h
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/debug.h
drivers/net/wireless/ath/ath9k/eeprom_4k.c
drivers/net/wireless/ath/ath9k/hif_usb.c
drivers/net/wireless/ath/ath9k/htc_drv_init.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/phy.h
drivers/net/wireless/ath/ath9k/rc.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/wil6210/Makefile
drivers/net/wireless/ath/wil6210/debugfs.c
drivers/net/wireless/ath/wil6210/netdev.c
drivers/net/wireless/ath/wil6210/trace.h
drivers/net/wireless/ath/wil6210/txrx.c
drivers/net/wireless/ath/wil6210/txrx.h
drivers/net/wireless/ath/wil6210/wil6210.h
drivers/net/wireless/ath/wil6210/wmi.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
drivers/net/wireless/brcm80211/brcmsmac/ampdu.c
drivers/net/wireless/brcm80211/brcmsmac/main.c
drivers/net/wireless/cw1200/txrx.c
drivers/net/wireless/cw1200/wsm.h
drivers/net/wireless/iwlegacy/3945-rs.c
drivers/net/wireless/iwlegacy/3945.c
drivers/net/wireless/iwlegacy/4965-mac.c
drivers/net/wireless/iwlegacy/4965-rs.c
drivers/net/wireless/iwlwifi/dvm/main.c
drivers/net/wireless/iwlwifi/dvm/rs.c
drivers/net/wireless/iwlwifi/iwl-prph.h
drivers/net/wireless/iwlwifi/mvm/d3.c
drivers/net/wireless/iwlwifi/mvm/debugfs.c
drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/rs.c
drivers/net/wireless/iwlwifi/mvm/scan.c
drivers/net/wireless/iwlwifi/mvm/sta.c
drivers/net/wireless/iwlwifi/pcie/drv.c
drivers/net/wireless/iwlwifi/pcie/rx.c
drivers/net/wireless/iwlwifi/pcie/trans.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mwifiex/11n_aggr.c
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/cfp.c
drivers/net/wireless/mwifiex/decl.h
drivers/net/wireless/mwifiex/fw.h
drivers/net/wireless/mwifiex/ie.c
drivers/net/wireless/mwifiex/init.c
drivers/net/wireless/mwifiex/join.c
drivers/net/wireless/mwifiex/main.c
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/pcie.c
drivers/net/wireless/mwifiex/scan.c
drivers/net/wireless/mwifiex/sdio.c
drivers/net/wireless/mwifiex/sdio.h
drivers/net/wireless/mwifiex/sta_cmd.c
drivers/net/wireless/mwifiex/sta_event.c
drivers/net/wireless/mwifiex/sta_ioctl.c
drivers/net/wireless/mwifiex/uap_cmd.c
drivers/net/wireless/mwifiex/uap_txrx.c
drivers/net/wireless/mwifiex/usb.c
drivers/net/wireless/mwifiex/wmm.c
drivers/net/wireless/rt2x00/Kconfig
drivers/net/wireless/rt2x00/rt2800.h
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/rt2x00/rt2x00.h
drivers/net/wireless/rt2x00/rt2x00queue.c
drivers/net/wireless/rtlwifi/Kconfig
drivers/net/wireless/rtlwifi/Makefile
drivers/net/wireless/rtlwifi/base.c
drivers/net/wireless/rtlwifi/base.h
drivers/net/wireless/rtlwifi/core.c
drivers/net/wireless/rtlwifi/debug.c
drivers/net/wireless/rtlwifi/efuse.c
drivers/net/wireless/rtlwifi/pci.c
drivers/net/wireless/rtlwifi/ps.c
drivers/net/wireless/rtlwifi/ps.h
drivers/net/wireless/rtlwifi/rc.c
drivers/net/wireless/rtlwifi/rtl8192cu/hw.h
drivers/net/wireless/rtlwifi/rtl8192cu/sw.h
drivers/net/wireless/rtlwifi/usb.c
drivers/net/wireless/ti/wlcore/main.c
drivers/pci/host/pci-mvebu.c
drivers/pci/hotplug/Kconfig
drivers/pci/hotplug/acpiphp.h
drivers/pci/hotplug/acpiphp_core.c
drivers/pci/hotplug/acpiphp_glue.c
drivers/pci/hotplug/acpiphp_ibm.c
drivers/pci/hotplug/pciehp_pci.c
drivers/pci/iov.c
drivers/pci/pci-acpi.c
drivers/pci/pci-sysfs.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/pcie/Kconfig
drivers/pci/probe.c
drivers/pci/quirks.c
drivers/pci/setup-bus.c
drivers/platform/x86/asus-laptop.c
drivers/platform/x86/eeepc-laptop.c
drivers/platform/x86/fujitsu-laptop.c
drivers/platform/x86/panasonic-laptop.c
drivers/platform/x86/sony-laptop.c
drivers/platform/x86/thinkpad_acpi.c
drivers/pnp/driver.c
drivers/pnp/pnpacpi/core.c
drivers/rapidio/rio.c
drivers/rtc/rtc-twl.c
drivers/s390/block/dasd.c
drivers/s390/block/dasd_devmap.c
drivers/s390/block/dasd_erp.c
drivers/s390/char/sclp_config.c
drivers/s390/cio/airq.c
drivers/s390/cio/ccwgroup.c
drivers/s390/cio/cio.c
drivers/s390/cio/cio.h
drivers/s390/cio/cmf.c
drivers/s390/cio/css.c
drivers/s390/cio/device.c
drivers/s390/net/qeth_l3_sys.c
drivers/scsi/bnx2i/57xx_iscsi_hsi.h
drivers/scsi/esp_scsi.c
drivers/scsi/esp_scsi.h
drivers/scsi/virtio_scsi.c
drivers/ssb/Kconfig
drivers/ssb/driver_chipcommon_sflash.c
drivers/staging/media/lirc/lirc_igorplugusb.c
drivers/staging/zcache/zcache-main.c
drivers/tty/serial/arc_uart.c
drivers/tty/serial/mxs-auart.c
drivers/tty/serial/sh-sci.c
drivers/tty/tty_port.c
drivers/usb/chipidea/Kconfig
drivers/usb/chipidea/bits.h
drivers/usb/gadget/ether.c
drivers/usb/gadget/f_phonet.c
drivers/usb/gadget/multi.c
drivers/usb/gadget/udc-core.c
drivers/usb/musb/omap2430.c
drivers/usb/musb/tusb6010.c
drivers/usb/serial/Kconfig
drivers/usb/serial/Makefile
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/mos7840.c
drivers/usb/serial/suunto.c [new file with mode: 0644]
drivers/vfio/pci/vfio_pci.c
drivers/vfio/vfio.c
drivers/video/aty/atyfb_base.c
drivers/video/nuc900fb.c
drivers/video/sgivwfb.c
drivers/video/sh7760fb.c
drivers/video/vga16fb.c
drivers/video/xilinxfb.c
drivers/xen/Kconfig
drivers/xen/Makefile
drivers/xen/acpi.c
drivers/xen/evtchn.c
drivers/xen/xenbus/xenbus_probe_frontend.c
fs/9p/vfs_inode.c
fs/binfmt_aout.c
fs/binfmt_elf.c
fs/binfmt_elf_fdpic.c
fs/ceph/dir.c
fs/ceph/inode.c
fs/ceph/ioctl.c
fs/cifs/cifsencrypt.c
fs/cifs/cifsfs.c
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/connect.c
fs/cifs/file.c
fs/cifs/link.c
fs/cifs/sess.c
fs/cifs/smb1ops.c
fs/cifs/smb2transport.c
fs/coredump.c
fs/dlm/ast.c
fs/ext3/super.c
fs/f2fs/checkpoint.c
fs/f2fs/data.c
fs/f2fs/debug.c
fs/f2fs/dir.c
fs/f2fs/f2fs.h
fs/f2fs/file.c
fs/f2fs/inode.c
fs/f2fs/namei.c
fs/f2fs/node.c
fs/f2fs/node.h
fs/f2fs/recovery.c
fs/f2fs/segment.c
fs/f2fs/super.c
fs/gfs2/inode.c
fs/gfs2/lops.c
fs/gfs2/main.c
fs/gfs2/meta_io.c
fs/gfs2/meta_io.h
fs/isofs/inode.c
fs/logfs/dev_mtd.c
fs/logfs/super.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/nfs4xdr.c
fs/nfsd/nfs4state.c
fs/ocfs2/cluster/heartbeat.c
fs/ocfs2/cluster/masklog.h
fs/ocfs2/dlm/dlmmaster.c
fs/ocfs2/dlm/dlmrecovery.c
fs/ocfs2/refcounttree.c
fs/udf/super.c
fs/xfs/xfs_aops.c
fs/xfs/xfs_log.c
fs/xfs/xfs_mount.c
fs/xfs/xfs_qm.c
fs/xfs/xfs_qm_syscalls.c
fs/xfs/xfs_sb.h
fs/xfs/xfs_super.c
include/acpi/acpi_bus.h
include/acpi/acpi_drivers.h
include/acpi/acpixf.h
include/acpi/actypes.h
include/drm/drmP.h
include/drm/drm_dp_helper.h
include/drm/drm_fixed.h
include/drm/drm_mm.h
include/drm/drm_vma_manager.h [new file with mode: 0644]
include/drm/ttm/ttm_bo_api.h
include/drm/ttm/ttm_bo_driver.h
include/linux/acpi.h
include/linux/ata.h
include/linux/atmel-ssc.h
include/linux/bcma/bcma.h
include/linux/binfmts.h
include/linux/cgroup.h
include/linux/coredump.h
include/linux/cpufreq.h
include/linux/cpuidle.h
include/linux/dmaengine.h
include/linux/elf.h
include/linux/elfcore.h
include/linux/firewire.h
include/linux/hid.h
include/linux/i2c/i2c-hid.h
include/linux/if_team.h
include/linux/igmp.h
include/linux/jbd.h
include/linux/libata.h
include/linux/mfd/arizona/gpio.h [new file with mode: 0644]
include/linux/mlx4/cmd.h
include/linux/mlx4/device.h
include/linux/mlx5/device.h
include/linux/mlx5/driver.h
include/linux/mod_devicetable.h
include/linux/module.h
include/linux/mtd/fsmc.h
include/linux/mtd/nand.h
include/linux/netdevice.h
include/linux/pci-acpi.h
include/linux/pci.h
include/linux/pci_hotplug.h
include/linux/platform_data/atmel.h
include/linux/platform_data/elm.h
include/linux/platform_data/omap-abe-twl6040.h [deleted file]
include/linux/raid/pq.h
include/linux/sched.h
include/linux/serial_sci.h
include/linux/skbuff.h
include/linux/tcp.h
include/linux/tick.h
include/linux/usb/usbnet.h
include/linux/vmpressure.h
include/media/adv7343.h
include/media/davinci/vpif_types.h
include/media/lirc_dev.h
include/media/rc-core.h
include/media/v4l2-async.h
include/media/v4l2-ctrls.h
include/media/v4l2-mem2mem.h
include/media/v4l2-subdev.h
include/net/9p/transport.h
include/net/act_api.h
include/net/addrconf.h
include/net/af_rxrpc.h
include/net/af_unix.h
include/net/af_vsock.h [moved from net/vmw_vsock/af_vsock.h with 100% similarity]
include/net/arp.h
include/net/ax25.h
include/net/bluetooth/hci.h
include/net/busy_poll.h
include/net/cfg80211.h
include/net/checksum.h
include/net/cls_cgroup.h
include/net/fib_rules.h
include/net/ieee80211_radiotap.h
include/net/ip6_fib.h
include/net/mac80211.h
include/net/ndisc.h
include/net/neighbour.h
include/net/net_namespace.h
include/net/netns/ipv4.h
include/net/netns/ipv6.h
include/net/netprio_cgroup.h
include/net/nfc/hci.h
include/net/nfc/nfc.h
include/net/pkt_cls.h
include/net/pkt_sched.h
include/net/sch_generic.h
include/net/sctp/auth.h
include/net/sctp/checksum.h
include/net/sctp/constants.h
include/net/sctp/sctp.h
include/net/sctp/sm.h
include/net/sctp/structs.h
include/net/sctp/tsnmap.h
include/net/sctp/ulpevent.h
include/net/sctp/ulpqueue.h
include/net/sock.h
include/net/tcp.h
include/net/udp.h
include/net/vsock_addr.h [moved from net/vmw_vsock/vsock_addr.h with 100% similarity]
include/net/xfrm.h
include/sound/rcar_snd.h [new file with mode: 0644]
include/sound/soc-dapm.h
include/sound/soc-dpcm.h
include/sound/soc.h
include/sound/tea575x-tuner.h
include/trace/events/power.h
include/uapi/drm/drm.h
include/uapi/drm/i915_drm.h
include/uapi/linux/fib_rules.h
include/uapi/linux/firewire-cdev.h
include/uapi/linux/if_link.h
include/uapi/linux/if_tun.h
include/uapi/linux/nfc.h
include/uapi/linux/nl80211.h
include/uapi/linux/sctp.h
include/uapi/linux/tcp.h
include/uapi/linux/uhid.h
include/uapi/linux/virtio_net.h
include/xen/acpi.h
include/xen/interface/platform.h
kernel/Makefile
kernel/cgroup.c
kernel/cpuset.c
kernel/elfcore.c
kernel/freezer.c
kernel/power/process.c
kernel/power/suspend.c
kernel/printk/Makefile [new file with mode: 0644]
kernel/printk/braille.c [new file with mode: 0644]
kernel/printk/braille.h [new file with mode: 0644]
kernel/printk/console_cmdline.h [new file with mode: 0644]
kernel/printk/printk.c [moved from kernel/printk.c with 95% similarity]
kernel/sched/fair.c
kernel/sysctl.c
kernel/time/tick-sched.c
lib/raid6/.gitignore
lib/raid6/Makefile
lib/raid6/algos.c
lib/raid6/neon.c [new file with mode: 0644]
lib/raid6/neon.uc [new file with mode: 0644]
lib/raid6/test/Makefile
mm/huge_memory.c
mm/memcontrol.c
mm/mempolicy.c
mm/mmap.c
mm/slub.c
mm/swap.c
mm/vmpressure.c
mm/zbud.c
net/8021q/vlan.c
net/9p/client.c
net/9p/trans_rdma.c
net/Kconfig
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/hidp/core.c
net/bluetooth/l2cap_core.c
net/bridge/br_device.c
net/bridge/br_if.c
net/bridge/br_input.c
net/bridge/br_multicast.c
net/bridge/br_notify.c
net/bridge/br_private.h
net/ceph/messenger.c
net/ceph/osd_client.c
net/core/dev.c
net/core/fib_rules.c
net/core/flow_dissector.c
net/core/neighbour.c
net/core/net-sysfs.c
net/core/pktgen.c
net/core/rtnetlink.c
net/core/skbuff.c
net/core/sock.c
net/core/stream.c
net/core/sysctl_net_core.c
net/dccp/proto.c
net/ipv4/devinet.c
net/ipv4/fib_rules.c
net/ipv4/fib_trie.c
net/ipv4/igmp.c
net/ipv4/ip_vti.c
net/ipv4/ipmr.c
net/ipv4/route.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_minisocks.c
net/ipv4/tcp_output.c
net/ipv4/udp.c
net/ipv6/addrconf.c
net/ipv6/af_inet6.c
net/ipv6/fib6_rules.c
net/ipv6/ip6_fib.c
net/ipv6/ip6mr.c
net/ipv6/mcast.c
net/ipv6/ndisc.c
net/ipv6/route.c
net/ipv6/tcp_ipv6.c
net/irda/irttp.c
net/key/af_key.c
net/mac80211/cfg.c
net/mac80211/ht.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/main.c
net/mac80211/mesh.c
net/mac80211/mesh_plink.c
net/mac80211/mesh_ps.c
net/mac80211/mlme.c
net/mac80211/pm.c
net/mac80211/rate.c
net/mac80211/rate.h
net/mac80211/rc80211_minstrel.c
net/mac80211/rc80211_minstrel_ht.c
net/mac80211/rc80211_pid_algo.c
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/status.c
net/mac80211/tx.c
net/mac80211/util.c
net/netfilter/ipvs/ip_vs_proto_sctp.c
net/netfilter/nf_conntrack_expect.c
net/netfilter/nf_nat_proto_sctp.c
net/netfilter/xt_socket.c
net/netlink/genetlink.c
net/nfc/core.c
net/nfc/hci/core.c
net/nfc/nci/Kconfig
net/nfc/netlink.c
net/nfc/nfc.h
net/packet/af_packet.c
net/sched/sch_atm.c
net/sched/sch_cbq.c
net/sched/sch_netem.c
net/sctp/associola.c
net/sctp/auth.c
net/sctp/bind_addr.c
net/sctp/chunk.c
net/sctp/command.c
net/sctp/debug.c
net/sctp/endpointola.c
net/sctp/input.c
net/sctp/inqueue.c
net/sctp/ipv6.c
net/sctp/objcnt.c
net/sctp/output.c
net/sctp/outqueue.c
net/sctp/primitive.c
net/sctp/proc.c
net/sctp/protocol.c
net/sctp/sm_make_chunk.c
net/sctp/sm_sideeffect.c
net/sctp/sm_statefuns.c
net/sctp/sm_statetable.c
net/sctp/socket.c
net/sctp/ssnmap.c
net/sctp/sysctl.c
net/sctp/transport.c
net/sctp/tsnmap.c
net/sctp/ulpevent.c
net/sctp/ulpqueue.c
net/socket.c
net/sunrpc/rpc_pipe.c
net/sunrpc/svcsock.c
net/sunrpc/xprtsock.c
net/tipc/server.c
net/vmw_vsock/af_vsock.c
net/vmw_vsock/vmci_transport.c
net/vmw_vsock/vmci_transport.h
net/vmw_vsock/vsock_addr.c
net/wireless/core.c
net/wireless/core.h
net/wireless/mesh.c
net/wireless/nl80211.c
net/wireless/nl80211.h
net/wireless/reg.c
net/wireless/scan.c
net/wireless/sme.c
net/wireless/trace.h
net/wireless/util.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_state.c
scripts/kconfig/mconf.c
scripts/kconfig/nconf.c
scripts/kconfig/symbol.c
scripts/package/builddeb
scripts/package/buildtar
scripts/package/mkspec
security/selinux/include/xfrm.h
sound/core/compress_offload.c
sound/drivers/dummy.c
sound/firewire/speakers.c
sound/i2c/other/tea575x-tuner.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_generic.h
sound/pci/hda/hda_hwdep.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_jack.c
sound/pci/hda/hda_jack.h
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_via.c
sound/pci/rme9652/hdspm.c
sound/soc/atmel/Kconfig
sound/soc/atmel/Makefile
sound/soc/atmel/atmel-pcm-dma.c
sound/soc/atmel/atmel_ssc_dai.c
sound/soc/atmel/atmel_wm8904.c [new file with mode: 0644]
sound/soc/au1x/ac97c.c
sound/soc/au1x/db1200.c
sound/soc/au1x/psc-ac97.c
sound/soc/blackfin/bf5xx-ac97.c
sound/soc/blackfin/bf5xx-ac97.h
sound/soc/cirrus/ep93xx-ac97.c
sound/soc/cirrus/ep93xx-i2s.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/adau1701.c
sound/soc/codecs/adav80x.c
sound/soc/codecs/ak4554.c [new file with mode: 0644]
sound/soc/codecs/arizona.c
sound/soc/codecs/arizona.h
sound/soc/codecs/hdmi.c
sound/soc/codecs/lm4857.c
sound/soc/codecs/max98090.c
sound/soc/codecs/pcm1681.c [new file with mode: 0644]
sound/soc/codecs/pcm3008.c
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/spdif_receiver.c
sound/soc/codecs/spdif_transmitter.c
sound/soc/codecs/sta32x.c
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/twl6040.c
sound/soc/codecs/uda134x.c
sound/soc/codecs/wm0010.c
sound/soc/codecs/wm5102.c
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm8350.c
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8753.c
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8904.c
sound/soc/codecs/wm8962.c
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8995.c
sound/soc/codecs/wm_adsp.c
sound/soc/codecs/wm_adsp.h
sound/soc/codecs/wm_hubs.c
sound/soc/fsl/Kconfig
sound/soc/fsl/fsl_ssi.c
sound/soc/fsl/imx-audmux.c
sound/soc/fsl/imx-mc13783.c
sound/soc/fsl/imx-pcm-dma.c
sound/soc/fsl/imx-pcm-fiq.c
sound/soc/fsl/imx-pcm.h
sound/soc/fsl/imx-sgtl5000.c
sound/soc/fsl/imx-ssi.c
sound/soc/fsl/imx-ssi.h
sound/soc/fsl/imx-wm8962.c
sound/soc/kirkwood/Kconfig
sound/soc/kirkwood/kirkwood-i2s.c
sound/soc/kirkwood/kirkwood-openrd.c
sound/soc/kirkwood/kirkwood-t5325.c
sound/soc/mxs/Kconfig
sound/soc/mxs/mxs-saif.c
sound/soc/mxs/mxs-sgtl5000.c
sound/soc/nuc900/nuc900-ac97.c
sound/soc/omap/Kconfig
sound/soc/omap/mcbsp.c
sound/soc/omap/omap-abe-twl6040.c
sound/soc/omap/omap-mcbsp.c
sound/soc/pxa/brownstone.c
sound/soc/pxa/mmp-sspa.c
sound/soc/pxa/ttc-dkb.c
sound/soc/samsung/i2s-regs.h
sound/soc/samsung/i2s.c
sound/soc/samsung/smdk_wm8994.c
sound/soc/samsung/spdif.c
sound/soc/sh/Kconfig
sound/soc/sh/Makefile
sound/soc/sh/rcar/Makefile [new file with mode: 0644]
sound/soc/sh/rcar/adg.c [new file with mode: 0644]
sound/soc/sh/rcar/core.c [new file with mode: 0644]
sound/soc/sh/rcar/gen.c [new file with mode: 0644]
sound/soc/sh/rcar/rsnd.h [new file with mode: 0644]
sound/soc/sh/rcar/scu.c [new file with mode: 0644]
sound/soc/sh/rcar/ssi.c [new file with mode: 0644]
sound/soc/soc-compress.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/soc-jack.c
sound/soc/soc-pcm.c
sound/soc/tegra/Kconfig
sound/soc/tegra/tegra20_ac97.c
sound/soc/tegra/tegra_alc5632.c
sound/soc/tegra/tegra_wm8753.c
sound/soc/tegra/trimslice.c
sound/soc/txx9/txx9aclc-ac97.c
sound/soc/ux500/mop500.c
sound/usb/usx2y/usbusx2y.c
tools/lguest/lguest.c
tools/power/fspin/Makefile [new file with mode: 0644]
tools/power/fspin/fspin.1 [new file with mode: 0644]
tools/power/fspin/fspin.c [new file with mode: 0644]
tools/virtio/.gitignore [new file with mode: 0644]

index 3b8b9b33be380b75f9a4d19a4680723f3febfce7..7e9932e55475cef2891a790e391011b77b9ff666 100644 (file)
@@ -29,6 +29,7 @@ modules.builtin
 *.bz2
 *.lzma
 *.xz
+*.lz4
 *.lzo
 *.patch
 *.gcno
index cbfdf5486639a144c414cc46334144fccee8a1e5..fe397f90a34f50153f5936cfa13635ed7bc85b7b 100644 (file)
@@ -84,7 +84,7 @@ X!Iinclude/linux/kobject.h
 
      <sect1><title>Kernel utility functions</title>
 !Iinclude/linux/kernel.h
-!Ekernel/printk.c
+!Ekernel/printk/printk.c
 !Ekernel/panic.c
 !Ekernel/sys.c
 !Ekernel/rcupdate.c
index 7d1278e7a4341603a4b8c8c84953ca95f8cc30e2..87e22ecd92815186aa424bd7515adb57d9dfa0d9 100644 (file)
@@ -2212,6 +2212,12 @@ void intel_crt_init(struct drm_device *dev)
 !Iinclude/drm/drm_rect.h
 !Edrivers/gpu/drm/drm_rect.c
     </sect2>
+    <sect2>
+      <title>VMA Offset Manager</title>
+!Pdrivers/gpu/drm/drm_vma_manager.c vma offset manager
+!Edrivers/gpu/drm/drm_vma_manager.c
+!Iinclude/drm/drm_vma_manager.h
+    </sect2>
   </sect1>
 
   <!-- Internals: kms properties -->
index 8d7eb6bf6312f4934c613912b7930d127c12956a..34cada2ca71038694f11faa3f1060fe641b12bd1 100644 (file)
@@ -46,7 +46,9 @@ describing an IR signal are read from the chardev.</para>
 values. Pulses and spaces are only marked implicitly by their position. The
 data must start and end with a pulse, therefore, the data must always include
 an uneven number of samples. The write function must block until the data has
-been transmitted by the hardware.</para>
+been transmitted by the hardware. If more data is provided than the hardware
+can send, the driver returns EINVAL.</para>
+
 </section>
 
 <section id="lirc_ioctl">
index 48748499c097516e9ac39b2e8584eb5a8e92c0f2..098ff483802e6094b09b62f29c85545ab0df5cc3 100644 (file)
@@ -92,8 +92,8 @@ to add them.</para>
            <entry>int</entry>
            <entry><structfield>quality</structfield></entry>
            <entry>Deprecated. If <link linkend="jpeg-quality-control"><constant>
-           V4L2_CID_JPEG_IMAGE_QUALITY</constant></link> control is exposed by
-           a driver applications should use it instead and ignore this field.
+           V4L2_CID_JPEG_COMPRESSION_QUALITY</constant></link> control is exposed
+           by a driver applications should use it instead and ignore this field.
            </entry>
          </row>
          <row>
index 6a8b7158697f9ae58b33e82d2f7becd772a6c4aa..9c92bb879b6dc7b1468e247ae0dbb026ad519f2f 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0"?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
-       "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+       "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
 <!ENTITY % media-entities SYSTEM "./media-entities.tmpl"> %media-entities;
 <!ENTITY media-indices SYSTEM "./media-indices.tmpl">
 
diff --git a/Documentation/devicetree/bindings/hid/hid-over-i2c.txt b/Documentation/devicetree/bindings/hid/hid-over-i2c.txt
new file mode 100644 (file)
index 0000000..488edcb
--- /dev/null
@@ -0,0 +1,28 @@
+* HID over I2C Device-Tree bindings
+
+HID over I2C provides support for various Human Interface Devices over the
+I2C bus. These devices can be for example touchpads, keyboards, touch screens
+or sensors.
+
+The specification has been written by Microsoft and is currently available here:
+http://msdn.microsoft.com/en-us/library/windows/hardware/hh852380.aspx
+
+If this binding is used, the kernel module i2c-hid will handle the communication
+with the device and the generic hid core layer will handle the protocol.
+
+Required properties:
+- compatible: must be "hid-over-i2c"
+- reg: i2c slave address
+- hid-descr-addr: HID descriptor address
+- interrupt-parent: the phandle for the interrupt controller
+- interrupts: interrupt line
+
+Example:
+
+       i2c-hid-dev@2c {
+               compatible = "hid-over-i2c";
+               reg = <0x2c>;
+               hid-descr-addr = <0x0020>;
+               interrupt-parent = <&gpx3>;
+               interrupts = <3 2>;
+       };
diff --git a/Documentation/devicetree/bindings/media/i2c/adv7343.txt b/Documentation/devicetree/bindings/media/i2c/adv7343.txt
new file mode 100644 (file)
index 0000000..5653bc2
--- /dev/null
@@ -0,0 +1,48 @@
+* Analog Devices adv7343 video encoder
+
+The ADV7343 are high speed, digital-to-analog video encoders in a 64-lead LQFP
+package. Six high speed, 3.3 V, 11-bit video DACs provide support for composite
+(CVBS), S-Video (Y-C), and component (YPrPb/RGB) analog outputs in standard
+definition (SD), enhanced definition (ED), or high definition (HD) video
+formats.
+
+Required Properties :
+- compatible: Must be "adi,adv7343"
+
+Optional Properties :
+- adi,power-mode-sleep-mode: on enable the current consumption is reduced to
+                             micro ampere level. All DACs and the internal PLL
+                             circuit are disabled.
+- adi,power-mode-pll-ctrl: PLL and oversampling control. This control allows
+                          internal PLL 1 circuit to be powered down and the
+                          oversampling to be switched off.
+- ad,adv7343-power-mode-dac: array configuring the power on/off DAC's 1..6,
+                             0 = OFF and 1 = ON, Default value when this
+                             property is not specified is <0 0 0 0 0 0>.
+- ad,adv7343-sd-config-dac-out: array configure SD DAC Output's 1 and 2, 0 = OFF
+                                and 1 = ON, Default value when this property is
+                                not specified is <0 0>.
+
+Example:
+
+i2c0@1c22000 {
+       ...
+       ...
+
+       adv7343@2a {
+               compatible = "adi,adv7343";
+               reg = <0x2a>;
+
+               port {
+                       adv7343_1: endpoint {
+                                       adi,power-mode-sleep-mode;
+                                       adi,power-mode-pll-ctrl;
+                                       /* Use DAC1..3, DAC6 */
+                                       adi,dac-enable = <1 1 1 0 0 1>;
+                                       /* Use SD DAC output 1 */
+                                       adi,sd-dac-enable = <1 0>;
+                       };
+               };
+       };
+       ...
+};
diff --git a/Documentation/devicetree/bindings/media/i2c/ths8200.txt b/Documentation/devicetree/bindings/media/i2c/ths8200.txt
new file mode 100644 (file)
index 0000000..285f6ae
--- /dev/null
@@ -0,0 +1,19 @@
+* Texas Instruments THS8200 video encoder
+
+The ths8200 device is a digital to analog converter used in DVD players, video
+recorders, set-top boxes.
+
+Required Properties :
+- compatible : value must be "ti,ths8200"
+
+Example:
+
+       i2c0@1c22000 {
+               ...
+               ...
+               ths8200@5c {
+                       compatible = "ti,ths8200";
+                       reg = <0x5c>;
+               };
+               ...
+       };
index d555421ea49f8237d5a8a0c1822facd379b60f1b..b6eb484366a5de6aebbb281776407a382e8449eb 100644 (file)
@@ -15,6 +15,7 @@ Required properties:
   optional gpio and may be set to 0 if not present.
 
 Optional properties:
+- atmel,nand-has-dma : boolean to support dma transfer for nand read/write.
 - nand-ecc-mode : String, operation mode of the NAND ecc mode, soft by default.
   Supported values are: "none", "soft", "hw", "hw_syndrome", "hw_oob_first",
   "soft_bch".
index 2240ac09f6ba05cf1bea9aaa6788d01b9c3583e4..ec42935f390861810c1e7f6dd8e925220d46e6f1 100644 (file)
@@ -1,4 +1,5 @@
-* FSMC NAND
+ST Microelectronics Flexible Static Memory Controller (FSMC)
+NAND Interface
 
 Required properties:
 - compatible : "st,spear600-fsmc-nand", "stericsson,fsmc-nand"
@@ -9,6 +10,26 @@ Optional properties:
 - bank-width : Width (in bytes) of the device.  If not present, the width
   defaults to 1 byte
 - nand-skip-bbtscan: Indicates the the BBT scanning should be skipped
+- timings: array of 6 bytes for NAND timings. The meanings of these bytes
+  are:
+  byte 0 TCLR  : CLE to RE delay in number of AHB clock cycles, only 4 bits
+                 are valid. Zero means one clockcycle, 15 means 16 clock
+                 cycles.
+  byte 1 TAR   : ALE to RE delay, 4 bits are valid. Same format as TCLR.
+  byte 2 THIZ  : number of HCLK clock cycles during which the data bus is
+                 kept in Hi-Z (tristate) after the start of a write access.
+                 Only valid for write transactions. Zero means zero cycles,
+                 255 means 255 cycles.
+  byte 3 THOLD : number of HCLK clock cycles to hold the address (and data
+                 when writing) after the command deassertation. Zero means
+                 one cycle, 255 means 256 cycles.
+  byte 4 TWAIT : number of HCLK clock cycles to assert the command to the
+                 NAND flash in response to SMWAITn. Zero means 1 cycle,
+                 255 means 256 cycles.
+  byte 5 TSET  : number of HCLK clock cycles to assert the address before the
+                 command is asserted. Zero means one cycle, 255 means 256
+                 cycles.
+- bank: default NAND bank to use (0-3 are valid, 0 is the default).
 
 Example:
 
@@ -24,6 +45,8 @@ Example:
 
                bank-width = <1>;
                nand-skip-bbtscan;
+               timings = /bits/ 8 <0 0 0 2 3 0>;
+               bank = <1>;
 
                partition@0 {
                        ...
diff --git a/Documentation/devicetree/bindings/sound/ak4554.c b/Documentation/devicetree/bindings/sound/ak4554.c
new file mode 100644 (file)
index 0000000..934fa02
--- /dev/null
@@ -0,0 +1,11 @@
+AK4554 ADC/DAC
+
+Required properties:
+
+  - compatible : "asahi-kasei,ak4554"
+
+Example:
+
+ak4554-adc-dac {
+       compatible = "asahi-kasei,ak4554";
+};
diff --git a/Documentation/devicetree/bindings/sound/atmel-wm8904.txt b/Documentation/devicetree/bindings/sound/atmel-wm8904.txt
new file mode 100644 (file)
index 0000000..8bbe50c
--- /dev/null
@@ -0,0 +1,55 @@
+Atmel ASoC driver with wm8904 audio codec complex
+
+Required properties:
+  - compatible: "atmel,asoc-wm8904"
+  - atmel,model: The user-visible name of this sound complex.
+  - atmel,audio-routing: A list of the connections between audio components.
+    Each entry is a pair of strings, the first being the connection's sink,
+    the second being the connection's source. Valid names for sources and
+    sinks are the WM8904's pins, and the jacks on the board:
+
+    WM8904 pins:
+
+    * IN1L
+    * IN1R
+    * IN2L
+    * IN2R
+    * IN3L
+    * IN3R
+    * HPOUTL
+    * HPOUTR
+    * LINEOUTL
+    * LINEOUTR
+    * MICBIAS
+
+    Board connectors:
+
+    * Headphone Jack
+    * Line In Jack
+    * Mic
+
+  - atmel,ssc-controller: The phandle of the SSC controller
+  - atmel,audio-codec: The phandle of the WM8904 audio codec
+
+Optional properties:
+  - pinctrl-names, pinctrl-0: Please refer to pinctrl-bindings.txt
+
+Example:
+sound {
+       compatible = "atmel,asoc-wm8904";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pck0_as_mck>;
+
+       atmel,model = "wm8904 @ AT91SAM9N12EK";
+
+       atmel,audio-routing =
+               "Headphone Jack", "HPOUTL",
+               "Headphone Jack", "HPOUTR",
+               "IN2L", "Line In Jack",
+               "IN2R", "Line In Jack",
+               "Mic", "MICBIAS",
+               "IN1L", "Mic";
+
+       atmel,ssc-controller = <&ssc0>;
+       atmel,audio-codec = <&wm8904>;
+};
diff --git a/Documentation/devicetree/bindings/sound/ti,pcm1681.txt b/Documentation/devicetree/bindings/sound/ti,pcm1681.txt
new file mode 100644 (file)
index 0000000..4df1718
--- /dev/null
@@ -0,0 +1,15 @@
+Texas Instruments PCM1681 8-channel PWM Processor
+
+Required properties:
+
+ - compatible:         Should contain "ti,pcm1681".
+ - reg:                        The i2c address. Should contain <0x4c>.
+
+Examples:
+
+       i2c_bus {
+               pcm1681@4c {
+                       compatible = "ti,pcm1681";
+                       reg = <0x4c>;
+               };
+       };
index f47c3f589fd03a8deb2485292116e33d17a0f7da..705a6b156c6c4fc00713443f5fa631996b259401 100644 (file)
@@ -3,7 +3,14 @@ Texas Instruments - tlv320aic3x Codec module
 The tlv320aic3x serial control bus communicates through I2C protocols
 
 Required properties:
-- compatible - "string" -  "ti,tlv320aic3x"
+
+- compatible - "string" - One of:
+    "ti,tlv320aic3x" - Generic TLV320AIC3x device
+    "ti,tlv320aic33" - TLV320AIC33
+    "ti,tlv320aic3007" - TLV320AIC3007
+    "ti,tlv320aic3106" - TLV320AIC3106
+
+
 - reg - <int> -  I2C slave address
 
 
index f2f3e80934d227f123e4ecef3f8562c1530ed70a..e045e90a0924bc6e4d8a1861cd1a43b1a7a8d178 100644 (file)
@@ -32,6 +32,10 @@ Optional properties:
     The second cell is the flags, encoded as the trigger masks from
     Documentation/devicetree/bindings/interrupts.txt
 
+  - clocks : A list of up to two phandle and clock specifier pairs
+  - clock-names : A list of clock names sorted in the same order as clocks.
+                  Valid clock names are "MCLK1" and "MCLK2".
+
   - wlf,gpio-cfg : A list of GPIO configuration register values. If absent,
     no configuration of these registers is performed. If any value is
     over 0xffff then the register will be left as default. If present 11
diff --git a/Documentation/devicetree/bindings/tty/serial/renesas,sci-serial.txt b/Documentation/devicetree/bindings/tty/serial/renesas,sci-serial.txt
new file mode 100644 (file)
index 0000000..6ad1adf
--- /dev/null
@@ -0,0 +1,53 @@
+* Renesas SH-Mobile Serial Communication Interface
+
+Required properties:
+- compatible : Should be "renesas,sci-<port type>-uart", where <port type> may be
+  SCI, SCIF, IRDA, SCIFA or SCIFB.
+- reg : Address and length of the register set for the device
+- interrupts : Should contain the following IRQs: ERI, RXI, TXI and BRI.
+- cell-index : The device id.
+- renesas,scscr : Should contain a bitfield used by the Serial Control Register.
+  b7 = SCSCR_TIE
+  b6 = SCSCR_RIE
+  b5 = SCSCR_TE
+  b4 = SCSCR_RE
+  b3 = SCSCR_REIE
+  b2 = SCSCR_TOIE
+  b1 = SCSCR_CKE1
+  b0 = SCSCR_CKE0
+- renesas,scbrr-algo-id : Algorithm ID for the Bit Rate Register
+  1 = SCBRR_ALGO_1 ((clk + 16 * bps) / (16 * bps) - 1)
+  2 = SCBRR_ALGO_2 ((clk + 16 * bps) / (32 * bps) - 1)
+  3 = SCBRR_ALGO_3 (((clk * 2) + 16 * bps) / (16 * bps) - 1)
+  4 = SCBRR_ALGO_4 (((clk * 2) + 16 * bps) / (32 * bps) - 1)
+  5 = SCBRR_ALGO_5 (((clk * 1000 / 32) / bps) - 1)
+
+Optional properties:
+- renesas,autoconf : Set if device is capable of auto configuration
+- renesas,regtype : Overwrite the register layout. In most cases you can rely
+  on auto-probing (omit this property or set to 0) but some legacy devices
+  use a non-default register layout. Possible layouts are
+  0 = SCIx_PROBE_REGTYPE (default)
+  1 = SCIx_SCI_REGTYPE
+  2 = SCIx_IRDA_REGTYPE
+  3 = SCIx_SCIFA_REGTYPE
+  4 = SCIx_SCIFB_REGTYPE
+  5 = SCIx_SH2_SCIF_FIFODATA_REGTYPE
+  6 = SCIx_SH3_SCIF_REGTYPE
+  7 = SCIx_SH4_SCIF_REGTYPE
+  8 = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE
+  9 = SCIx_SH4_SCIF_FIFODATA_REGTYPE
+ 10 = SCIx_SH7705_SCIF_REGTYPE
+
+
+Example:
+       sci@0xe6c50000 {
+               compatible = "renesas,sci-SCIFA-uart";
+               interrupt-parent = <&intca>;
+               reg = <0xe6c50000 0x100>;
+               interrupts = <0x0c20>, <0x0c20>, <0x0c20>, <0x0c20>;
+               cell-index = <1>;
+               renesas,scscr = <0x30>;
+               renesas,scbrr-algo-id = <4>;
+               renesas,autoconf;
+       };
index 293855e950000ce53223d137b094d266d7911ad3..7ed0d17d67218597c33b46e391a095ca0e3e5aa2 100644 (file)
@@ -26,11 +26,12 @@ journal=inum                When a journal already exists, this option is ignored.
                        Otherwise, it specifies the number of the inode which
                        will represent the ext3 file system's journal file.
 
+journal_path=path
 journal_dev=devnum     When the external journal device's major/minor numbers
-                       have changed, this option allows the user to specify
+                       have changed, these options allow the user to specify
                        the new journal location.  The journal device is
-                       identified through its new major/minor numbers encoded
-                       in devnum.
+                       identified through either its new major/minor numbers
+                       encoded in devnum, or via a path to the device.
 
 norecovery             Don't load the journal on mounting. Note that this forces
 noload                 mount of inconsistent filesystem, which can lead to
index b91e2f26b672451e687b73fb42f18bb2ebd21821..0500c198cd080ce8c40735cc85b1740f5c1345f0 100644 (file)
@@ -18,8 +18,8 @@ according to its internal geometry or flash memory management scheme, namely FTL
 F2FS and its tools support various parameters not only for configuring on-disk
 layout, but also for selecting allocation and cleaning algorithms.
 
-The file system formatting tool, "mkfs.f2fs", is available from the following
-git tree:
+The following git tree provides the file system formatting tool (mkfs.f2fs),
+a consistency checking tool (fsck.f2fs), and a debugging tool (dump.f2fs).
 >> git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs-tools.git
 
 For reporting bugs and sending patches, please use the following mailing list:
@@ -149,8 +149,12 @@ USAGE
  # mkfs.f2fs -l label /dev/block_device
  # mount -t f2fs /dev/block_device /mnt/f2fs
 
-Format options
---------------
+mkfs.f2fs
+---------
+The mkfs.f2fs is for the use of formatting a partition as the f2fs filesystem,
+which builds a basic on-disk layout.
+
+The options consist of:
 -l [label]   : Give a volume label, up to 512 unicode name.
 -a [0 or 1]  : Split start location of each area for heap-based allocation.
                1 is set by default, which performs this.
@@ -164,6 +168,37 @@ Format options
 -t [0 or 1]  : Disable discard command or not.
                1 is set by default, which conducts discard.
 
+fsck.f2fs
+---------
+The fsck.f2fs is a tool to check the consistency of an f2fs-formatted
+partition, which examines whether the filesystem metadata and user-made data
+are cross-referenced correctly or not.
+Note that, initial version of the tool does not fix any inconsistency.
+
+The options consist of:
+  -d debug level [default:0]
+
+dump.f2fs
+---------
+The dump.f2fs shows the information of specific inode and dumps SSA and SIT to
+file. Each file is dump_ssa and dump_sit.
+
+The dump.f2fs is used to debug on-disk data structures of the f2fs filesystem.
+It shows on-disk inode information reconized by a given inode number, and is
+able to dump all the SSA and SIT entries into predefined files, ./dump_ssa and
+./dump_sit respectively.
+
+The options consist of:
+  -d debug level [default:0]
+  -i inode no (hex)
+  -s [SIT dump segno from #1~#2 (decimal), for all 0~-1]
+  -a [SSA dump segno from #1~#2 (decimal), for all 0~-1]
+
+Examples:
+# dump.f2fs -i [ino] /dev/sdx
+# dump.f2fs -s 0~-1 /dev/sdx (SIT dump)
+# dump.f2fs -a 0~-1 /dev/sdx (SSA dump)
+
 ================================================================================
 DESIGN
 ================================================================================
index 3c741214dfbbb028044be22a88c5359f7ba49646..dc35a2b75eeec08743b5e55614508a881589d3c0 100644 (file)
@@ -149,11 +149,13 @@ needs. Only UHID_OUTPUT and UHID_OUTPUT_EV have payloads.
   is of type "struct uhid_data_req".
   This may be received even though you haven't received UHID_OPEN, yet.
 
-  UHID_OUTPUT_EV:
+  UHID_OUTPUT_EV (obsolete):
   Same as UHID_OUTPUT but this contains a "struct input_event" as payload. This
   is called for force-feedback, LED or similar events which are received through
   an input device by the HID subsystem. You should convert this into raw reports
   and send them to your device similar to events of type UHID_OUTPUT.
+  This is no longer sent by newer kernels. Instead, HID core converts it into a
+  raw output report and sends it via UHID_OUTPUT.
 
   UHID_FEATURE:
   This event is sent if the kernel driver wants to perform a feature request as
index 90387c3540f70e4cb99e2401b2f608672f51ffc3..f4021a285460353ca0e4a2eda7b934d7839b57ff 100644 (file)
@@ -17,7 +17,7 @@ Credits:
     Philip Edelbrock <phil@netroedge.com>,
     and Mark Studebaker <mdsxyz123@yahoo.com>
   w83792d.c:
-    Chunhao Huang <DZShen@Winbond.com.tw>,
+    Shane Huang (Winbond),
     Rudolf Marek <r.marek@assembler.cz>
 
 Additional contributors:
index 8a023ce0b72e7726bf8888b88d304f0be5ce51a3..53f7b6866fec4d51c4049ba6c700d58e1950a046 100644 (file)
@@ -7,8 +7,7 @@ Supported chips:
     Addresses scanned: I2C 0x2c - 0x2f
     Datasheet: http://www.winbond.com.tw
 
-Author: Chunhao Huang
-Contact: DZShen <DZShen@Winbond.com.tw>
+Author: Shane Huang (Winbond)
 
 
 Module Parameters
index e349f293cc9829dc5cad185a41f95cb8627e90ea..8ef6dbb6a462d707401fe08289dfa51702125789 100644 (file)
@@ -175,11 +175,9 @@ Searching in menuconfig:
                /^hotplug
 
        When searching, symbols are sorted thus:
-         - exact match first: an exact match is when the search matches
-           the complete symbol name;
-         - alphabetical order: when two symbols do not match exactly,
-           they are sorted in alphabetical order (in the user's current
-           locale).
+         - first, exact matches, sorted alphabetically (an exact match
+           is when the search matches the complete symbol name);
+         - then, other matches, sorted alphabetically.
        For example: ^ATH.K matches:
            ATH5K ATH9K ATH5K_AHB ATH5K_DEBUG [...] ATH6KL ATH6KL_DEBUG
            [...] ATH9K_AHB ATH9K_BTCOEX_SUPPORT ATH9K_COMMON [...]
index 15356aca938cd9a7bb2cdef09d8e7a19da36db90..5ec77aad1773ce5f55894cff118edfe9229830cd 100644 (file)
@@ -235,10 +235,61 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        Format: To spoof as Windows 98: ="Microsoft Windows"
 
        acpi_osi=       [HW,ACPI] Modify list of supported OS interface strings
-                       acpi_osi="string1"      # add string1 -- only one string
-                       acpi_osi="!string2"     # remove built-in string2
+                       acpi_osi="string1"      # add string1
+                       acpi_osi="!string2"     # remove string2
+                       acpi_osi=!*             # remove all strings
+                       acpi_osi=!              # disable all built-in OS vendor
+                                                 strings
                        acpi_osi=               # disable all strings
 
+                       'acpi_osi=!' can be used in combination with single or
+                       multiple 'acpi_osi="string1"' to support specific OS
+                       vendor string(s).  Note that such command can only
+                       affect the default state of the OS vendor strings, thus
+                       it cannot affect the default state of the feature group
+                       strings and the current state of the OS vendor strings,
+                       specifying it multiple times through kernel command line
+                       is meaningless.  This command is useful when one do not
+                       care about the state of the feature group strings which
+                       should be controlled by the OSPM.
+                       Examples:
+                         1. 'acpi_osi=! acpi_osi="Windows 2000"' is equivalent
+                            to 'acpi_osi="Windows 2000" acpi_osi=!', they all
+                            can make '_OSI("Windows 2000")' TRUE.
+
+                       'acpi_osi=' cannot be used in combination with other
+                       'acpi_osi=' command lines, the _OSI method will not
+                       exist in the ACPI namespace.  NOTE that such command can
+                       only affect the _OSI support state, thus specifying it
+                       multiple times through kernel command line is also
+                       meaningless.
+                       Examples:
+                         1. 'acpi_osi=' can make 'CondRefOf(_OSI, Local1)'
+                            FALSE.
+
+                       'acpi_osi=!*' can be used in combination with single or
+                       multiple 'acpi_osi="string1"' to support specific
+                       string(s).  Note that such command can affect the
+                       current state of both the OS vendor strings and the
+                       feature group strings, thus specifying it multiple times
+                       through kernel command line is meaningful.  But it may
+                       still not able to affect the final state of a string if
+                       there are quirks related to this string.  This command
+                       is useful when one want to control the state of the
+                       feature group strings to debug BIOS issues related to
+                       the OSPM features.
+                       Examples:
+                         1. 'acpi_osi="Module Device" acpi_osi=!*' can make
+                            '_OSI("Module Device")' FALSE.
+                         2. 'acpi_osi=!* acpi_osi="Module Device"' can make
+                            '_OSI("Module Device")' TRUE.
+                         3. 'acpi_osi=! acpi_osi=!* acpi_osi="Windows 2000"' is
+                            equivalent to
+                            'acpi_osi=!* acpi_osi=! acpi_osi="Windows 2000"'
+                            and
+                            'acpi_osi=!* acpi_osi="Windows 2000" acpi_osi=!',
+                            they all will make '_OSI("Windows 2000")' TRUE.
+
        acpi_pm_good    [X86]
                        Override the pmtimer bug detection: force the kernel
                        to assume that this machine's pmtimer latches its value
index 69f9fb3701e07804961f931ef76ea5716b4f8312..79a1bc675a8dd468bf2b9153690459230196408a 100644 (file)
@@ -8,8 +8,8 @@ http://acpi4asus.sf.net/
 
  This driver provides support for extra features of ACPI-compatible ASUS laptops.
  It may also support some MEDION, JVC or VICTOR laptops (such as MEDION 9675 or
- VICTOR XP7210 for example). It makes all the extra buttons generate standard
ACPI events that go through /proc/acpi/events and input events (like keyboards).
+ VICTOR XP7210 for example). It makes all the extra buttons generate input
+ events (like keyboards).
  On some models adds support for changing the display brightness and output,
  switching the LCD backlight on and off, and most importantly, allows you to
  blink those fancy LEDs intended for reporting mail and wireless status.
@@ -55,8 +55,8 @@ Usage
   DSDT) to me.
 
   That's all, now, all the events generated by the hotkeys of your laptop
-  should be reported in your /proc/acpi/event entry. You can check with
-  "acpi_listen".
+  should be reported via netlink events. You can check with
+  "acpi_genl monitor" (part of the acpica project).
 
   Hotkeys are also reported as input keys (like keyboards) you can check
   which key are supported using "xev" under X11.
index 0d5ac7f5287e611d4aa171937a1d83b31d0f6038..978b1e615155da1e4ddd24429c63708795965dd2 100644 (file)
@@ -12,10 +12,10 @@ Fn keys (hotkeys):
 ------------------
 Some models report hotkeys through the SNC or SPIC devices, such events are
 reported both through the ACPI subsystem as acpi events and through the INPUT
-subsystem. See the logs of acpid or /proc/acpi/event and
-/proc/bus/input/devices to find out what those events are and which input
-devices are created by the driver. Additionally, loading the driver with the
-debug option will report all events in the kernel log.
+subsystem. See the logs of /proc/bus/input/devices to find out what those
+events are and which input devices are created by the driver.
+Additionally, loading the driver with the debug option will report all events
+in the kernel log.
 
 The "scancodes" passed to the input system (that can be remapped with udev)
 are indexes to the table "sony_laptop_input_keycode_map" in the sony-laptop.c
index cf7bc6cb9719adca0bf96f2f65e7640f8866ceb2..86c52360ffe7326cce53541897d4aa98b86f0e8a 100644 (file)
@@ -329,20 +329,6 @@ sysfs notes:
 
                This attribute has poll()/select() support.
 
-       hotkey_report_mode:
-               Returns the state of the procfs ACPI event report mode
-               filter for hot keys.  If it is set to 1 (the default),
-               all hot key presses are reported both through the input
-               layer and also as ACPI events through procfs (but not
-               through netlink).  If it is set to 2, hot key presses
-               are reported only through the input layer.
-
-               This attribute is read-only in kernels 2.6.23 or later,
-               and read-write on earlier kernels.
-
-               May return -EPERM (write access locked out by module
-               parameter) or -EACCES (read-only).
-
        wakeup_reason:
                Set to 1 if the system is waking up because the user
                requested a bay ejection.  Set to 2 if the system is
@@ -518,24 +504,21 @@ SW_TABLET_MODE    Tablet ThinkPads HKEY events 0x5009 and 0x500A
 Non hotkey ACPI HKEY event map:
 -------------------------------
 
-Events that are not propagated by the driver, except for legacy
-compatibility purposes when hotkey_report_mode is set to 1:
-
-0x5001         Lid closed
-0x5002         Lid opened
-0x5009         Tablet swivel: switched to tablet mode
-0x500A         Tablet swivel: switched to normal mode
-0x7000         Radio Switch may have changed state
-
 Events that are never propagated by the driver:
 
 0x2304         System is waking up from suspend to undock
 0x2305         System is waking up from suspend to eject bay
 0x2404         System is waking up from hibernation to undock
 0x2405         System is waking up from hibernation to eject bay
+0x5001         Lid closed
+0x5002         Lid opened
+0x5009         Tablet swivel: switched to tablet mode
+0x500A         Tablet swivel: switched to normal mode
 0x5010         Brightness level changed/control event
 0x6000         KEYBOARD: Numlock key pressed
 0x6005         KEYBOARD: Fn key pressed (TO BE VERIFIED)
+0x7000         Radio Switch may have changed state
+
 
 Events that are propagated by the driver to userspace:
 
@@ -574,50 +557,6 @@ operating system is to force either an immediate suspend or hibernate
 cycle, or a system shutdown.  Obviously, something is very wrong if this
 happens.
 
-Compatibility notes:
-
-ibm-acpi and thinkpad-acpi 0.15 (mainline kernels before 2.6.23) never
-supported the input layer, and sent events over the procfs ACPI event
-interface.
-
-To avoid sending duplicate events over the input layer and the ACPI
-event interface, thinkpad-acpi 0.16 implements a module parameter
-(hotkey_report_mode), and also a sysfs device attribute with the same
-name.
-
-Make no mistake here: userspace is expected to switch to using the input
-layer interface of thinkpad-acpi, together with the ACPI netlink event
-interface in kernels 2.6.23 and later, or with the ACPI procfs event
-interface in kernels 2.6.22 and earlier.
-
-If no hotkey_report_mode module parameter is specified (or it is set to
-zero), the driver defaults to mode 1 (see below), and on kernels 2.6.22
-and earlier, also allows one to change the hotkey_report_mode through
-sysfs.  In kernels 2.6.23 and later, where the netlink ACPI event
-interface is available, hotkey_report_mode cannot be changed through
-sysfs (it is read-only).
-
-If the hotkey_report_mode module parameter is set to 1 or 2, it cannot
-be changed later through sysfs (any writes will return -EPERM to signal
-that hotkey_report_mode was locked.  On 2.6.23 and later, where
-hotkey_report_mode cannot be changed at all, writes will return -EACCES).
-
-hotkey_report_mode set to 1 makes the driver export through the procfs
-ACPI event interface all hot key presses (which are *also* sent to the
-input layer).  This is a legacy compatibility behaviour, and it is also
-the default mode of operation for the driver.
-
-hotkey_report_mode set to 2 makes the driver filter out the hot key
-presses from the procfs ACPI event interface, so these events will only
-be sent through the input layer.  Userspace that has been updated to use
-the thinkpad-acpi input layer interface should set hotkey_report_mode to
-2.
-
-Hot key press events are never sent to the ACPI netlink event interface.
-Really up-to-date userspace under kernel 2.6.23 and later is to use the
-netlink interface and the input layer interface, and don't bother at all
-with hotkey_report_mode.
-
 
 Brightness hotkey notes:
 
index 32dfbd924121f13747f220d692b0ad61a3a507d2..18b64b2b8a682552b4c3fd08f607a817218615c5 100644 (file)
@@ -124,6 +124,8 @@ multiqueue.txt
        - HOWTO for multiqueue network device support.
 netconsole.txt
        - The network console module netconsole.ko: configuration and notes.
+netdev-FAQ.txt
+       - FAQ describing how to submit net changes to netdev mailing list.
 netdev-features.txt
        - Network interface features API description.
 netdevices.txt
index 10742902146fc1da3ae1c84a94929b42a79e29d0..36be26b2ef7af81407771420e3e146099bf6b468 100644 (file)
@@ -440,6 +440,10 @@ tcp_syncookies - BOOLEAN
        SYN flood warnings in logs not being really flooded, your server
        is seriously misconfigured.
 
+       If you want to test which effects syncookies have to your
+       network connections you can set this knob to 2 to enable
+       unconditionally generation of syncookies.
+
 tcp_fastopen - INTEGER
        Enable TCP Fast Open feature (draft-ietf-tcpm-fastopen) to send data
        in the opening SYN packet. To use this feature, the client application
@@ -516,6 +520,19 @@ tcp_wmem - vector of 3 INTEGERs: min, default, max
        this value is ignored.
        Default: between 64K and 4MB, depending on RAM size.
 
+tcp_notsent_lowat - UNSIGNED INTEGER
+       A TCP socket can control the amount of unsent bytes in its write queue,
+       thanks to TCP_NOTSENT_LOWAT socket option. poll()/select()/epoll()
+       reports POLLOUT events if the amount of unsent bytes is below a per
+       socket value, and if the write queue is not full. sendmsg() will
+       also not add new buffers if the limit is hit.
+
+       This global variable controls the amount of unsent data for
+       sockets not using TCP_NOTSENT_LOWAT. For these sockets, a change
+       to the global variable has immediate effect.
+
+       Default: UINT_MAX (0xFFFFFFFF)
+
 tcp_workaround_signed_windows - BOOLEAN
        If set, assume no receipt of a window scaling option means the
        remote TCP is broken and treats the window as a signed quantity.
diff --git a/Documentation/networking/netdev-FAQ.txt b/Documentation/networking/netdev-FAQ.txt
new file mode 100644 (file)
index 0000000..d9112f0
--- /dev/null
@@ -0,0 +1,224 @@
+
+Information you need to know about netdev
+-----------------------------------------
+
+Q: What is netdev?
+
+A: It is a mailing list for all network related linux stuff.  This includes
+   anything found under net/  (i.e. core code like IPv6) and drivers/net
+   (i.e. hardware specific drivers) in the linux source tree.
+
+   Note that some subsystems (e.g. wireless drivers) which have a high volume
+   of traffic have their own specific mailing lists.
+
+   The netdev list is managed (like many other linux mailing lists) through
+   VGER ( http://vger.kernel.org/ ) and archives can be found below:
+
+       http://marc.info/?l=linux-netdev
+       http://www.spinics.net/lists/netdev/
+
+   Aside from subsystems like that mentioned above, all network related linux
+   development (i.e. RFC, review, comments, etc) takes place on netdev.
+
+Q: How do the changes posted to netdev make their way into linux?
+
+A: There are always two trees (git repositories) in play.  Both are driven
+   by David Miller, the main network maintainer.  There is the "net" tree,
+   and the "net-next" tree.  As you can probably guess from the names, the
+   net tree is for fixes to existing code already in the mainline tree from
+   Linus, and net-next is where the new code goes for the future release.
+   You can find the trees here:
+
+       http://git.kernel.org/?p=linux/kernel/git/davem/net.git
+       http://git.kernel.org/?p=linux/kernel/git/davem/net-next.git
+
+Q: How often do changes from these trees make it to the mainline Linus tree?
+
+A: To understand this, you need to know a bit of background information
+   on the cadence of linux development.  Each new release starts off with
+   a two week "merge window" where the main maintainers feed their new
+   stuff to Linus for merging into the mainline tree.  After the two weeks,
+   the merge window is closed, and it is called/tagged "-rc1".  No new
+   features get mainlined after this -- only fixes to the rc1 content
+   are expected.  After roughly a week of collecting fixes to the rc1
+   content, rc2 is released.  This repeats on a roughly weekly basis
+   until rc7 (typically; sometimes rc6 if things are quiet, or rc8 if
+   things are in a state of churn), and a week after the last vX.Y-rcN
+   was done, the official "vX.Y" is released.
+
+   Relating that to netdev:  At the beginning of the 2 week merge window,
+   the net-next tree will be closed - no new changes/features.  The
+   accumulated new content of the past ~10 weeks will be passed onto
+   mainline/Linus via a pull request for vX.Y -- at the same time,
+   the "net" tree will start accumulating fixes for this pulled content
+   relating to vX.Y
+
+   An announcement indicating when net-next has been closed is usually
+   sent to netdev, but knowing the above, you can predict that in advance.
+
+   IMPORTANT:  Do not send new net-next content to netdev during the
+   period during which net-next tree is closed.
+
+   Shortly after the two weeks have passed, (and vX.Y-rc1 is released) the
+   tree for net-next reopens to collect content for the next (vX.Y+1) release.
+
+   If you aren't subscribed to netdev and/or are simply unsure if net-next
+   has re-opened yet, simply check the net-next git repository link above for
+   any new networking related commits.
+
+   The "net" tree continues to collect fixes for the vX.Y content, and
+   is fed back to Linus at regular (~weekly) intervals.  Meaning that the
+   focus for "net" is on stablilization and bugfixes.
+
+   Finally, the vX.Y gets released, and the whole cycle starts over.
+
+Q: So where are we now in this cycle?
+
+A: Load the mainline (Linus) page here:
+
+       http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git
+
+   and note the top of the "tags" section.  If it is rc1, it is early
+   in the dev cycle.  If it was tagged rc7 a week ago, then a release
+   is probably imminent.
+
+Q: How do I indicate which tree (net vs. net-next) my patch should be in?
+
+A: Firstly, think whether you have a bug fix or new "next-like" content.
+   Then once decided, assuming that you use git, use the prefix flag, i.e.
+
+       git format-patch --subject-prefix='PATCH net-next' start..finish
+
+   Use "net" instead of "net-next" (always lower case) in the above for
+   bug-fix net content.  If you don't use git, then note the only magic in
+   the above is just the subject text of the outgoing e-mail, and you can
+   manually change it yourself with whatever MUA you are comfortable with.
+
+Q: I sent a patch and I'm wondering what happened to it.  How can I tell
+   whether it got merged?
+
+A: Start by looking at the main patchworks queue for netdev:
+
+       http://patchwork.ozlabs.org/project/netdev/list/
+
+   The "State" field will tell you exactly where things are at with
+   your patch.
+
+Q: The above only says "Under Review".  How can I find out more?
+
+A: Generally speaking, the patches get triaged quickly (in less than 48h).
+   So be patient.  Asking the maintainer for status updates on your
+   patch is a good way to ensure your patch is ignored or pushed to
+   the bottom of the priority list.
+
+Q: How can I tell what patches are queued up for backporting to the
+   various stable releases?
+
+A: Normally Greg Kroah-Hartman collects stable commits himself, but
+   for networking, Dave collects up patches he deems critical for the
+   networking subsystem, and then hands them off to Greg.
+
+   There is a patchworks queue that you can see here:
+       http://patchwork.ozlabs.org/bundle/davem/stable/?state=*
+
+   It contains the patches which Dave has selected, but not yet handed
+   off to Greg.  If Greg already has the patch, then it will be here:
+       http://git.kernel.org/cgit/linux/kernel/git/stable/stable-queue.git
+
+   A quick way to find whether the patch is in this stable-queue is
+   to simply clone the repo, and then git grep the mainline commit ID, e.g.
+
+       stable-queue$ git grep -l 284041ef21fdf2e
+       releases/3.0.84/ipv6-fix-possible-crashes-in-ip6_cork_release.patch
+       releases/3.4.51/ipv6-fix-possible-crashes-in-ip6_cork_release.patch
+       releases/3.9.8/ipv6-fix-possible-crashes-in-ip6_cork_release.patch
+       stable/stable-queue$
+
+Q: I see a network patch and I think it should be backported to stable.
+   Should I request it via "stable@vger.kernel.org" like the references in
+   the kernel's Documentation/stable_kernel_rules.txt file say?
+
+A: No, not for networking.  Check the stable queues as per above 1st to see
+   if it is already queued.  If not, then send a mail to netdev, listing
+   the upstream commit ID and why you think it should be a stable candidate.
+
+   Before you jump to go do the above, do note that the normal stable rules
+   in Documentation/stable_kernel_rules.txt still apply.  So you need to
+   explicitly indicate why it is a critical fix and exactly what users are
+   impacted.  In addition, you need to convince yourself that you _really_
+   think it has been overlooked, vs. having been considered and rejected.
+
+   Generally speaking, the longer it has had a chance to "soak" in mainline,
+   the better the odds that it is an OK candidate for stable.  So scrambling
+   to request a commit be added the day after it appears should be avoided.
+
+Q: I have created a network patch and I think it should be backported to
+   stable.  Should I add a "Cc: stable@vger.kernel.org" like the references
+   in the kernel's Documentation/ directory say?
+
+A: No.  See above answer.  In short, if you think it really belongs in
+   stable, then ensure you write a decent commit log that describes who
+   gets impacted by the bugfix and how it manifests itself, and when the
+   bug was introduced.  If you do that properly, then the commit will
+   get handled appropriately and most likely get put in the patchworks
+   stable queue if it really warrants it.
+
+   If you think there is some valid information relating to it being in
+   stable that does _not_ belong in the commit log, then use the three
+   dash marker line as described in Documentation/SubmittingPatches to
+   temporarily embed that information into the patch that you send.
+
+Q: Someone said that the comment style and coding convention is different
+   for the networking content.  Is this true?
+
+A: Yes, in a largely trivial way.  Instead of this:
+
+       /*
+        * foobar blah blah blah
+        * another line of text
+        */
+
+   it is requested that you make it look like this:
+
+       /* foobar blah blah blah
+        * another line of text
+        */
+
+Q: I am working in existing code that has the former comment style and not the
+   latter.  Should I submit new code in the former style or the latter?
+
+A: Make it the latter style, so that eventually all code in the domain of
+   netdev is of this format.
+
+Q: I found a bug that might have possible security implications or similar.
+   Should I mail the main netdev maintainer off-list?
+
+A: No. The current netdev maintainer has consistently requested that people
+   use the mailing lists and not reach out directly.  If you aren't OK with
+   that, then perhaps consider mailing "security@kernel.org" or reading about
+   http://oss-security.openwall.org/wiki/mailing-lists/distros
+   as possible alternative mechanisms.
+
+Q: What level of testing is expected before I submit my change?
+
+A: If your changes are against net-next, the expectation is that you
+   have tested by layering your changes on top of net-next.  Ideally you
+   will have done run-time testing specific to your change, but at a
+   minimum, your changes should survive an "allyesconfig" and an
+   "allmodconfig" build without new warnings or failures.
+
+Q: Any other tips to help ensure my net/net-next patch gets OK'd?
+
+A: Attention to detail.  Re-read your own work as if you were the
+   reviewer.  You can start with using checkpatch.pl, perhaps even
+   with the "--strict" flag.  But do not be mindlessly robotic in
+   doing so.  If your change is a bug-fix, make sure your commit log
+   indicates the end-user visible symptom, the underlying reason as
+   to why it happens, and then if necessary, explain why the fix proposed
+   is the best way to get things done.   Don't mangle whitespace, and as
+   is common, don't mis-indent function arguments that span multiple lines.
+   If it is your 1st patch, mail it to yourself so you can test apply
+   it to an unpatched tree to confirm infrastructure didn't mangle it.
+
+   Finally, go back and read Documentation/SubmittingPatches to be
+   sure you are not repeating some common mistake documented there.
index 0c790a76910ef81052faeff278d57b5b4fe2499b..97b810ca9082dbad569c57b8b9bdd6f0a8dda1c1 100644 (file)
@@ -19,7 +19,6 @@ of SCTP that is RFC 2960 compliant and provides an programming interface
 referred to as the  UDP-style API of the Sockets Extensions for SCTP, as 
 proposed in IETF Internet-Drafts.    
 
-
 Caveats:  
 
 -lksctp can be built as statically or as a module.  However, be aware that 
@@ -33,6 +32,4 @@ For more information, please visit the lksctp project website:
    http://www.sf.net/projects/lksctp
 
 Or contact the lksctp developers through the mailing list:
-   <lksctp-developers@lists.sourceforge.net> 
-
-
+   <linux-sctp@vger.kernel.org>
index 809d72b8eff1a8217dc5e7666f3e895019421f9c..a46ddb85e83a0dcdf0f2a54fd9b745eadb31cb6f 100644 (file)
@@ -244,6 +244,7 @@ STAC9227/9228/9229/927x
   5stack-no-fp D965 5stack without front panel
   dell-3stack  Dell Dimension E520
   dell-bios    Fixes with Dell BIOS setup
+  dell-bios-amic Fixes with Dell BIOS setup including analog mic
   volknob      Fixes with volume-knob widget 0x24
   auto         BIOS setup (default)
 
index c3c912d023cc5c184c6f0496344cb1a1a82265eb..42a0a39b77e6a5da339e0f71717a6d3809986c24 100644 (file)
@@ -454,6 +454,8 @@ The generic parser supports the following hints:
 - need_dac_fix (bool): limits the DACs depending on the channel count
 - primary_hp (bool): probe headphone jacks as the primary outputs;
   default true
+- multi_io (bool): try probing multi-I/O config (e.g. shared
+  line-in/surround, mic/clfe jacks)
 - multi_cap_vol (bool): provide multiple capture volumes
 - inv_dmic_split (bool): provide split internal mic volume/switch for
   phase-inverted digital mics
index 1c15043aaee4c89bf2c76aca10633557c1327bd3..d569f2a424d511218f679258bbb246cae2438b25 100644 (file)
@@ -52,7 +52,7 @@ Default: 64
 
 busy_read
 ----------------
-Low latency busy poll timeout for socket reads. (needs CONFIG_NET_LL_RX_POLL)
+Low latency busy poll timeout for socket reads. (needs CONFIG_NET_RX_BUSY_POLL)
 Approximate time in us to busy loop waiting for packets on the device queue.
 This sets the default value of the SO_BUSY_POLL socket option.
 Can be set or overridden per socket by setting socket option SO_BUSY_POLL,
@@ -63,7 +63,7 @@ Default: 0 (off)
 
 busy_poll
 ----------------
-Low latency busy poll timeout for poll and select. (needs CONFIG_NET_LL_RX_POLL)
+Low latency busy poll timeout for poll and select. (needs CONFIG_NET_RX_BUSY_POLL)
 Approximate time in us to busy loop waiting for events.
 Recommended value depends on the number of sockets you poll on.
 For several sockets 50, for several hundreds 100.
index a26b10e52aea18cf39b61095cc563cd940ff1dac..35884db94bfe8c5005ff08b17563dd63f6f27bb7 100644 (file)
@@ -1406,7 +1406,7 @@ ATHEROS ATH6KL WIRELESS DRIVER
 M:     Kalle Valo <kvalo@qca.qualcomm.com>
 L:     linux-wireless@vger.kernel.org
 W:     http://wireless.kernel.org/en/users/Drivers/ath6kl
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath6kl.git
+T:     git git://github.com/kvalo/ath.git
 S:     Supported
 F:     drivers/net/wireless/ath/ath6kl/
 
@@ -2871,7 +2871,7 @@ F:        drivers/media/usb/dvb-usb-v2/dvb_usb*
 F:     drivers/media/usb/dvb-usb-v2/usb_urb.c
 
 DYNAMIC DEBUG
-M:     Jason Baron <jbaron@redhat.com>
+M:     Jason Baron <jbaron@akamai.com>
 S:     Maintained
 F:     lib/dynamic_debug.c
 F:     include/linux/dynamic_debug.h
@@ -5391,6 +5391,7 @@ F:        drivers/watchdog/mena21_wdt.c
 
 METAG ARCHITECTURE
 M:     James Hogan <james.hogan@imgtec.com>
+L:     linux-metag@vger.kernel.org
 S:     Supported
 F:     arch/metag/
 F:     Documentation/metag/
@@ -6726,6 +6727,14 @@ T:       git git://linuxtv.org/anttip/media_tree.git
 S:     Maintained
 F:     drivers/media/tuners/qt1010*
 
+QUALCOMM ATHEROS ATH10K WIRELESS DRIVER
+M:     Kalle Valo <kvalo@qca.qualcomm.com>
+L:     ath10k@lists.infradead.org
+W:     http://wireless.kernel.org/en/users/Drivers/ath10k
+T:     git git://github.com/kvalo/ath.git
+S:     Supported
+F:     drivers/net/wireless/ath/ath10k/
+
 QUALCOMM HEXAGON ARCHITECTURE
 M:     Richard Kuo <rkuo@codeaurora.org>
 L:     linux-hexagon@vger.kernel.org
@@ -7118,6 +7127,7 @@ F:        drivers/tty/serial
 
 SYNOPSYS DESIGNWARE DMAC DRIVER
 M:     Viresh Kumar <viresh.linux@gmail.com>
+M:     Andy Shevchenko <andriy.shevchenko@linux.intel.com>
 S:     Maintained
 F:     include/linux/dw_dmac.h
 F:     drivers/dma/dw/
@@ -7223,6 +7233,7 @@ W:        http://lksctp.sourceforge.net
 S:     Maintained
 F:     Documentation/networking/sctp.txt
 F:     include/linux/sctp.h
+F:     include/uapi/linux/sctp.h
 F:     include/net/sctp/
 F:     net/sctp/
 
@@ -8270,7 +8281,7 @@ S:        Maintained
 F:     sound/soc/codecs/twl4030*
 
 TI WILINK WIRELESS DRIVERS
-M:     Luciano Coelho <coelho@ti.com>
+M:     Luciano Coelho <luca@coelho.fi>
 L:     linux-wireless@vger.kernel.org
 W:     http://wireless.kernel.org/en/users/Drivers/wl12xx
 W:     http://wireless.kernel.org/en/users/Drivers/wl1251
diff --git a/arch/arc/boot/.gitignore b/arch/arc/boot/.gitignore
new file mode 100644 (file)
index 0000000..5d65b54
--- /dev/null
@@ -0,0 +1 @@
+*.dtb*
index 8943c028d4bbe3ae2aea2875aae5c2d7e3dd2bda..884081099f800fd6b4ba133bc1f1746084845c49 100644 (file)
@@ -38,6 +38,7 @@
 #include <asm/ptrace.h>
 #include <asm/processor.h>     /* For VMALLOC_START */
 #include <asm/thread_info.h>   /* For THREAD_SIZE */
+#include <asm/mmu.h>
 
 /* Note on the LD/ST addr modes with addr reg wback
  *
  * it to memory (non-SMP case) or SCRATCH0 Aux Reg (SMP).
  *
  * Before saving the full regfile - this reg is restored back, only
- * to be saved again on kernel mode stack, as part of ptregs.
+ * to be saved again on kernel mode stack, as part of pt_regs.
  *-------------------------------------------------------------*/
 .macro EXCPN_PROLOG_FREEUP_REG reg
 #ifdef CONFIG_SMP
 #endif
 .endm
 
+/*--------------------------------------------------------------
+ * Exception Entry prologue
+ * -Switches stack to K mode (if not already)
+ * -Saves the register file
+ *
+ * After this it is safe to call the "C" handlers
+ *-------------------------------------------------------------*/
+.macro EXCEPTION_PROLOGUE
+
+       /* Need at least 1 reg to code the early exception prologue */
+       EXCPN_PROLOG_FREEUP_REG r9
+
+       /* U/K mode at time of exception (stack not switched if already K) */
+       lr  r9, [erstatus]
+
+       /* ARC700 doesn't provide auto-stack switching */
+       SWITCH_TO_KERNEL_STK
+
+       /* save the regfile */
+       SAVE_ALL_SYS
+.endm
+
 /*--------------------------------------------------------------
  * Save all registers used by Exceptions (TLB Miss, Prot-V, Mem err etc)
  * Requires SP to be already switched to kernel mode Stack
index d99f79bcf865a248ddb1c1dfa1eb35a58ae5f948..b68b53f458d1bc07f89b5b64c8f9fd9dc84ba323 100644 (file)
@@ -157,13 +157,6 @@ static inline void arch_unmask_irq(unsigned int irq)
        flag    \scratch
 .endm
 
-.macro IRQ_DISABLE_SAVE  scratch, save
-       lr      \scratch, [status32]
-       mov     \save, \scratch         /* Make a copy */
-       bic     \scratch, \scratch, (STATUS_E1_MASK | STATUS_E2_MASK)
-       flag    \scratch
-.endm
-
 .macro IRQ_ENABLE  scratch
        lr      \scratch, [status32]
        or      \scratch, \scratch, (STATUS_E1_MASK | STATUS_E2_MASK)
index 7c03fe61759c2262d30550cfc6ad73dd363b2903..baf923f689c113b66a375737f66c39b78e9de270 100644 (file)
@@ -32,6 +32,8 @@
 /* Error code if probe fails */
 #define TLB_LKUP_ERR           0x80000000
 
+#define TLB_DUP_ERR    (TLB_LKUP_ERR | 0x00000001)
+
 /* TLB Commands */
 #define TLBWrite    0x1
 #define TLBRead     0x2
 #ifndef __ASSEMBLY__
 
 typedef struct {
-       unsigned long asid;     /* Pvt Addr-Space ID for mm */
-#ifdef CONFIG_ARC_TLB_DBG
-       struct task_struct *tsk;
-#endif
+       unsigned long asid[NR_CPUS];    /* Hw PID + Generation cycle */
 } mm_context_t;
 
 #ifdef CONFIG_ARC_DBG_TLB_PARANOIA
index 0d71fb11b57c753c5b1cb4dd13bd7b731b196e18..97949e70d690402ec5c70074a6d99511a28e96cc 100644 (file)
  * "Fast Context Switch" i.e. no TLB flush on ctxt-switch
  *
  * Linux assigns each task a unique ASID. A simple round-robin allocation
- * of H/w ASID is done using software tracker @asid_cache.
+ * of H/w ASID is done using software tracker @asid_cpu.
  * When it reaches max 255, the allocation cycle starts afresh by flushing
  * the entire TLB and wrapping ASID back to zero.
  *
- * For book-keeping, Linux uses a couple of data-structures:
- *  -mm_struct has an @asid field to keep a note of task's ASID (needed at the
- *   time of say switch_mm( )
- *  -An array of mm structs @asid_mm_map[] for asid->mm the reverse mapping,
- *  given an ASID, finding the mm struct associated.
- *
- * The round-robin allocation algorithm allows for ASID stealing.
- * If asid tracker is at "x-1", a new req will allocate "x", even if "x" was
- * already assigned to another (switched-out) task. Obviously the prev owner
- * is marked with an invalid ASID to make it request for a new ASID when it
- * gets scheduled next time. However its TLB entries (with ASID "x") could
- * exist, which must be cleared before the same ASID is used by the new owner.
- * Flushing them would be plausible but costly solution. Instead we force a
- * allocation policy quirk, which ensures that a stolen ASID won't have any
- * TLB entries associates, alleviating the need to flush.
- * The quirk essentially is not allowing ASID allocated in prev cycle
- * to be used past a roll-over in the next cycle.
- * When this happens (i.e. task ASID > asid tracker), task needs to refresh
- * its ASID, aligning it to current value of tracker. If the task doesn't get
- * scheduled past a roll-over, hence its ASID is not yet realigned with
- * tracker, such ASID is anyways safely reusable because it is
- * gauranteed that TLB entries with that ASID wont exist.
+ * A new allocation cycle, post rollover, could potentially reassign an ASID
+ * to a different task. Thus the rule is to refresh the ASID in a new cycle.
+ * The 32 bit @asid_cpu (and mm->asid) have 8 bits MMU PID and rest 24 bits
+ * serve as cycle/generation indicator and natural 32 bit unsigned math
+ * automagically increments the generation when lower 8 bits rollover.
  */
 
-#define FIRST_ASID  0
-#define MAX_ASID    255                        /* 8 bit PID field in PID Aux reg */
-#define NO_ASID     (MAX_ASID + 1)     /* ASID Not alloc to mmu ctxt */
-#define NUM_ASID    ((MAX_ASID - FIRST_ASID) + 1)
+#define MM_CTXT_ASID_MASK      0x000000ff /* MMU PID reg :8 bit PID */
+#define MM_CTXT_CYCLE_MASK     (~MM_CTXT_ASID_MASK)
+
+#define MM_CTXT_FIRST_CYCLE    (MM_CTXT_ASID_MASK + 1)
+#define MM_CTXT_NO_ASID                0UL
 
-/* ASID to mm struct mapping */
-extern struct mm_struct *asid_mm_map[NUM_ASID + 1];
+#define asid_mm(mm, cpu)       mm->context.asid[cpu]
+#define hw_pid(mm, cpu)                (asid_mm(mm, cpu) & MM_CTXT_ASID_MASK)
 
-extern int asid_cache;
+DECLARE_PER_CPU(unsigned int, asid_cache);
+#define asid_cpu(cpu)          per_cpu(asid_cache, cpu)
 
 /*
- * Assign a new ASID to task. If the task already has an ASID, it is
- * relinquished.
+ * Get a new ASID if task doesn't have a valid one (unalloc or from prev cycle)
+ * Also set the MMU PID register to existing/updated ASID
  */
 static inline void get_new_mmu_context(struct mm_struct *mm)
 {
-       struct mm_struct *prev_owner;
+       const unsigned int cpu = smp_processor_id();
        unsigned long flags;
 
        local_irq_save(flags);
 
        /*
-        * Relinquish the currently owned ASID (if any).
-        * Doing unconditionally saves a cmp-n-branch; for already unused
-        * ASID slot, the value was/remains NULL
+        * Move to new ASID if it was not from current alloc cycle/generation.
+        * Callers needing new ASID unconditionally, independent of alloc-cycle
+        * (local_flush_tlb_mm() for forking  parent) first need to destroy the
+        * context, setting it to invalid value, which the check below would
+        * catch too
         */
-       asid_mm_map[mm->context.asid] = (struct mm_struct *)NULL;
+       if (!((asid_mm(mm, cpu) ^ asid_cpu(cpu)) & MM_CTXT_CYCLE_MASK))
+               goto set_hw;
 
        /* move to new ASID */
-       if (++asid_cache > MAX_ASID) {  /* ASID roll-over */
-               asid_cache = FIRST_ASID;
-               flush_tlb_all();
+       if (!(++asid_cpu(cpu) & MM_CTXT_ASID_MASK)) {   /* ASID roll-over */
+               local_flush_tlb_all();
        }
 
-       /*
-        * Is next ASID already owned by some-one else (we are stealing it).
-        * If so, let the orig owner be aware of this, so when it runs, it
-        * asks for a brand new ASID. This would only happen for a long-lived
-        * task with ASID from prev allocation cycle (before ASID roll-over).
-        *
-        * This might look wrong - if we are re-using some other task's ASID,
-        * won't we use it's stale TLB entries too. Actually switch_mm( ) takes
-        * care of such a case: it ensures that task with ASID from prev alloc
-        * cycle, when scheduled will refresh it's ASID: see switch_mm( ) below
-        * The stealing scenario described here will only happen if that task
-        * didn't get a chance to refresh it's ASID - implying stale entries
-        * won't exist.
+       /* Above was rollover of 8 bit ASID in 32 bit container.
+        * If the container itself wrapped around, set it to a non zero
+        * "generation" to distinguish from no context
         */
-       prev_owner = asid_mm_map[asid_cache];
-       if (prev_owner)
-               prev_owner->context.asid = NO_ASID;
+       if (!asid_cpu(cpu))
+               asid_cpu(cpu) = MM_CTXT_FIRST_CYCLE;
 
        /* Assign new ASID to tsk */
-       asid_mm_map[asid_cache] = mm;
-       mm->context.asid = asid_cache;
-
-#ifdef CONFIG_ARC_TLB_DBG
-       pr_info("ARC_TLB_DBG: NewMM=0x%x OldMM=0x%x task_struct=0x%x Task: %s,"
-              " pid:%u, assigned asid:%lu\n",
-              (unsigned int)mm, (unsigned int)prev_owner,
-              (unsigned int)(mm->context.tsk), (mm->context.tsk)->comm,
-              (mm->context.tsk)->pid, mm->context.asid);
-#endif
+       asid_mm(mm, cpu) = asid_cpu(cpu);
 
-       write_aux_reg(ARC_REG_PID, asid_cache | MMU_ENABLE);
+set_hw:
+       write_aux_reg(ARC_REG_PID, hw_pid(mm, cpu) | MMU_ENABLE);
 
        local_irq_restore(flags);
 }
@@ -134,60 +102,66 @@ static inline void get_new_mmu_context(struct mm_struct *mm)
 static inline int
 init_new_context(struct task_struct *tsk, struct mm_struct *mm)
 {
-       mm->context.asid = NO_ASID;
-#ifdef CONFIG_ARC_TLB_DBG
-       mm->context.tsk = tsk;
-#endif
+       int i;
+
+       for (i = 0; i < NR_CPUS; i++)
+               asid_mm(mm, i) = MM_CTXT_NO_ASID;
+
        return 0;
 }
 
+static inline void destroy_context(struct mm_struct *mm)
+{
+       asid_mm(mm, smp_processor_id()) = MM_CTXT_NO_ASID;
+}
+
 /* Prepare the MMU for task: setup PID reg with allocated ASID
     If task doesn't have an ASID (never alloc or stolen, get a new ASID)
 */
 static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
                             struct task_struct *tsk)
 {
-#ifndef CONFIG_SMP
-       /* PGD cached in MMU reg to avoid 3 mem lookups: task->mm->pgd */
-       write_aux_reg(ARC_REG_SCRATCH_DATA0, next->pgd);
-#endif
+       int migrating = 0;
+
+#ifdef CONFIG_SMP
+       const int cpu = smp_processor_id();
 
        /*
-        * Get a new ASID if task doesn't have a valid one. Possible when
-        *  -task never had an ASID (fresh after fork)
-        *  -it's ASID was stolen - past an ASID roll-over.
-        *  -There's a third obscure scenario (if this task is running for the
-        *   first time afer an ASID rollover), where despite having a valid
-        *   ASID, we force a get for new ASID - see comments at top.
-        *
-        * Both the non-alloc scenario and first-use-after-rollover can be
-        * detected using the single condition below:  NO_ASID = 256
-        * while asid_cache is always a valid ASID value (0-255).
+        * If @next is migrating to a different CPU, force an ASID refresh (by
+        *      relinquishing current value as required by new implementation
+        *      of get_new_mmu_context()
+        * Use Case:
+        *      Task t1 migrates to a different core, forks, migrates back to
+        *      orig core. COW semantics requires it to have a new ASID now
+        *      so that pre-fork TLB entries can't be used.
         */
-       if (next->context.asid > asid_cache) {
-               get_new_mmu_context(next);
-       } else {
-               /*
-                * XXX: This will never happen given the chks above
-                * BUG_ON(next->context.asid > MAX_ASID);
-                */
-               write_aux_reg(ARC_REG_PID, next->context.asid | MMU_ENABLE);
-       }
-
-}
-
-static inline void destroy_context(struct mm_struct *mm)
-{
-       unsigned long flags;
+       cpumask_clear_cpu(cpu, mm_cpumask(prev));
+       migrating = !cpumask_test_and_set_cpu(cpu, mm_cpumask(next));
+       if (migrating)
+               destroy_context(next);
+#endif
 
-       local_irq_save(flags);
+       /* threads of same process (and not migrating cores in SMP) */
+       if ((prev == next) && !migrating)
+               return;
 
-       asid_mm_map[mm->context.asid] = NULL;
-       mm->context.asid = NO_ASID;
+#ifndef CONFIG_SMP
+       /* PGD cached in MMU reg to avoid 3 mem lookups: task->mm->pgd */
+       write_aux_reg(ARC_REG_SCRATCH_DATA0, next->pgd);
+#endif
 
-       local_irq_restore(flags);
+       get_new_mmu_context(next);
 }
 
+/*
+ * Called at the time of execve() to get a new ASID
+ * Note the subtlety here: get_new_mmu_context() behaves differently here
+ * vs. in switch_mm(). Here it always returns a new ASID, because mm has
+ * an unallocated "initial" value, while in latter, it moves to a new ASID,
+ * only if it was unallocated
+ */
+#define activate_mm(prev, next)                switch_mm(prev, next, NULL)
+
 /* it seemed that deactivate_mm( ) is a reasonable place to do book-keeping
  * for retiring-mm. However destroy_context( ) still needs to do that because
  * between mm_release( ) = >deactive_mm( ) and
@@ -197,17 +171,6 @@ static inline void destroy_context(struct mm_struct *mm)
  */
 #define deactivate_mm(tsk, mm)   do { } while (0)
 
-static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next)
-{
-#ifndef CONFIG_SMP
-       write_aux_reg(ARC_REG_SCRATCH_DATA0, next->pgd);
-#endif
-
-       /* Unconditionally get a new ASID */
-       get_new_mmu_context(next);
-
-}
-
 #define enter_lazy_tlb(mm, tsk)
 
 #endif /* __ASM_ARC_MMU_CONTEXT_H */
index 4749a0eee1cffcf3a06c916353af6db9facc19a1..6b0b7f7ef783cec0ecbd0bbd53e084be2011ae82 100644 (file)
 
 #define _PAGE_ACCESSED      (1<<1)     /* Page is accessed (S) */
 #define _PAGE_CACHEABLE     (1<<2)     /* Page is cached (H) */
-#define _PAGE_U_EXECUTE     (1<<3)     /* Page has user execute perm (H) */
-#define _PAGE_U_WRITE       (1<<4)     /* Page has user write perm (H) */
-#define _PAGE_U_READ        (1<<5)     /* Page has user read perm (H) */
-#define _PAGE_K_EXECUTE     (1<<6)     /* Page has kernel execute perm (H) */
-#define _PAGE_K_WRITE       (1<<7)     /* Page has kernel write perm (H) */
-#define _PAGE_K_READ        (1<<8)     /* Page has kernel perm (H) */
-#define _PAGE_GLOBAL        (1<<9)     /* Page is global (H) */
-#define _PAGE_MODIFIED      (1<<10)    /* Page modified (dirty) (S) */
-#define _PAGE_FILE          (1<<10)    /* page cache/ swap (S) */
-#define _PAGE_PRESENT       (1<<11)    /* TLB entry is valid (H) */
+#define _PAGE_EXECUTE       (1<<3)     /* Page has user execute perm (H) */
+#define _PAGE_WRITE         (1<<4)     /* Page has user write perm (H) */
+#define _PAGE_READ          (1<<5)     /* Page has user read perm (H) */
+#define _PAGE_MODIFIED      (1<<6)     /* Page modified (dirty) (S) */
+#define _PAGE_FILE          (1<<7)     /* page cache/ swap (S) */
+#define _PAGE_GLOBAL        (1<<8)     /* Page is global (H) */
+#define _PAGE_PRESENT       (1<<10)    /* TLB entry is valid (H) */
 
-#else
+#else  /* MMU v3 onwards */
 
-/* PD1 */
 #define _PAGE_CACHEABLE     (1<<0)     /* Page is cached (H) */
-#define _PAGE_U_EXECUTE     (1<<1)     /* Page has user execute perm (H) */
-#define _PAGE_U_WRITE       (1<<2)     /* Page has user write perm (H) */
-#define _PAGE_U_READ        (1<<3)     /* Page has user read perm (H) */
-#define _PAGE_K_EXECUTE     (1<<4)     /* Page has kernel execute perm (H) */
-#define _PAGE_K_WRITE       (1<<5)     /* Page has kernel write perm (H) */
-#define _PAGE_K_READ        (1<<6)     /* Page has kernel perm (H) */
-#define _PAGE_ACCESSED      (1<<7)     /* Page is accessed (S) */
-
-/* PD0 */
+#define _PAGE_EXECUTE       (1<<1)     /* Page has user execute perm (H) */
+#define _PAGE_WRITE         (1<<2)     /* Page has user write perm (H) */
+#define _PAGE_READ          (1<<3)     /* Page has user read perm (H) */
+#define _PAGE_ACCESSED      (1<<4)     /* Page is accessed (S) */
+#define _PAGE_MODIFIED      (1<<5)     /* Page modified (dirty) (S) */
+#define _PAGE_FILE          (1<<6)     /* page cache/ swap (S) */
 #define _PAGE_GLOBAL        (1<<8)     /* Page is global (H) */
 #define _PAGE_PRESENT       (1<<9)     /* TLB entry is valid (H) */
-#define _PAGE_SHARED_CODE   (1<<10)    /* Shared Code page with cmn vaddr
+#define _PAGE_SHARED_CODE   (1<<11)    /* Shared Code page with cmn vaddr
                                           usable for shared TLB entries (H) */
-
-#define _PAGE_MODIFIED      (1<<11)    /* Page modified (dirty) (S) */
-#define _PAGE_FILE          (1<<12)    /* page cache/ swap (S) */
-
-#define _PAGE_SHARED_CODE_H (1<<31)    /* Hardware counterpart of above */
 #endif
 
-/* Kernel allowed all permissions for all pages */
-#define _K_PAGE_PERMS  (_PAGE_K_EXECUTE | _PAGE_K_WRITE | _PAGE_K_READ | \
+/* vmalloc permissions */
+#define _K_PAGE_PERMS  (_PAGE_EXECUTE | _PAGE_WRITE | _PAGE_READ | \
                        _PAGE_GLOBAL | _PAGE_PRESENT)
 
 #ifdef CONFIG_ARC_CACHE_PAGES
  */
 #define ___DEF (_PAGE_PRESENT | _PAGE_DEF_CACHEABLE)
 
-#define _PAGE_READ     (_PAGE_U_READ    | _PAGE_K_READ)
-#define _PAGE_WRITE    (_PAGE_U_WRITE   | _PAGE_K_WRITE)
-#define _PAGE_EXECUTE  (_PAGE_U_EXECUTE | _PAGE_K_EXECUTE)
-
 /* Set of bits not changed in pte_modify */
 #define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_MODIFIED)
 
 
 #define PAGE_SHARED    PAGE_U_W_R
 
-/* While kernel runs out of unstrslated space, vmalloc/modules use a chunk of
- * kernel vaddr space - visible in all addr spaces, but kernel mode only
+/* While kernel runs out of unstranslated space, vmalloc/modules use a chunk of
+ * user vaddr space - visible in all addr spaces, but kernel mode only
  * Thus Global, all-kernel-access, no-user-access, cached
  */
 #define PAGE_KERNEL          __pgprot(_K_PAGE_PERMS | _PAGE_DEF_CACHEABLE)
 #define PAGE_KERNEL_NO_CACHE __pgprot(_K_PAGE_PERMS)
 
 /* Masks for actual TLB "PD"s */
-#define PTE_BITS_IN_PD0        (_PAGE_GLOBAL | _PAGE_PRESENT)
-#define PTE_BITS_IN_PD1        (PAGE_MASK | _PAGE_CACHEABLE | \
-                        _PAGE_U_EXECUTE | _PAGE_U_WRITE | _PAGE_U_READ | \
-                        _PAGE_K_EXECUTE | _PAGE_K_WRITE | _PAGE_K_READ)
+#define PTE_BITS_IN_PD0                (_PAGE_GLOBAL | _PAGE_PRESENT)
+#define PTE_BITS_RWX           (_PAGE_EXECUTE | _PAGE_WRITE | _PAGE_READ)
+#define PTE_BITS_NON_RWX_IN_PD1        (PAGE_MASK | _PAGE_CACHEABLE)
 
 /**************************************************************************
  * Mapping of vm_flags (Generic VM) to PTE flags (arch specific)
index c9938e7a7dbd3b596fc3c0021d8ff57548719402..1bfeec2c0558c2f6f91142105bee0c6ff70c7a75 100644 (file)
@@ -20,27 +20,17 @@ struct pt_regs {
 
        /* Real registers */
        long bta;       /* bta_l1, bta_l2, erbta */
-       long lp_start;
-       long lp_end;
-       long lp_count;
+
+       long lp_start, lp_end, lp_count;
+
        long status32;  /* status32_l1, status32_l2, erstatus */
        long ret;       /* ilink1, ilink2 or eret */
        long blink;
        long fp;
        long r26;       /* gp */
-       long r12;
-       long r11;
-       long r10;
-       long r9;
-       long r8;
-       long r7;
-       long r6;
-       long r5;
-       long r4;
-       long r3;
-       long r2;
-       long r1;
-       long r0;
+
+       long r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r1, r0;
+
        long sp;        /* user/kernel sp depending on where we came from  */
        long orig_r0;
 
@@ -70,19 +60,7 @@ struct pt_regs {
 /* Callee saved registers - need to be saved only when you are scheduled out */
 
 struct callee_regs {
-       long r25;
-       long r24;
-       long r23;
-       long r22;
-       long r21;
-       long r20;
-       long r19;
-       long r18;
-       long r17;
-       long r16;
-       long r15;
-       long r14;
-       long r13;
+       long r25, r24, r23, r22, r21, r20, r19, r18, r17, r16, r15, r14, r13;
 };
 
 #define instruction_pointer(regs)      ((regs)->ret)
index b2f9bc7f68c8cb13ba73a368a321ffc2ece31c05..71c7b2e4b8745002083e71fd19ae28305d62972e 100644 (file)
@@ -18,11 +18,18 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end);
 void local_flush_tlb_range(struct vm_area_struct *vma,
                           unsigned long start, unsigned long end);
 
-/* XXX: Revisit for SMP */
+#ifndef CONFIG_SMP
 #define flush_tlb_range(vma, s, e)     local_flush_tlb_range(vma, s, e)
 #define flush_tlb_page(vma, page)      local_flush_tlb_page(vma, page)
 #define flush_tlb_kernel_range(s, e)   local_flush_tlb_kernel_range(s, e)
 #define flush_tlb_all()                        local_flush_tlb_all()
 #define flush_tlb_mm(mm)               local_flush_tlb_mm(mm)
-
+#else
+extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
+                                                        unsigned long end);
+extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
+extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
+extern void flush_tlb_all(void);
+extern void flush_tlb_mm(struct mm_struct *mm);
+#endif /* CONFIG_SMP */
 #endif
diff --git a/arch/arc/kernel/.gitignore b/arch/arc/kernel/.gitignore
new file mode 100644 (file)
index 0000000..c5f676c
--- /dev/null
@@ -0,0 +1 @@
+vmlinux.lds
index 1d7165156e1708ee6a24391ed9218de330603ccf..b908dde8a331c26a00a4912309af78cf643fc05b 100644 (file)
@@ -267,12 +267,7 @@ ARC_EXIT handle_interrupt_level1
 
 ARC_ENTRY instr_service
 
-       EXCPN_PROLOG_FREEUP_REG r9
-
-       lr  r9, [erstatus]
-
-       SWITCH_TO_KERNEL_STK
-       SAVE_ALL_SYS
+       EXCEPTION_PROLOGUE
 
        lr  r0, [efa]
        mov r1, sp
@@ -289,15 +284,13 @@ ARC_EXIT instr_service
 
 ARC_ENTRY mem_service
 
-       EXCPN_PROLOG_FREEUP_REG r9
-
-       lr  r9, [erstatus]
-
-       SWITCH_TO_KERNEL_STK
-       SAVE_ALL_SYS
+       EXCEPTION_PROLOGUE
 
        lr  r0, [efa]
        mov r1, sp
+
+       FAKE_RET_FROM_EXCPN r9
+
        bl  do_memory_error
        b   ret_from_exception
 ARC_EXIT mem_service
@@ -308,11 +301,7 @@ ARC_EXIT mem_service
 
 ARC_ENTRY EV_MachineCheck
 
-       EXCPN_PROLOG_FREEUP_REG r9
-       lr  r9, [erstatus]
-
-       SWITCH_TO_KERNEL_STK
-       SAVE_ALL_SYS
+       EXCEPTION_PROLOGUE
 
        lr  r2, [ecr]
        lr  r0, [efa]
@@ -342,13 +331,7 @@ ARC_EXIT EV_MachineCheck
 
 ARC_ENTRY EV_TLBProtV
 
-       EXCPN_PROLOG_FREEUP_REG r9
-
-       ;Which mode (user/kernel) was the system in when Exception occured
-       lr  r9, [erstatus]
-
-       SWITCH_TO_KERNEL_STK
-       SAVE_ALL_SYS
+       EXCEPTION_PROLOGUE
 
        ;---------(3) Save some more regs-----------------
        ;  vineetg: Mar 6th: Random Seg Fault issue #1
@@ -406,12 +389,7 @@ ARC_EXIT EV_TLBProtV
 ; ---------------------------------------------
 ARC_ENTRY EV_PrivilegeV
 
-       EXCPN_PROLOG_FREEUP_REG r9
-
-       lr  r9, [erstatus]
-
-       SWITCH_TO_KERNEL_STK
-       SAVE_ALL_SYS
+       EXCEPTION_PROLOGUE
 
        lr  r0, [efa]
        mov r1, sp
@@ -427,14 +405,13 @@ ARC_EXIT EV_PrivilegeV
 ; ---------------------------------------------
 ARC_ENTRY EV_Extension
 
-       EXCPN_PROLOG_FREEUP_REG r9
-       lr  r9, [erstatus]
-
-       SWITCH_TO_KERNEL_STK
-       SAVE_ALL_SYS
+       EXCEPTION_PROLOGUE
 
        lr  r0, [efa]
        mov r1, sp
+
+       FAKE_RET_FROM_EXCPN r9
+
        bl  do_extension_fault
        b   ret_from_exception
 ARC_EXIT EV_Extension
@@ -526,14 +503,7 @@ trap_with_param:
 
 ARC_ENTRY EV_Trap
 
-       ; Need at least 1 reg to code the early exception prolog
-       EXCPN_PROLOG_FREEUP_REG r9
-
-       ;Which mode (user/kernel) was the system in when intr occured
-       lr  r9, [erstatus]
-
-       SWITCH_TO_KERNEL_STK
-       SAVE_ALL_SYS
+       EXCEPTION_PROLOGUE
 
        ;------- (4) What caused the Trap --------------
        lr     r12, [ecr]
@@ -642,6 +612,9 @@ resume_kernel_mode:
 
 #ifdef CONFIG_PREEMPT
 
+       ; This is a must for preempt_schedule_irq()
+       IRQ_DISABLE     r9
+
        ; Can't preempt if preemption disabled
        GET_CURR_THR_INFO_FROM_SP   r10
        ld  r8, [r10, THREAD_INFO_PREEMPT_COUNT]
@@ -651,8 +624,6 @@ resume_kernel_mode:
        ld  r9, [r10, THREAD_INFO_FLAGS]
        bbit0  r9, TIF_NEED_RESCHED, restore_regs
 
-       IRQ_DISABLE     r9
-
        ; Invoke PREEMPTION
        bl      preempt_schedule_irq
 
@@ -665,12 +636,11 @@ resume_kernel_mode:
 ;
 ; Restore the saved sys context (common exit-path for EXCPN/IRQ/Trap)
 ; IRQ shd definitely not happen between now and rtie
+; All 2 entry points to here already disable interrupts
 
 restore_regs :
 
-       ; Disable Interrupts while restoring reg-file back
-       ; XXX can this be optimised out
-       IRQ_DISABLE_SAVE    r9, r10     ;@r10 has prisitine (pre-disable) copy
+       lr      r10, [status32]
 
        ; Restore REG File. In case multiple Events outstanding,
        ; use the same priorty as rtie: EXCPN, L2 IRQ, L1 IRQ, None
index bca3052c956dab7edc2c5ccffba613f7a1d5cd39..482a42bdc051344c6b46170b6a9f59458540c742 100644 (file)
@@ -128,6 +128,7 @@ void start_kernel_secondary(void)
        atomic_inc(&mm->mm_users);
        atomic_inc(&mm->mm_count);
        current->active_mm = mm;
+       cpumask_set_cpu(cpu, mm_cpumask(mm));
 
        notify_cpu_starting(cpu);
        set_cpu_online(cpu, true);
index ac95cc239c1e47d3d2f5a133b1d66936c6af0b91..618561270518002eaf4b88339f42012980892f1a 100644 (file)
@@ -8,3 +8,4 @@
 
 obj-y  := extable.o ioremap.o dma.o fault.o init.o
 obj-y  += tlb.o tlbex.o cache_arc700.o mmap.o
+obj-$(CONFIG_SMP)              += tlbflush.o
index 7957dc4e4d4a4c8acee3fe521d0ecf8bb939c39c..8fed015a711617a4b20e368e3ba6ea7ae703e64f 100644 (file)
@@ -52,6 +52,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/bug.h>
 #include <asm/arcregs.h>
 #include <asm/setup.h>
 #include <asm/mmu_context.h>
 
 
 /* A copy of the ASID from the PID reg is kept in asid_cache */
-int asid_cache = FIRST_ASID;
-
-/* ASID to mm struct mapping. We have one extra entry corresponding to
- * NO_ASID to save us a compare when clearing the mm entry for old asid
- * see get_new_mmu_context (asm-arc/mmu_context.h)
- */
-struct mm_struct *asid_mm_map[NUM_ASID + 1];
+DEFINE_PER_CPU(unsigned int, asid_cache) = MM_CTXT_FIRST_CYCLE;
 
 /*
  * Utility Routine to erase a J-TLB entry
- * The procedure is to look it up in the MMU. If found, ERASE it by
- *  issuing a TlbWrite CMD with PD0 = PD1 = 0
+ * Caller needs to setup Index Reg (manually or via getIndex)
  */
-
-static void __tlb_entry_erase(void)
+static inline void __tlb_entry_erase(void)
 {
        write_aux_reg(ARC_REG_TLBPD1, 0);
        write_aux_reg(ARC_REG_TLBPD0, 0);
        write_aux_reg(ARC_REG_TLBCOMMAND, TLBWrite);
 }
 
-static void tlb_entry_erase(unsigned int vaddr_n_asid)
+static inline unsigned int tlb_entry_lkup(unsigned long vaddr_n_asid)
 {
        unsigned int idx;
 
-       /* Locate the TLB entry for this vaddr + ASID */
        write_aux_reg(ARC_REG_TLBPD0, vaddr_n_asid);
+
        write_aux_reg(ARC_REG_TLBCOMMAND, TLBProbe);
        idx = read_aux_reg(ARC_REG_TLBINDEX);
 
+       return idx;
+}
+
+static void tlb_entry_erase(unsigned int vaddr_n_asid)
+{
+       unsigned int idx;
+
+       /* Locate the TLB entry for this vaddr + ASID */
+       idx = tlb_entry_lkup(vaddr_n_asid);
+
        /* No error means entry found, zero it out */
        if (likely(!(idx & TLB_LKUP_ERR))) {
                __tlb_entry_erase();
-       } else {                /* Some sort of Error */
-
+       } else {
                /* Duplicate entry error */
-               if (idx & 0x1) {
-                       /* TODO we need to handle this case too */
-                       pr_emerg("unhandled Duplicate flush for %x\n",
-                              vaddr_n_asid);
-               }
-               /* else entry not found so nothing to do */
+               WARN(idx == TLB_DUP_ERR, "Probe returned Dup PD for %x\n",
+                                          vaddr_n_asid);
        }
 }
 
@@ -159,7 +157,7 @@ static void utlb_invalidate(void)
 {
 #if (CONFIG_ARC_MMU_VER >= 2)
 
-#if (CONFIG_ARC_MMU_VER < 3)
+#if (CONFIG_ARC_MMU_VER == 2)
        /* MMU v2 introduced the uTLB Flush command.
         * There was however an obscure hardware bug, where uTLB flush would
         * fail when a prior probe for J-TLB (both totally unrelated) would
@@ -182,6 +180,37 @@ static void utlb_invalidate(void)
 
 }
 
+static void tlb_entry_insert(unsigned int pd0, unsigned int pd1)
+{
+       unsigned int idx;
+
+       /*
+        * First verify if entry for this vaddr+ASID already exists
+        * This also sets up PD0 (vaddr, ASID..) for final commit
+        */
+       idx = tlb_entry_lkup(pd0);
+
+       /*
+        * If Not already present get a free slot from MMU.
+        * Otherwise, Probe would have located the entry and set INDEX Reg
+        * with existing location. This will cause Write CMD to over-write
+        * existing entry with new PD0 and PD1
+        */
+       if (likely(idx & TLB_LKUP_ERR))
+               write_aux_reg(ARC_REG_TLBCOMMAND, TLBGetIndex);
+
+       /* setup the other half of TLB entry (pfn, rwx..) */
+       write_aux_reg(ARC_REG_TLBPD1, pd1);
+
+       /*
+        * Commit the Entry to MMU
+        * It doesnt sound safe to use the TLBWriteNI cmd here
+        * which doesn't flush uTLBs. I'd rather be safe than sorry.
+        */
+       write_aux_reg(ARC_REG_TLBCOMMAND, TLBWrite);
+}
+
+
 /*
  * Un-conditionally (without lookup) erase the entire MMU contents
  */
@@ -224,13 +253,14 @@ noinline void local_flush_tlb_mm(struct mm_struct *mm)
                return;
 
        /*
-        * Workaround for Android weirdism:
-        * A binder VMA could end up in a task such that vma->mm != tsk->mm
-        * old code would cause h/w - s/w ASID to get out of sync
+        * - Move to a new ASID, but only if the mm is still wired in
+        *   (Android Binders ended up calling this for vma->mm != tsk->mm,
+        *    causing h/w - s/w ASID to get out of sync)
+        * - Also get_new_mmu_context() new implementation allocates a new
+        *   ASID only if it is not allocated already - so unallocate first
         */
-       if (current->mm != mm)
-               destroy_context(mm);
-       else
+       destroy_context(mm);
+       if (current->mm == mm)
                get_new_mmu_context(mm);
 }
 
@@ -245,8 +275,8 @@ noinline void local_flush_tlb_mm(struct mm_struct *mm)
 void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
                           unsigned long end)
 {
+       const unsigned int cpu = smp_processor_id();
        unsigned long flags;
-       unsigned int asid;
 
        /* If range @start to @end is more than 32 TLB entries deep,
         * its better to move to a new ASID rather than searching for
@@ -268,11 +298,10 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
        start &= PAGE_MASK;
 
        local_irq_save(flags);
-       asid = vma->vm_mm->context.asid;
 
-       if (asid != NO_ASID) {
+       if (asid_mm(vma->vm_mm, cpu) != MM_CTXT_NO_ASID) {
                while (start < end) {
-                       tlb_entry_erase(start | (asid & 0xff));
+                       tlb_entry_erase(start | hw_pid(vma->vm_mm, cpu));
                        start += PAGE_SIZE;
                }
        }
@@ -319,6 +348,7 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
 
 void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
 {
+       const unsigned int cpu = smp_processor_id();
        unsigned long flags;
 
        /* Note that it is critical that interrupts are DISABLED between
@@ -326,9 +356,8 @@ void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
         */
        local_irq_save(flags);
 
-       if (vma->vm_mm->context.asid != NO_ASID) {
-               tlb_entry_erase((page & PAGE_MASK) |
-                               (vma->vm_mm->context.asid & 0xff));
+       if (asid_mm(vma->vm_mm, cpu) != MM_CTXT_NO_ASID) {
+               tlb_entry_erase((page & PAGE_MASK) | hw_pid(vma->vm_mm, cpu));
                utlb_invalidate();
        }
 
@@ -341,8 +370,8 @@ void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
 void create_tlb(struct vm_area_struct *vma, unsigned long address, pte_t *ptep)
 {
        unsigned long flags;
-       unsigned int idx, asid_or_sasid;
-       unsigned long pd0_flags;
+       unsigned int asid_or_sasid, rwx;
+       unsigned long pd0, pd1;
 
        /*
         * create_tlb() assumes that current->mm == vma->mm, since
@@ -374,47 +403,30 @@ void create_tlb(struct vm_area_struct *vma, unsigned long address, pte_t *ptep)
 
        local_irq_save(flags);
 
-       tlb_paranoid_check(vma->vm_mm->context.asid, address);
+       tlb_paranoid_check(hw_pid(vma->vm_mm), address);
 
        address &= PAGE_MASK;
 
        /* update this PTE credentials */
        pte_val(*ptep) |= (_PAGE_PRESENT | _PAGE_ACCESSED);
 
-       /* Create HW TLB entry Flags (in PD0) from PTE Flags */
-#if (CONFIG_ARC_MMU_VER <= 2)
-       pd0_flags = ((pte_val(*ptep) & PTE_BITS_IN_PD0) >> 1);
-#else
-       pd0_flags = ((pte_val(*ptep) & PTE_BITS_IN_PD0));
-#endif
+       /* Create HW TLB(PD0,PD1) from PTE  */
 
        /* ASID for this task */
        asid_or_sasid = read_aux_reg(ARC_REG_PID) & 0xff;
 
-       write_aux_reg(ARC_REG_TLBPD0, address | pd0_flags | asid_or_sasid);
+       pd0 = address | asid_or_sasid | (pte_val(*ptep) & PTE_BITS_IN_PD0);
 
-       /* Load remaining info in PD1 (Page Frame Addr and Kx/Kw/Kr Flags) */
-       write_aux_reg(ARC_REG_TLBPD1, (pte_val(*ptep) & PTE_BITS_IN_PD1));
+       rwx = pte_val(*ptep) & PTE_BITS_RWX;
 
-       /* First verify if entry for this vaddr+ASID already exists */
-       write_aux_reg(ARC_REG_TLBCOMMAND, TLBProbe);
-       idx = read_aux_reg(ARC_REG_TLBINDEX);
+       if (pte_val(*ptep) & _PAGE_GLOBAL)
+               rwx <<= 3;              /* r w x => Kr Kw Kx 0 0 0 */
+       else
+               rwx |= (rwx << 3);      /* r w x => Kr Kw Kx Ur Uw Ux */
 
-       /*
-        * If Not already present get a free slot from MMU.
-        * Otherwise, Probe would have located the entry and set INDEX Reg
-        * with existing location. This will cause Write CMD to over-write
-        * existing entry with new PD0 and PD1
-        */
-       if (likely(idx & TLB_LKUP_ERR))
-               write_aux_reg(ARC_REG_TLBCOMMAND, TLBGetIndex);
+       pd1 = rwx | (pte_val(*ptep) & PTE_BITS_NON_RWX_IN_PD1);
 
-       /*
-        * Commit the Entry to MMU
-        * It doesnt sound safe to use the TLBWriteNI cmd here
-        * which doesn't flush uTLBs. I'd rather be safe than sorry.
-        */
-       write_aux_reg(ARC_REG_TLBCOMMAND, TLBWrite);
+       tlb_entry_insert(pd0, pd1);
 
        local_irq_restore(flags);
 }
@@ -553,11 +565,6 @@ void arc_mmu_init(void)
        if (mmu->pg_sz != PAGE_SIZE)
                panic("MMU pg size != PAGE_SIZE (%luk)\n", TO_KB(PAGE_SIZE));
 
-       /*
-        * ASID mgmt data structures are compile time init
-        *  asid_cache = FIRST_ASID and asid_mm_map[] all zeroes
-        */
-
        local_flush_tlb_all();
 
        /* Enable the MMU */
@@ -674,7 +681,7 @@ void do_tlb_overlap_fault(unsigned long cause, unsigned long address,
 void print_asid_mismatch(int is_fast_path)
 {
        int pid_sw, pid_hw;
-       pid_sw = current->active_mm->context.asid;
+       pid_sw = hw_pid(current->active_mm, smp_processor_id());
        pid_hw = read_aux_reg(ARC_REG_PID) & 0xff;
 
        pr_emerg("ASID Mismatch in %s Path Handler: sw-pid=0x%x hw-pid=0x%x\n",
@@ -689,7 +696,8 @@ void tlb_paranoid_check(unsigned int pid_sw, unsigned long addr)
 
        pid_hw = read_aux_reg(ARC_REG_PID) & 0xff;
 
-       if (addr < 0x70000000 && ((pid_hw != pid_sw) || (pid_sw == NO_ASID)))
+       if (addr < 0x70000000 && ((pid_hw != pid_sw) ||
+           (pid_sw == MM_CTXT_NO_ASID)))
                print_asid_mismatch(0);
 }
 #endif
index 5c5bb23001b071b02a0ea33dba44d72211656d28..50e83ca96b96a6f0f1ef3f068b21e33a9bcb4b0c 100644 (file)
 #include <asm/arcregs.h>
 #include <asm/cache.h>
 #include <asm/processor.h>
-#if (CONFIG_ARC_MMU_VER == 1)
 #include <asm/tlb-mmu1.h>
-#endif
 
-;--------------------------------------------------------------------------
-; scratch memory to save the registers (r0-r3) used to code TLB refill Handler
-; For details refer to comments before TLBMISS_FREEUP_REGS below
+;-----------------------------------------------------------------
+; ARC700 Exception Handling doesn't auto-switch stack and it only provides
+; ONE scratch AUX reg "ARC_REG_SCRATCH_DATA0"
+;
+; For Non-SMP, the scratch AUX reg is repurposed to cache task PGD, so a
+; "global" is used to free-up FIRST core reg to be able to code the rest of
+; exception prologue (IRQ auto-disabled on Exceptions, so it's IRQ-safe).
+; Since the Fast Path TLB Miss handler is coded with 4 regs, the remaining 3
+; need to be saved as well by extending the "global" to be 4 words. Hence
+;      ".size   ex_saved_reg1, 16"
+; [All of this dance is to avoid stack switching for each TLB Miss, since we
+; only need to save only a handful of regs, as opposed to complete reg file]
+;
+; For ARC700 SMP, the "global" obviously can't be used for free up the FIRST
+; core reg as it will not be SMP safe.
+; Thus scratch AUX reg is used (and no longer used to cache task PGD).
+; To save the rest of 3 regs - per cpu, the global is made "per-cpu".
+; Epilogue thus has to locate the "per-cpu" storage for regs.
+; To avoid cache line bouncing the per-cpu global is aligned/sized per
+; L1_CACHE_SHIFT, despite fundamentally needing to be 12 bytes only. Hence
+;      ".size   ex_saved_reg1, (CONFIG_NR_CPUS << L1_CACHE_SHIFT)"
+
+; As simple as that....
 ;--------------------------------------------------------------------------
 
+; scratch memory to save [r0-r3] used to code TLB refill Handler
 ARCFP_DATA ex_saved_reg1
-       .align 1 << L1_CACHE_SHIFT      ; IMP: Must be Cache Line aligned
+       .align 1 << L1_CACHE_SHIFT
        .type   ex_saved_reg1, @object
 #ifdef CONFIG_SMP
        .size   ex_saved_reg1, (CONFIG_NR_CPUS << L1_CACHE_SHIFT)
@@ -66,6 +85,44 @@ ex_saved_reg1:
        .zero 16
 #endif
 
+.macro TLBMISS_FREEUP_REGS
+#ifdef CONFIG_SMP
+       sr  r0, [ARC_REG_SCRATCH_DATA0] ; freeup r0 to code with
+       GET_CPU_ID  r0                  ; get to per cpu scratch mem,
+       lsl r0, r0, L1_CACHE_SHIFT      ; cache line wide per cpu
+       add r0, @ex_saved_reg1, r0
+#else
+       st    r0, [@ex_saved_reg1]
+       mov_s r0, @ex_saved_reg1
+#endif
+       st_s  r1, [r0, 4]
+       st_s  r2, [r0, 8]
+       st_s  r3, [r0, 12]
+
+       ; VERIFY if the ASID in MMU-PID Reg is same as
+       ; one in Linux data structures
+
+       DBG_ASID_MISMATCH
+.endm
+
+.macro TLBMISS_RESTORE_REGS
+#ifdef CONFIG_SMP
+       GET_CPU_ID  r0                  ; get to per cpu scratch mem
+       lsl r0, r0, L1_CACHE_SHIFT      ; each is cache line wide
+       add r0, @ex_saved_reg1, r0
+       ld_s  r3, [r0,12]
+       ld_s  r2, [r0, 8]
+       ld_s  r1, [r0, 4]
+       lr    r0, [ARC_REG_SCRATCH_DATA0]
+#else
+       mov_s r0, @ex_saved_reg1
+       ld_s  r3, [r0,12]
+       ld_s  r2, [r0, 8]
+       ld_s  r1, [r0, 4]
+       ld_s  r0, [r0]
+#endif
+.endm
+
 ;============================================================================
 ;  Troubleshooting Stuff
 ;============================================================================
@@ -161,13 +218,17 @@ ex_saved_reg1:
 ; IN: r0 = PTE, r1 = ptr to PTE
 
 .macro CONV_PTE_TO_TLB
-       and r3, r0, PTE_BITS_IN_PD1 ; Extract permission flags+PFN from PTE
-       sr  r3, [ARC_REG_TLBPD1]    ; these go in PD1
+       and    r3, r0, PTE_BITS_RWX     ;       r w x
+       lsl    r2, r3, 3                ; r w x 0 0 0
+       and.f  0,  r0, _PAGE_GLOBAL
+       or.z   r2, r2, r3               ; r w x r w x
+
+       and r3, r0, PTE_BITS_NON_RWX_IN_PD1 ; Extract PFN+cache bits from PTE
+       or  r3, r3, r2
+
+       sr  r3, [ARC_REG_TLBPD1]        ; these go in PD1
 
        and r2, r0, PTE_BITS_IN_PD0 ; Extract other PTE flags: (V)alid, (G)lb
-#if (CONFIG_ARC_MMU_VER <= 2)   /* Neednot be done with v3 onwards */
-       lsr r2, r2                  ; shift PTE flags to match layout in PD0
-#endif
 
        lr  r3,[ARC_REG_TLBPD0]     ; MMU prepares PD0 with vaddr and asid
 
@@ -191,68 +252,6 @@ ex_saved_reg1:
 #endif
 .endm
 
-;-----------------------------------------------------------------
-; ARC700 Exception Handling doesn't auto-switch stack and it only provides
-; ONE scratch AUX reg "ARC_REG_SCRATCH_DATA0"
-;
-; For Non-SMP, the scratch AUX reg is repurposed to cache task PGD, so a
-; "global" is used to free-up FIRST core reg to be able to code the rest of
-; exception prologue (IRQ auto-disabled on Exceptions, so it's IRQ-safe).
-; Since the Fast Path TLB Miss handler is coded with 4 regs, the remaining 3
-; need to be saved as well by extending the "global" to be 4 words. Hence
-;      ".size   ex_saved_reg1, 16"
-; [All of this dance is to avoid stack switching for each TLB Miss, since we
-; only need to save only a handful of regs, as opposed to complete reg file]
-;
-; For ARC700 SMP, the "global" obviously can't be used for free up the FIRST
-; core reg as it will not be SMP safe.
-; Thus scratch AUX reg is used (and no longer used to cache task PGD).
-; To save the rest of 3 regs - per cpu, the global is made "per-cpu".
-; Epilogue thus has to locate the "per-cpu" storage for regs.
-; To avoid cache line bouncing the per-cpu global is aligned/sized per
-; L1_CACHE_SHIFT, despite fundamentally needing to be 12 bytes only. Hence
-;      ".size   ex_saved_reg1, (CONFIG_NR_CPUS << L1_CACHE_SHIFT)"
-
-; As simple as that....
-
-.macro TLBMISS_FREEUP_REGS
-#ifdef CONFIG_SMP
-       sr  r0, [ARC_REG_SCRATCH_DATA0] ; freeup r0 to code with
-       GET_CPU_ID  r0                  ; get to per cpu scratch mem,
-       lsl r0, r0, L1_CACHE_SHIFT      ; cache line wide per cpu
-       add r0, @ex_saved_reg1, r0
-#else
-       st    r0, [@ex_saved_reg1]
-       mov_s r0, @ex_saved_reg1
-#endif
-       st_s  r1, [r0, 4]
-       st_s  r2, [r0, 8]
-       st_s  r3, [r0, 12]
-
-       ; VERIFY if the ASID in MMU-PID Reg is same as
-       ; one in Linux data structures
-
-       DBG_ASID_MISMATCH
-.endm
-
-;-----------------------------------------------------------------
-.macro TLBMISS_RESTORE_REGS
-#ifdef CONFIG_SMP
-       GET_CPU_ID  r0                  ; get to per cpu scratch mem
-       lsl r0, r0, L1_CACHE_SHIFT      ; each is cache line wide
-       add r0, @ex_saved_reg1, r0
-       ld_s  r3, [r0,12]
-       ld_s  r2, [r0, 8]
-       ld_s  r1, [r0, 4]
-       lr    r0, [ARC_REG_SCRATCH_DATA0]
-#else
-       mov_s r0, @ex_saved_reg1
-       ld_s  r3, [r0,12]
-       ld_s  r2, [r0, 8]
-       ld_s  r1, [r0, 4]
-       ld_s  r0, [r0]
-#endif
-.endm
 
 ARCFP_CODE     ;Fast Path Code, candidate for ICCM
 
@@ -277,8 +276,8 @@ ARC_ENTRY EV_TLBMissI
        ;----------------------------------------------------------------
        ; VERIFY_PTE: Check if PTE permissions approp for executing code
        cmp_s   r2, VMALLOC_START
-       mov.lo  r2, (_PAGE_PRESENT | _PAGE_U_EXECUTE)
-       mov.hs  r2, (_PAGE_PRESENT | _PAGE_K_EXECUTE)
+       mov_s   r2, (_PAGE_PRESENT | _PAGE_EXECUTE)
+       or.hs   r2, r2, _PAGE_GLOBAL
 
        and     r3, r0, r2  ; Mask out NON Flag bits from PTE
        xor.f   r3, r3, r2  ; check ( ( pte & flags_test ) == flags_test )
@@ -317,26 +316,21 @@ ARC_ENTRY EV_TLBMissD
        ;----------------------------------------------------------------
        ; VERIFY_PTE: Chk if PTE permissions approp for data access (R/W/R+W)
 
-       mov_s   r2, 0
+       cmp_s   r2, VMALLOC_START
+       mov_s   r2, _PAGE_PRESENT       ; common bit for K/U PTE
+       or.hs   r2, r2, _PAGE_GLOBAL    ; kernel PTE only
+
+       ; Linux PTE [RWX] bits are semantically overloaded:
+       ; -If PAGE_GLOBAL set, they refer to kernel-only flags (vmalloc)
+       ; -Otherwise they are user-mode permissions, and those are exactly
+       ;  same for kernel mode as well (e.g. copy_(to|from)_user)
+
        lr      r3, [ecr]
        btst_s  r3, ECR_C_BIT_DTLB_LD_MISS      ; Read Access
-       or.nz   r2, r2, _PAGE_U_READ            ; chk for Read flag in PTE
+       or.nz   r2, r2, _PAGE_READ              ; chk for Read flag in PTE
        btst_s  r3, ECR_C_BIT_DTLB_ST_MISS      ; Write Access
-       or.nz   r2, r2, _PAGE_U_WRITE           ; chk for Write flag in PTE
-       ; Above laddering takes care of XCHG access
-       ;   which is both Read and Write
-
-       ; If kernel mode access, ; make _PAGE_xx flags as _PAGE_K_xx
-       ; For copy_(to|from)_user, despite exception taken in kernel mode,
-       ; this code is not hit, because EFA would still be the user mode
-       ; address (EFA < 0x6000_0000).
-       ; This code is for legit kernel mode faults, vmalloc specifically
-       ; (EFA: 0x7000_0000 to 0x7FFF_FFFF)
-
-       lr      r3, [efa]
-       cmp     r3, VMALLOC_START - 1   ; If kernel mode access
-       asl.hi  r2, r2, 3               ; make _PAGE_xx flags as _PAGE_K_xx
-       or      r2, r2, _PAGE_PRESENT   ; Common flag for K/U mode
+       or.nz   r2, r2, _PAGE_WRITE             ; chk for Write flag in PTE
+       ; Above laddering takes care of XCHG access (both R and W)
 
        ; By now, r2 setup with all the Flags we need to check in PTE
        and     r3, r0, r2              ; Mask out NON Flag bits from PTE
@@ -371,13 +365,7 @@ do_slow_path_pf:
 
        ; Slow path TLB Miss handled as a regular ARC Exception
        ; (stack switching / save the complete reg-file).
-       ; That requires freeing up r9
-       EXCPN_PROLOG_FREEUP_REG r9
-
-       lr  r9, [erstatus]
-
-       SWITCH_TO_KERNEL_STK
-       SAVE_ALL_SYS
+       EXCEPTION_PROLOGUE
 
        ; ------- setup args for Linux Page fault Hanlder ---------
        mov_s r0, sp
diff --git a/arch/arc/mm/tlbflush.c b/arch/arc/mm/tlbflush.c
new file mode 100644 (file)
index 0000000..a0abe48
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/sched.h>
+#include <asm/tlbflush.h>
+
+struct tlb_args {
+       struct vm_area_struct *ta_vma;
+       unsigned long ta_start;
+       unsigned long ta_end;
+};
+
+static inline void ipi_flush_tlb_all(void *ignored)
+{
+       local_flush_tlb_all();
+}
+
+static inline void ipi_flush_tlb_mm(void *arg)
+{
+       struct mm_struct *mm = (struct mm_struct *)arg;
+
+       local_flush_tlb_mm(mm);
+}
+
+static inline void ipi_flush_tlb_page(void *arg)
+{
+       struct tlb_args *ta = (struct tlb_args *)arg;
+
+       local_flush_tlb_page(ta->ta_vma, ta->ta_start);
+}
+
+static inline void ipi_flush_tlb_range(void *arg)
+{
+       struct tlb_args *ta = (struct tlb_args *)arg;
+
+       local_flush_tlb_range(ta->ta_vma, ta->ta_start, ta->ta_end);
+}
+
+static inline void ipi_flush_tlb_kernel_range(void *arg)
+{
+       struct tlb_args *ta = (struct tlb_args *)arg;
+
+       local_flush_tlb_kernel_range(ta->ta_start, ta->ta_end);
+}
+
+void flush_tlb_all(void)
+{
+       on_each_cpu(ipi_flush_tlb_all, NULL, 1);
+}
+
+void flush_tlb_mm(struct mm_struct *mm)
+{
+       on_each_cpu_mask(mm_cpumask(mm), ipi_flush_tlb_mm, mm, 1);
+}
+
+void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
+{
+       struct tlb_args ta;
+       ta.ta_vma = vma;
+       ta.ta_start = uaddr;
+       on_each_cpu_mask(mm_cpumask(vma->vm_mm), ipi_flush_tlb_page, &ta, 1);
+}
+
+void flush_tlb_range(struct vm_area_struct *vma,
+                     unsigned long start, unsigned long end)
+{
+       struct tlb_args ta;
+       ta.ta_vma = vma;
+       ta.ta_start = start;
+       ta.ta_end = end;
+       on_each_cpu_mask(mm_cpumask(vma->vm_mm), ipi_flush_tlb_range, &ta, 1);
+}
+
+void flush_tlb_kernel_range(unsigned long start, unsigned long end)
+{
+       struct tlb_args ta;
+       ta.ta_start = start;
+       ta.ta_end = end;
+       on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1);
+}
index 37c0f4e978d48c8e7928e0a9931b77b6fd4b6be5..5323393617e53de0ade4bff29871064d607e511b 100644 (file)
@@ -20,7 +20,6 @@ config ARM
        select GENERIC_STRNCPY_FROM_USER
        select GENERIC_STRNLEN_USER
        select HARDIRQS_SW_RESEND
-       select HAVE_AOUT
        select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL
        select HAVE_ARCH_KGDB
        select HAVE_ARCH_SECCOMP_FILTER
@@ -1613,13 +1612,49 @@ config ARCH_NR_GPIO
 
 source kernel/Kconfig.preempt
 
-config HZ
+config HZ_FIXED
        int
        default 200 if ARCH_EBSA110 || ARCH_S3C24XX || ARCH_S5P64X0 || \
                ARCH_S5PV210 || ARCH_EXYNOS4
        default AT91_TIMER_HZ if ARCH_AT91
        default SHMOBILE_TIMER_HZ if ARCH_SHMOBILE
-       default 100
+
+choice
+       depends on !HZ_FIXED
+       prompt "Timer frequency"
+
+config HZ_100
+       bool "100 Hz"
+
+config HZ_200
+       bool "200 Hz"
+
+config HZ_250
+       bool "250 Hz"
+
+config HZ_300
+       bool "300 Hz"
+
+config HZ_500
+       bool "500 Hz"
+
+config HZ_1000
+       bool "1000 Hz"
+
+endchoice
+
+config HZ
+       int
+       default HZ_FIXED if HZ_FIXED
+       default 100 if HZ_100
+       default 200 if HZ_200
+       default 250 if HZ_250
+       default 300 if HZ_300
+       default 500 if HZ_500
+       default 1000
+
+config SCHED_HRTICK
+       def_bool HIGH_RES_TIMERS
 
 config SCHED_HRTICK
        def_bool HIGH_RES_TIMERS
@@ -1756,6 +1791,9 @@ config HAVE_ARCH_TRANSPARENT_HUGEPAGE
        def_bool y
        depends on ARM_LPAE
 
+config ARCH_WANT_GENERAL_HUGETLB
+       def_bool y
+
 source "mm/Kconfig"
 
 config FORCE_MAX_ZONEORDER
@@ -2175,6 +2213,13 @@ config NEON
          Say Y to include support code for NEON, the ARMv7 Advanced SIMD
          Extension.
 
+config KERNEL_MODE_NEON
+       bool "Support for NEON in kernel mode"
+       default n
+       depends on NEON
+       help
+         Say Y to include support for NEON in kernel mode.
+
 endmenu
 
 menu "Userspace binary formats"
index e401a766c0bdaf633f9dd14977eb231d2b2656e9..2d57da32456278118bc9a52390036a87dc8d3651 100644 (file)
@@ -92,6 +92,7 @@ choice
        config DEBUG_BCM2835
                bool "Kernel low-level debugging on BCM2835 PL011 UART"
                depends on ARCH_BCM2835
+               select DEBUG_UART_PL01X
 
        config DEBUG_CLPS711X_UART1
                bool "Kernel low-level debugging messages via UART1"
@@ -110,6 +111,7 @@ choice
        config DEBUG_CNS3XXX
                bool "Kernel Kernel low-level debugging on Cavium Networks CNS3xxx"
                depends on ARCH_CNS3XXX
+               select DEBUG_UART_PL01X
                help
                  Say Y here if you want the debug print routines to direct
                   their output to the CNS3xxx UART0.
@@ -117,6 +119,7 @@ choice
        config DEBUG_DAVINCI_DA8XX_UART1
                bool "Kernel low-level debugging on DaVinci DA8XX using UART1"
                depends on ARCH_DAVINCI_DA8XX
+               select DEBUG_UART_8250
                help
                  Say Y here if you want the debug print routines to direct
                  their output to UART1 serial port on DaVinci DA8XX devices.
@@ -124,6 +127,7 @@ choice
        config DEBUG_DAVINCI_DA8XX_UART2
                bool "Kernel low-level debugging on DaVinci DA8XX using UART2"
                depends on ARCH_DAVINCI_DA8XX
+               select DEBUG_UART_8250
                help
                  Say Y here if you want the debug print routines to direct
                  their output to UART2 serial port on DaVinci DA8XX devices.
@@ -131,6 +135,7 @@ choice
        config DEBUG_DAVINCI_DMx_UART0
                bool "Kernel low-level debugging on DaVinci DMx using UART0"
                depends on ARCH_DAVINCI_DMx
+               select DEBUG_UART_8250
                help
                  Say Y here if you want the debug print routines to direct
                  their output to UART0 serial port on DaVinci DMx devices.
@@ -138,6 +143,7 @@ choice
        config DEBUG_DAVINCI_TNETV107X_UART1
                bool "Kernel low-level debugging on DaVinci TNETV107x using UART1"
                depends on ARCH_DAVINCI_TNETV107X
+               select DEBUG_UART_8250
                help
                  Say Y here if you want the debug print routines to direct
                  their output to UART1 serial port on DaVinci TNETV107X
@@ -177,6 +183,7 @@ choice
        config DEBUG_HIGHBANK_UART
                bool "Kernel low-level debugging messages via Highbank UART"
                depends on ARCH_HIGHBANK
+               select DEBUG_UART_PL01X
                help
                  Say Y here if you want the debug print routines to direct
                  their output to the UART on Highbank based devices.
@@ -191,6 +198,7 @@ choice
        config DEBUG_IMX23_UART
                bool "i.MX23 Debug UART"
                depends on SOC_IMX23
+               select DEBUG_UART_PL01X
                help
                  Say Y here if you want kernel low-level debugging support
                  on i.MX23.
@@ -212,6 +220,7 @@ choice
        config DEBUG_IMX28_UART
                bool "i.MX28 Debug UART"
                depends on SOC_IMX28
+               select DEBUG_UART_PL01X
                help
                  Say Y here if you want kernel low-level debugging support
                  on i.MX28.
@@ -261,6 +270,7 @@ choice
        config DEBUG_KEYSTONE_UART0
                bool "Kernel low-level debugging on KEYSTONE2 using UART0"
                depends on ARCH_KEYSTONE
+               select DEBUG_UART_8250
                help
                  Say Y here if you want the debug print routines to direct
                  their output to UART0 serial port on KEYSTONE2 devices.
@@ -268,6 +278,7 @@ choice
        config DEBUG_KEYSTONE_UART1
                bool "Kernel low-level debugging on KEYSTONE2 using UART1"
                depends on ARCH_KEYSTONE
+               select DEBUG_UART_8250
                help
                  Say Y here if you want the debug print routines to direct
                  their output to UART1 serial port on KEYSTONE2 devices.
@@ -275,6 +286,7 @@ choice
        config DEBUG_MMP_UART2
                bool "Kernel low-level debugging message via MMP UART2"
                depends on ARCH_MMP
+               select DEBUG_UART_8250
                help
                  Say Y here if you want kernel low-level debugging support
                  on MMP UART2.
@@ -282,6 +294,7 @@ choice
        config DEBUG_MMP_UART3
                bool "Kernel low-level debugging message via MMP UART3"
                depends on ARCH_MMP
+               select DEBUG_UART_8250
                help
                  Say Y here if you want kernel low-level debugging support
                  on MMP UART3.
@@ -326,6 +339,7 @@ choice
        config DEBUG_MVEBU_UART
                bool "Kernel low-level debugging messages via MVEBU UART (old bootloaders)"
                depends on ARCH_MVEBU
+               select DEBUG_UART_8250
                help
                  Say Y here if you want kernel low-level debugging support
                  on MVEBU based platforms.
@@ -344,6 +358,7 @@ choice
        config DEBUG_MVEBU_UART_ALTERNATE
                bool "Kernel low-level debugging messages via MVEBU UART (new bootloaders)"
                depends on ARCH_MVEBU
+               select DEBUG_UART_8250
                help
                  Say Y here if you want kernel low-level debugging support
                  on MVEBU based platforms.
@@ -358,6 +373,7 @@ choice
        config DEBUG_NOMADIK_UART
                bool "Kernel low-level debugging messages via NOMADIK UART"
                depends on ARCH_NOMADIK
+               select DEBUG_UART_PL01X
                help
                  Say Y here if you want kernel low-level debugging support
                  on NOMADIK based platforms.
@@ -365,6 +381,7 @@ choice
        config DEBUG_NSPIRE_CLASSIC_UART
                bool "Kernel low-level debugging via TI-NSPIRE 8250 UART"
                depends on ARCH_NSPIRE
+               select DEBUG_UART_8250
                help
                  Say Y here if you want kernel low-level debugging support
                  on TI-NSPIRE classic models.
@@ -372,20 +389,82 @@ choice
        config DEBUG_NSPIRE_CX_UART
                bool "Kernel low-level debugging via TI-NSPIRE PL011 UART"
                depends on ARCH_NSPIRE
+               select DEBUG_UART_PL01X
                help
                  Say Y here if you want kernel low-level debugging support
                  on TI-NSPIRE CX models.
 
-       config DEBUG_OMAP2PLUS_UART
-               bool "Kernel low-level debugging messages via OMAP2PLUS UART"
+       config DEBUG_OMAP2UART1
+               bool "OMAP2/3/4 UART1 (omap2/3 sdp boards and some omap3 boards)"
                depends on ARCH_OMAP2PLUS
+               select DEBUG_OMAP2PLUS_UART
                help
-                 Say Y here if you want kernel low-level debugging support
-                 on OMAP2PLUS based platforms.
+                 This covers at least h4, 2430sdp, 3430sdp, 3630sdp,
+                 omap3 torpedo and 3530 lv som.
+
+       config DEBUG_OMAP2UART2
+               bool "Kernel low-level debugging messages via OMAP2/3/4 UART2"
+               depends on ARCH_OMAP2PLUS
+               select DEBUG_OMAP2PLUS_UART
+
+       config DEBUG_OMAP2UART3
+               bool "Kernel low-level debugging messages via OMAP2 UART3 (n8x0)"
+               depends on ARCH_OMAP2PLUS
+               select DEBUG_OMAP2PLUS_UART
+
+       config DEBUG_OMAP3UART3
+               bool "Kernel low-level debugging messages via OMAP3 UART3 (most omap3 boards)"
+               depends on ARCH_OMAP2PLUS
+               select DEBUG_OMAP2PLUS_UART
+               help
+                 This covers at least cm_t3x, beagle, crane, devkit8000,
+                 igep00x0, ldp, n900, n9(50), pandora, overo, touchbook,
+                 and 3517evm.
+
+       config DEBUG_OMAP4UART3
+               bool "Kernel low-level debugging messages via OMAP4/5 UART3 (omap4 blaze, panda, omap5 sevm)"
+               depends on ARCH_OMAP2PLUS
+               select DEBUG_OMAP2PLUS_UART
+
+       config DEBUG_OMAP3UART4
+               bool "Kernel low-level debugging messages via OMAP36XX UART4"
+               depends on ARCH_OMAP2PLUS
+               select DEBUG_OMAP2PLUS_UART
+
+       config DEBUG_OMAP4UART4
+               bool "Kernel low-level debugging messages via OMAP4/5 UART4"
+               depends on ARCH_OMAP2PLUS
+               select DEBUG_OMAP2PLUS_UART
+
+       config DEBUG_TI81XXUART1
+               bool "Kernel low-level debugging messages via TI81XX UART1 (ti8148evm)"
+               depends on ARCH_OMAP2PLUS
+               select DEBUG_OMAP2PLUS_UART
+
+       config DEBUG_TI81XXUART2
+               bool "Kernel low-level debugging messages via TI81XX UART2"
+               depends on ARCH_OMAP2PLUS
+               select DEBUG_OMAP2PLUS_UART
+
+       config DEBUG_TI81XXUART3
+               bool "Kernel low-level debugging messages via TI81XX UART3 (ti8168evm)"
+               depends on ARCH_OMAP2PLUS
+               select DEBUG_OMAP2PLUS_UART
+
+       config DEBUG_AM33XXUART1
+               bool "Kernel low-level debugging messages via AM33XX UART1"
+               depends on ARCH_OMAP2PLUS
+               select DEBUG_OMAP2PLUS_UART
+
+       config DEBUG_ZOOM_UART
+               bool "Kernel low-level debugging messages via Zoom2/3 UART"
+               depends on ARCH_OMAP2PLUS
+               select DEBUG_OMAP2PLUS_UART
 
        config DEBUG_PICOXCELL_UART
                depends on ARCH_PICOXCELL
                bool "Use PicoXcell UART for low-level debug"
+               select DEBUG_UART_8250
                help
                  Say Y here if you want kernel low-level debugging support
                  on PicoXcell based platforms.
@@ -393,6 +472,7 @@ choice
        config DEBUG_PXA_UART1
                depends on ARCH_PXA
                bool "Use PXA UART1 for low-level debug"
+               select DEBUG_UART_8250
                help
                  Say Y here if you want kernel low-level debugging support
                  on PXA UART1.
@@ -400,6 +480,7 @@ choice
        config DEBUG_REALVIEW_STD_PORT
                bool "RealView Default UART"
                depends on ARCH_REALVIEW
+               select DEBUG_UART_PL01X
                help
                  Say Y here if you want the debug print routines to direct
                  their output to the serial port on RealView EB, PB11MP, PBA8
@@ -408,14 +489,64 @@ choice
        config DEBUG_REALVIEW_PB1176_PORT
                bool "RealView PB1176 UART"
                depends on MACH_REALVIEW_PB1176
+               select DEBUG_UART_PL01X
                help
                  Say Y here if you want the debug print routines to direct
                  their output to the standard serial port on the RealView
                  PB1176 platform.
 
-       config DEBUG_ROCKCHIP_UART
-               bool "Kernel low-level debugging messages via Rockchip UART"
+       config DEBUG_RK29_UART0
+               bool "Kernel low-level debugging messages via Rockchip RK29 UART0"
+               depends on ARCH_ROCKCHIP
+               select DEBUG_UART_8250
+               help
+                 Say Y here if you want kernel low-level debugging support
+                 on Rockchip based platforms.
+
+       config DEBUG_RK29_UART1
+               bool "Kernel low-level debugging messages via Rockchip RK29 UART1"
+               depends on ARCH_ROCKCHIP
+               select DEBUG_UART_8250
+               help
+                 Say Y here if you want kernel low-level debugging support
+                 on Rockchip based platforms.
+
+       config DEBUG_RK29_UART2
+               bool "Kernel low-level debugging messages via Rockchip RK29 UART2"
+               depends on ARCH_ROCKCHIP
+               select DEBUG_UART_8250
+               help
+                 Say Y here if you want kernel low-level debugging support
+                 on Rockchip based platforms.
+
+       config DEBUG_RK3X_UART0
+               bool "Kernel low-level debugging messages via Rockchip RK3X UART0"
+               depends on ARCH_ROCKCHIP
+               select DEBUG_UART_8250
+               help
+                 Say Y here if you want kernel low-level debugging support
+                 on Rockchip based platforms.
+
+       config DEBUG_RK3X_UART1
+               bool "Kernel low-level debugging messages via Rockchip RK3X UART1"
+               depends on ARCH_ROCKCHIP
+               select DEBUG_UART_8250
+               help
+                 Say Y here if you want kernel low-level debugging support
+                 on Rockchip based platforms.
+
+       config DEBUG_RK3X_UART2
+               bool "Kernel low-level debugging messages via Rockchip RK3X UART2"
+               depends on ARCH_ROCKCHIP
+               select DEBUG_UART_8250
+               help
+                 Say Y here if you want kernel low-level debugging support
+                 on Rockchip based platforms.
+
+       config DEBUG_RK3X_UART3
+               bool "Kernel low-level debugging messages via Rockchip RK3X UART3"
                depends on ARCH_ROCKCHIP
+               select DEBUG_UART_8250
                help
                  Say Y here if you want kernel low-level debugging support
                  on Rockchip based platforms.
@@ -471,6 +602,7 @@ choice
        config DEBUG_SOCFPGA_UART
                depends on ARCH_SOCFPGA
                bool "Use SOCFPGA UART for low-level debug"
+               select DEBUG_UART_8250
                help
                  Say Y here if you want kernel low-level debugging support
                  on SOCFPGA based platforms.
@@ -478,6 +610,7 @@ choice
        config DEBUG_SUNXI_UART0
                bool "Kernel low-level debugging messages via sunXi UART0"
                depends on ARCH_SUNXI
+               select DEBUG_UART_8250
                help
                  Say Y here if you want kernel low-level debugging support
                  on Allwinner A1X based platforms on the UART0.
@@ -485,13 +618,59 @@ choice
        config DEBUG_SUNXI_UART1
                bool "Kernel low-level debugging messages via sunXi UART1"
                depends on ARCH_SUNXI
+               select DEBUG_UART_8250
                help
                  Say Y here if you want kernel low-level debugging support
                  on Allwinner A1X based platforms on the UART1.
 
-       config DEBUG_TEGRA_UART
+       config TEGRA_DEBUG_UART_AUTO_ODMDATA
+               bool "Kernel low-level debugging messages via Tegra UART via ODMDATA"
                depends on ARCH_TEGRA
-               bool "Use Tegra UART for low-level debug"
+               select DEBUG_TEGRA_UART
+               help
+                 Automatically determines which UART to use for low-level
+                 debug based on the ODMDATA value. This value is part of
+                 the BCT, and is written to the boot memory device using
+                 nvflash, or other flashing tool.  When bits 19:18 are 3,
+                 then bits 17:15 indicate which UART to use; 0/1/2/3/4
+                 are UART A/B/C/D/E.
+
+       config TEGRA_DEBUG_UARTA
+               bool "Kernel low-level debugging messages via Tegra UART A"
+               depends on ARCH_TEGRA
+               select DEBUG_TEGRA_UART
+               help
+                 Say Y here if you want kernel low-level debugging support
+                 on Tegra based platforms.
+
+       config TEGRA_DEBUG_UARTB
+               bool "Kernel low-level debugging messages via Tegra UART B"
+               depends on ARCH_TEGRA
+               select DEBUG_TEGRA_UART
+               help
+                 Say Y here if you want kernel low-level debugging support
+                 on Tegra based platforms.
+
+       config TEGRA_DEBUG_UARTC
+               bool "Kernel low-level debugging messages via Tegra UART C"
+               depends on ARCH_TEGRA
+               select DEBUG_TEGRA_UART
+               help
+                 Say Y here if you want kernel low-level debugging support
+                 on Tegra based platforms.
+
+       config TEGRA_DEBUG_UARTD
+               bool "Kernel low-level debugging messages via Tegra UART D"
+               depends on ARCH_TEGRA
+               select DEBUG_TEGRA_UART
+               help
+                 Say Y here if you want kernel low-level debugging support
+                 on Tegra based platforms.
+
+       config TEGRA_DEBUG_UARTE
+               bool "Kernel low-level debugging messages via Tegra UART E"
+               depends on ARCH_TEGRA
+               select DEBUG_TEGRA_UART
                help
                  Say Y here if you want kernel low-level debugging support
                  on Tegra based platforms.
@@ -510,19 +689,32 @@ choice
                  Say Y here if you want the debug print routines to direct
                  their output to the uart1 port on SiRFmarco devices.
 
-       config DEBUG_STI_UART
+       config STIH41X_DEBUG_ASC2
+               bool "Use StiH415/416 ASC2 UART for low-level debug"
                depends on ARCH_STI
-               bool "Use StiH415/416 ASC for low-level debug"
+               select DEBUG_STI_UART
                help
                  Say Y here if you want kernel low-level debugging support
-                 on StiH415/416 based platforms like B2000, B2020.
-                 It support UART2 and SBC_UART1.
+                 on STiH415/416 based platforms like b2000, which has
+                 default UART wired up to ASC2.
+
+                 If unsure, say N.
+
+       config STIH41X_DEBUG_SBC_ASC1
+               bool "Use StiH415/416 SBC ASC1 UART for low-level debug"
+               depends on ARCH_STI
+               select DEBUG_STI_UART
+               help
+                 Say Y here if you want kernel low-level debugging support
+                 on STiH415/416 based platforms like b2020. which has
+                 default UART wired up to SBC ASC1.
 
                  If unsure, say N.
 
        config DEBUG_U300_UART
                bool "Kernel low-level debugging messages via U300 UART0"
                depends on ARCH_U300
+               select DEBUG_UART_PL01X
                help
                  Say Y here if you want the debug print routines to direct
                  their output to the uart port on U300 devices.
@@ -548,6 +740,7 @@ choice
        config DEBUG_VEXPRESS_UART0_CA9
                bool "Use PL011 UART0 at 0x10009000 (V2P-CA9 core tile)"
                depends on ARCH_VEXPRESS
+               select DEBUG_UART_PL01X
                help
                  This option selects UART0 at 0x10009000. Except for custom models,
                  this applies only to the V2P-CA9 tile.
@@ -555,6 +748,7 @@ choice
        config DEBUG_VEXPRESS_UART0_RS1
                bool "Use PL011 UART0 at 0x1c090000 (RS1 complaint tiles)"
                depends on ARCH_VEXPRESS
+               select DEBUG_UART_PL01X
                help
                  This option selects UART0 at 0x1c090000. This applies to most
                  of the tiles using the RS1 memory map, including all new A-class
@@ -563,6 +757,7 @@ choice
        config DEBUG_VEXPRESS_UART0_CRX
                bool "Use PL011 UART0 at 0xb0090000 (Cortex-R compliant tiles)"
                depends on ARCH_VEXPRESS && !MMU
+               select DEBUG_UART_PL01X
                help
                  This option selects UART0 at 0xb0090000. This is appropriate for
                  Cortex-R series tiles and SMMs, such as Cortex-R5 and Cortex-R7
@@ -579,7 +774,7 @@ choice
                depends on !ARCH_MULTIPLATFORM
                help
                  Say Y here if your platform doesn't provide a UART option
-                 below. This relies on your platform choosing the right UART
+                 above. This relies on your platform choosing the right UART
                  definition internally in order for low-level debugging to
                  work.
 
@@ -610,11 +805,41 @@ choice
                  For more details about semihosting, please see
                  chapter 8 of DUI0203I_rvct_developer_guide.pdf from ARM Ltd.
 
+       config DEBUG_LL_UART_8250
+               bool "Kernel low-level debugging via 8250 UART"
+               help
+                 Say Y here if you wish the debug print routes to direct
+                 their output to an 8250 UART.  You can use this option
+                 to provide the parameters for the 8250 UART rather than
+                 selecting one of the platform specific options above if
+                 you know the parameters for the port.
+
+                 This option is preferred over the platform specific
+                 options; the platform specific options are deprecated
+                 and will be soon removed.
+
+       config DEBUG_LL_UART_PL01X
+               bool "Kernel low-level debugging via ARM Ltd PL01x Primecell UART"
+               help
+                 Say Y here if you wish the debug print routes to direct
+                 their output to a PL01x Primecell UART.  You can use
+                 this option to provide the parameters for the UART
+                 rather than selecting one of the platform specific
+                 options above if you know the parameters for the port.
+
+                 This option is preferred over the platform specific
+                 options; the platform specific options are deprecated
+                 and will be soon removed.
+
 endchoice
 
 config DEBUG_EXYNOS_UART
        bool
 
+config DEBUG_OMAP2PLUS_UART
+       bool
+       depends on ARCH_OMAP2PLUS
+
 config DEBUG_IMX_UART_PORT
        int "i.MX Debug UART Port Selection" if DEBUG_IMX1_UART || \
                                                DEBUG_IMX25_UART || \
@@ -631,140 +856,19 @@ config DEBUG_IMX_UART_PORT
          Choose UART port on which kernel low-level debug messages
          should be output.
 
-choice
-       prompt "Low-level debug console UART"
-       depends on DEBUG_OMAP2PLUS_UART
-
-       config DEBUG_OMAP2UART1
-               bool "OMAP2/3/4 UART1 (omap2/3 sdp boards and some omap3 boards)"
-               help
-                 This covers at least h4, 2430sdp, 3430sdp, 3630sdp,
-                 omap3 torpedo and 3530 lv som.
-
-       config DEBUG_OMAP2UART2
-               bool "OMAP2/3/4 UART2"
-
-       config DEBUG_OMAP2UART3
-               bool "OMAP2 UART3 (n8x0)"
-
-       config DEBUG_OMAP3UART3
-               bool "OMAP3 UART3 (most omap3 boards)"
-               help
-                 This covers at least cm_t3x, beagle, crane, devkit8000,
-                 igep00x0, ldp, n900, n9(50), pandora, overo, touchbook,
-                 and 3517evm.
-
-       config DEBUG_OMAP4UART3
-               bool "OMAP4/5 UART3 (omap4 blaze, panda, omap5 sevm)"
-
-       config DEBUG_OMAP3UART4
-               bool "OMAP36XX UART4"
-
-       config DEBUG_OMAP4UART4
-               bool "OMAP4/5 UART4"
-
-       config DEBUG_TI81XXUART1
-               bool "TI81XX UART1 (ti8148evm)"
-
-       config DEBUG_TI81XXUART2
-               bool "TI81XX UART2"
-
-       config DEBUG_TI81XXUART3
-               bool "TI81XX UART3 (ti8168evm)"
-
-       config DEBUG_AM33XXUART1
-               bool "AM33XX UART1"
-
-       config DEBUG_ZOOM_UART
-               bool "Zoom2/3 UART"
-endchoice
-
-choice
-       prompt "Low-level debug console UART"
-       depends on DEBUG_ROCKCHIP_UART
-
-       config DEBUG_RK29_UART0
-               bool "RK29 UART0"
-
-       config DEBUG_RK29_UART1
-               bool "RK29 UART1"
-
-       config DEBUG_RK29_UART2
-               bool "RK29 UART2"
-
-       config DEBUG_RK3X_UART0
-               bool "RK3X UART0"
-
-       config DEBUG_RK3X_UART1
-               bool "RK3X UART1"
-
-       config DEBUG_RK3X_UART2
-               bool "RK3X UART2"
-
-       config DEBUG_RK3X_UART3
-               bool "RK3X UART3"
-endchoice
-
-choice
-       prompt "Low-level debug console UART"
-       depends on DEBUG_LL && DEBUG_TEGRA_UART
-
-       config TEGRA_DEBUG_UART_AUTO_ODMDATA
-       bool "Via ODMDATA"
-       help
-         Automatically determines which UART to use for low-level debug based
-         on the ODMDATA value. This value is part of the BCT, and is written
-         to the boot memory device using nvflash, or other flashing tool.
-         When bits 19:18 are 3, then bits 17:15 indicate which UART to use;
-         0/1/2/3/4 are UART A/B/C/D/E.
-
-       config TEGRA_DEBUG_UARTA
-               bool "UART A"
-
-       config TEGRA_DEBUG_UARTB
-               bool "UART B"
-
-       config TEGRA_DEBUG_UARTC
-               bool "UART C"
-
-       config TEGRA_DEBUG_UARTD
-               bool "UART D"
-
-       config TEGRA_DEBUG_UARTE
-               bool "UART E"
-
-endchoice
-
-choice
-       prompt "Low-level debug console UART"
-       depends on DEBUG_LL && DEBUG_STI_UART
-
-       config STIH41X_DEBUG_ASC2
-               bool "ASC2 UART"
-               help
-                 Say Y here if you want kernel low-level debugging support
-                 on STiH415/416 based platforms like b2000, which has
-                 default UART wired up to ASC2.
-
-                 If unsure, say N.
-
-       config STIH41X_DEBUG_SBC_ASC1
-               bool "SBC ASC1 UART"
-               help
-                 Say Y here if you want kernel low-level debugging support
-                 on STiH415/416 based platforms like b2020. which has
-                 default UART wired up to SBC ASC1.
-
-                 If unsure, say N.
+config DEBUG_TEGRA_UART
+       bool
+       depends on ARCH_TEGRA
 
-endchoice
+config DEBUG_STI_UART
+       bool
+       depends on ARCH_STI
 
 config DEBUG_LL_INCLUDE
        string
-       default "debug/bcm2835.S" if DEBUG_BCM2835
-       default "debug/cns3xxx.S" if DEBUG_CNS3XXX
+       default "debug/8250.S" if DEBUG_LL_UART_8250 || DEBUG_UART_8250
+       default "debug/pl01x.S" if DEBUG_LL_UART_PL01X || DEBUG_UART_PL01X
        default "debug/exynos.S" if DEBUG_EXYNOS_UART
-       default "debug/highbank.S" if DEBUG_HIGHBANK_UART
        default "debug/icedcc.S" if DEBUG_ICEDCC
        default "debug/imx.S" if DEBUG_IMX1_UART || \
                                 DEBUG_IMX25_UART || \
@@ -775,38 +879,177 @@ config DEBUG_LL_INCLUDE
                                 DEBUG_IMX53_UART ||\
                                 DEBUG_IMX6Q_UART || \
                                 DEBUG_IMX6SL_UART
-       default "debug/keystone.S" if DEBUG_KEYSTONE_UART0 || \
-                                     DEBUG_KEYSTONE_UART1
-       default "debug/mvebu.S" if DEBUG_MVEBU_UART || \
-                                  DEBUG_MVEBU_UART_ALTERNATE
-       default "debug/mxs.S" if DEBUG_IMX23_UART || DEBUG_IMX28_UART
-       default "debug/nomadik.S" if DEBUG_NOMADIK_UART
-       default "debug/nspire.S" if     DEBUG_NSPIRE_CX_UART || \
-                                       DEBUG_NSPIRE_CLASSIC_UART
        default "debug/omap2plus.S" if DEBUG_OMAP2PLUS_UART
-       default "debug/picoxcell.S" if DEBUG_PICOXCELL_UART
-       default "debug/pxa.S" if DEBUG_PXA_UART1 || DEBUG_MMP_UART2 || \
-                                DEBUG_MMP_UART3
-       default "debug/rockchip.S" if DEBUG_ROCKCHIP_UART
        default "debug/sirf.S" if DEBUG_SIRFPRIMA2_UART1 || DEBUG_SIRFMARCO_UART1
-       default "debug/socfpga.S" if DEBUG_SOCFPGA_UART
        default "debug/sti.S" if DEBUG_STI_UART
-       default "debug/sunxi.S" if DEBUG_SUNXI_UART0 || DEBUG_SUNXI_UART1
        default "debug/tegra.S" if DEBUG_TEGRA_UART
-       default "debug/u300.S" if DEBUG_U300_UART
        default "debug/ux500.S" if DEBUG_UX500_UART
-       default "debug/vexpress.S" if DEBUG_VEXPRESS_UART0_DETECT || \
-               DEBUG_VEXPRESS_UART0_CA9 || DEBUG_VEXPRESS_UART0_RS1 || \
-               DEBUG_VEXPRESS_UART0_CRX
+       default "debug/vexpress.S" if DEBUG_VEXPRESS_UART0_DETECT
        default "debug/vt8500.S" if DEBUG_VT8500_UART0
        default "debug/zynq.S" if DEBUG_ZYNQ_UART0 || DEBUG_ZYNQ_UART1
        default "mach/debug-macro.S"
 
+# Compatibility options for PL01x
+config DEBUG_UART_PL01X
+       def_bool ARCH_EP93XX || \
+               ARCH_INTEGRATOR || \
+               ARCH_SPEAR3XX || \
+               ARCH_SPEAR6XX || \
+               ARCH_SPEAR13XX || \
+               ARCH_VERSATILE
+
+# Compatibility options for 8250
+config DEBUG_UART_8250
+       def_bool ARCH_DOVE || ARCH_EBSA110 || \
+               (FOOTBRIDGE && !DEBUG_DC21285_PORT) || \
+               ARCH_GEMINI || ARCH_IOP13XX || ARCH_IOP32X || \
+               ARCH_IOP33X || ARCH_IXP4XX || ARCH_KIRKWOOD || \
+               ARCH_LPC32XX || ARCH_MV78XX0 || ARCH_ORION5X || ARCH_RPC
+
+config DEBUG_UART_PHYS
+       hex "Physical base address of debug UART"
+       default 0x01c20000 if DEBUG_DAVINCI_DMx_UART0
+       default 0x01c28000 if DEBUG_SUNXI_UART0
+       default 0x01c28400 if DEBUG_SUNXI_UART1
+       default 0x01d0c000 if DEBUG_DAVINCI_DA8XX_UART1
+       default 0x01d0d000 if DEBUG_DAVINCI_DA8XX_UART2
+       default 0x02530c00 if DEBUG_KEYSTONE_UART0
+       default 0x02531000 if DEBUG_KEYSTONE_UART1
+       default 0x03010fe0 if ARCH_RPC
+       default 0x08108300 if DEBUG_DAVINCI_TNETV107X_UART1
+       default 0x10009000 if DEBUG_REALVIEW_STD_PORT || DEBUG_CNS3XXX || \
+                               DEBUG_VEXPRESS_UART0_CA9
+       default 0x1010c000 if DEBUG_REALVIEW_PB1176_PORT
+       default 0x10124000 if DEBUG_RK3X_UART0
+       default 0x10126000 if DEBUG_RK3X_UART1
+       default 0x101f1000 if ARCH_VERSATILE
+       default 0x101fb000 if DEBUG_NOMADIK_UART
+       default 0x16000000 if ARCH_INTEGRATOR
+       default 0x1c090000 if DEBUG_VEXPRESS_UART0_RS1
+       default 0x20060000 if DEBUG_RK29_UART0
+       default 0x20064000 if DEBUG_RK29_UART1 || DEBUG_RK3X_UART2
+       default 0x20068000 if DEBUG_RK29_UART2 || DEBUG_RK3X_UART3
+       default 0x20201000 if DEBUG_BCM2835
+       default 0x40090000 if ARCH_LPC32XX
+       default 0x40100000 if DEBUG_PXA_UART1
+       default 0x42000000 if ARCH_GEMINI
+       default 0x7c0003f8 if FOOTBRIDGE
+       default 0x80230000 if DEBUG_PICOXCELL_UART
+       default 0x80070000 if DEBUG_IMX23_UART
+       default 0x80074000 if DEBUG_IMX28_UART
+       default 0x808c0000 if ARCH_EP93XX
+       default 0x90020000 if DEBUG_NSPIRE_CLASSIC_UART || DEBUG_NSPIRE_CX_UART
+       default 0xb0090000 if DEBUG_VEXPRESS_UART0_CRX
+       default 0xc0013000 if DEBUG_U300_UART
+       default 0xc8000000 if ARCH_IXP4XX && !CPU_BIG_ENDIAN
+       default 0xc8000003 if ARCH_IXP4XX && CPU_BIG_ENDIAN
+       default 0xd0000000 if ARCH_SPEAR3XX || ARCH_SPEAR6XX
+       default 0xd0012000 if DEBUG_MVEBU_UART
+       default 0xd4017000 if DEBUG_MMP_UART2
+       default 0xd4018000 if DEBUG_MMP_UART3
+       default 0xe0000000 if ARCH_SPEAR13XX
+       default 0xf0000be0 if ARCH_EBSA110
+       default 0xf1012000 if DEBUG_MVEBU_UART_ALTERNATE
+       default 0xf1012000 if ARCH_DOVE || ARCH_KIRKWOOD || ARCH_MV78XX0 || \
+                               ARCH_ORION5X
+       default 0xfe800000 if ARCH_IOP32X
+       default 0xffc02000 if DEBUG_SOCFPGA_UART
+       default 0xffd82340 if ARCH_IOP13XX
+       default 0xfff36000 if DEBUG_HIGHBANK_UART
+       default 0xfffff700 if ARCH_IOP33X
+       depends on DEBUG_LL_UART_8250 || DEBUG_LL_UART_PL01X || \
+               DEBUG_UART_8250 || DEBUG_UART_PL01X
+
+config DEBUG_UART_VIRT
+       hex "Virtual base address of debug UART"
+       default 0xe0010fe0 if ARCH_RPC
+       default 0xf0000be0 if ARCH_EBSA110
+       default 0xf0009000 if DEBUG_CNS3XXX
+       default 0xf01fb000 if DEBUG_NOMADIK_UART
+       default 0xf0201000 if DEBUG_BCM2835
+       default 0xf11f1000 if ARCH_VERSATILE
+       default 0xf1600000 if ARCH_INTEGRATOR
+       default 0xf1c28000 if DEBUG_SUNXI_UART0
+       default 0xf1c28400 if DEBUG_SUNXI_UART1
+       default 0xf2100000 if DEBUG_PXA_UART1
+       default 0xf4090000 if ARCH_LPC32XX
+       default 0xf4200000 if ARCH_GEMINI
+       default 0xf8009000 if DEBUG_VEXPRESS_UART0_CA9
+       default 0xf8090000 if DEBUG_VEXPRESS_UART0_RS1
+       default 0xfb009000 if DEBUG_REALVIEW_STD_PORT
+       default 0xfb10c000 if DEBUG_REALVIEW_PB1176_PORT
+       default 0xfd000000 if ARCH_SPEAR3XX || ARCH_SPEAR6XX
+       default 0xfd000000 if ARCH_SPEAR13XX
+       default 0xfd012000 if ARCH_MV78XX0
+       default 0xfde12000 if ARCH_DOVE
+       default 0xfe012000 if ARCH_ORION5X
+       default 0xfe017000 if DEBUG_MMP_UART2
+       default 0xfe018000 if DEBUG_MMP_UART3
+       default 0xfe100000 if DEBUG_IMX23_UART || DEBUG_IMX28_UART
+       default 0xfe230000 if DEBUG_PICOXCELL_UART
+       default 0xfe800000 if ARCH_IOP32X
+       default 0xfeb24000 if DEBUG_RK3X_UART0
+       default 0xfeb26000 if DEBUG_RK3X_UART1
+       default 0xfeb30c00 if DEBUG_KEYSTONE_UART0
+       default 0xfeb31000 if DEBUG_KEYSTONE_UART1
+       default 0xfec12000 if DEBUG_MVEBU_UART || DEBUG_MVEBU_UART_ALTERNATE
+       default 0xfed60000 if DEBUG_RK29_UART0
+       default 0xfed64000 if DEBUG_RK29_UART1 || DEBUG_RK3X_UART2
+       default 0xfed68000 if DEBUG_RK29_UART2 || DEBUG_RK3X_UART3
+       default 0xfec02000 if DEBUG_SOCFPGA_UART
+       default 0xfec20000 if DEBUG_DAVINCI_DMx_UART0
+       default 0xfed0c000 if DEBUG_DAVINCI_DA8XX_UART1
+       default 0xfed0d000 if DEBUG_DAVINCI_DA8XX_UART2
+       default 0xfed12000 if ARCH_KIRKWOOD
+       default 0xfedc0000 if ARCH_EP93XX
+       default 0xfee003f8 if FOOTBRIDGE
+       default 0xfee08300 if DEBUG_DAVINCI_TNETV107X_UART1
+       default 0xfee20000 if DEBUG_NSPIRE_CLASSIC_UART || DEBUG_NSPIRE_CX_UART
+       default 0xfee36000 if DEBUG_HIGHBANK_UART
+       default 0xfee82340 if ARCH_IOP13XX
+       default 0xfef00000 if ARCH_IXP4XX && !CPU_BIG_ENDIAN
+       default 0xfef00003 if ARCH_IXP4XX && CPU_BIG_ENDIAN
+       default 0xfefff700 if ARCH_IOP33X
+       default 0xff003000 if DEBUG_U300_UART
+       default DEBUG_UART_PHYS if !MMU
+       depends on DEBUG_LL_UART_8250 || DEBUG_LL_UART_PL01X || \
+               DEBUG_UART_8250 || DEBUG_UART_PL01X
+
+config DEBUG_UART_8250_SHIFT
+       int "Register offset shift for the 8250 debug UART"
+       depends on DEBUG_LL_UART_8250 || DEBUG_UART_8250
+       default 0 if FOOTBRIDGE || ARCH_IOP32X
+       default 2
+
+config DEBUG_UART_8250_WORD
+       bool "Use 32-bit accesses for 8250 UART"
+       depends on DEBUG_LL_UART_8250 || DEBUG_UART_8250
+       depends on DEBUG_UART_8250_SHIFT >= 2
+       default y if DEBUG_PICOXCELL_UART || DEBUG_SOCFPGA_UART || \
+               ARCH_KEYSTONE || \
+               DEBUG_DAVINCI_DMx_UART0 || DEBUG_DAVINCI_DA8XX_UART1 || \
+               DEBUG_DAVINCI_DA8XX_UART2 || DEBUG_DAVINCI_TNETV107X_UART1
+
+config DEBUG_UART_8250_FLOW_CONTROL
+       bool "Enable flow control for 8250 UART"
+       depends on DEBUG_LL_UART_8250 || DEBUG_UART_8250
+       default y if ARCH_EBSA110 || FOOTBRIDGE || ARCH_GEMINI || ARCH_RPC
+
 config DEBUG_UNCOMPRESS
        bool
-       default y if ARCH_MULTIPLATFORM && DEBUG_LL && \
-                    !DEBUG_OMAP2PLUS_UART && \
+       depends on ARCH_MULTIPLATFORM
+       default y if DEBUG_LL && !DEBUG_OMAP2PLUS_UART && \
                     !DEBUG_TEGRA_UART
+       help
+         This option influences the normal decompressor output for
+         multiplatform kernels.  Normally, multiplatform kernels disable
+         decompressor output because it is not possible to know where to
+         send the decompressor output.
+
+         When this option is set, the selected DEBUG_LL output method
+         will be re-used for normal decompressor output on multiplatform
+         kernels.
+         
 
 config UNCOMPRESS_INCLUDE
        string
index c0ac0f5e5e5c0900c5e0e081390e0af900005738..6fd2ceae305a6a5cf6c5d2e766e4c91848b147f7 100644 (file)
@@ -153,6 +153,7 @@ machine-$(CONFIG_ARCH_DAVINCI)              += davinci
 machine-$(CONFIG_ARCH_DOVE)            += dove
 machine-$(CONFIG_ARCH_EBSA110)         += ebsa110
 machine-$(CONFIG_ARCH_EP93XX)          += ep93xx
+machine-$(CONFIG_ARCH_EXYNOS)          += exynos
 machine-$(CONFIG_ARCH_GEMINI)          += gemini
 machine-$(CONFIG_ARCH_HIGHBANK)                += highbank
 machine-$(CONFIG_ARCH_INTEGRATOR)      += integrator
@@ -160,15 +161,16 @@ machine-$(CONFIG_ARCH_IOP13XX)            += iop13xx
 machine-$(CONFIG_ARCH_IOP32X)          += iop32x
 machine-$(CONFIG_ARCH_IOP33X)          += iop33x
 machine-$(CONFIG_ARCH_IXP4XX)          += ixp4xx
+machine-$(CONFIG_ARCH_KEYSTONE)                += keystone
 machine-$(CONFIG_ARCH_KIRKWOOD)                += kirkwood
 machine-$(CONFIG_ARCH_KS8695)          += ks8695
 machine-$(CONFIG_ARCH_LPC32XX)         += lpc32xx
 machine-$(CONFIG_ARCH_MMP)             += mmp
 machine-$(CONFIG_ARCH_MSM)             += msm
 machine-$(CONFIG_ARCH_MV78XX0)         += mv78xx0
+machine-$(CONFIG_ARCH_MVEBU)           += mvebu
 machine-$(CONFIG_ARCH_MXC)             += imx
 machine-$(CONFIG_ARCH_MXS)             += mxs
-machine-$(CONFIG_ARCH_MVEBU)           += mvebu
 machine-$(CONFIG_ARCH_NETX)            += netx
 machine-$(CONFIG_ARCH_NOMADIK)         += nomadik
 machine-$(CONFIG_ARCH_NSPIRE)          += nspire
@@ -176,7 +178,6 @@ machine-$(CONFIG_ARCH_OMAP1)                += omap1
 machine-$(CONFIG_ARCH_OMAP2PLUS)       += omap2
 machine-$(CONFIG_ARCH_ORION5X)         += orion5x
 machine-$(CONFIG_ARCH_PICOXCELL)       += picoxcell
-machine-$(CONFIG_ARCH_SIRF)            += prima2
 machine-$(CONFIG_ARCH_PXA)             += pxa
 machine-$(CONFIG_ARCH_REALVIEW)                += realview
 machine-$(CONFIG_ARCH_ROCKCHIP)                += rockchip
@@ -186,25 +187,24 @@ machine-$(CONFIG_ARCH_S3C64XX)            += s3c64xx
 machine-$(CONFIG_ARCH_S5P64X0)         += s5p64x0
 machine-$(CONFIG_ARCH_S5PC100)         += s5pc100
 machine-$(CONFIG_ARCH_S5PV210)         += s5pv210
-machine-$(CONFIG_ARCH_EXYNOS)          += exynos
 machine-$(CONFIG_ARCH_SA1100)          += sa1100
 machine-$(CONFIG_ARCH_SHARK)           += shark
 machine-$(CONFIG_ARCH_SHMOBILE)        += shmobile
+machine-$(CONFIG_ARCH_SIRF)            += prima2
+machine-$(CONFIG_ARCH_SOCFPGA)         += socfpga
+machine-$(CONFIG_ARCH_STI)             += sti
+machine-$(CONFIG_ARCH_SUNXI)           += sunxi
 machine-$(CONFIG_ARCH_TEGRA)           += tegra
 machine-$(CONFIG_ARCH_U300)            += u300
 machine-$(CONFIG_ARCH_U8500)           += ux500
 machine-$(CONFIG_ARCH_VERSATILE)       += versatile
 machine-$(CONFIG_ARCH_VEXPRESS)                += vexpress
+machine-$(CONFIG_ARCH_VIRT)            += virt
 machine-$(CONFIG_ARCH_VT8500)          += vt8500
 machine-$(CONFIG_ARCH_W90X900)         += w90x900
+machine-$(CONFIG_ARCH_ZYNQ)            += zynq
 machine-$(CONFIG_FOOTBRIDGE)           += footbridge
-machine-$(CONFIG_ARCH_SOCFPGA)         += socfpga
 machine-$(CONFIG_PLAT_SPEAR)           += spear
-machine-$(CONFIG_ARCH_STI)             += sti
-machine-$(CONFIG_ARCH_VIRT)            += virt
-machine-$(CONFIG_ARCH_ZYNQ)            += zynq
-machine-$(CONFIG_ARCH_SUNXI)           += sunxi
-machine-$(CONFIG_ARCH_KEYSTONE)                += keystone
 
 # Platform directory name.  This list is sorted alphanumerically
 # by CONFIG_* macro name.
diff --git a/arch/arm/include/asm/a.out-core.h b/arch/arm/include/asm/a.out-core.h
deleted file mode 100644 (file)
index 92f10cb..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/* a.out coredump register dumper
- *
- * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public Licence
- * as published by the Free Software Foundation; either version
- * 2 of the Licence, or (at your option) any later version.
- */
-
-#ifndef _ASM_A_OUT_CORE_H
-#define _ASM_A_OUT_CORE_H
-
-#ifdef __KERNEL__
-
-#include <linux/user.h>
-#include <linux/elfcore.h>
-
-/*
- * fill in the user structure for an a.out core dump
- */
-static inline void aout_dump_thread(struct pt_regs *regs, struct user *dump)
-{
-       struct task_struct *tsk = current;
-
-       dump->magic = CMAGIC;
-       dump->start_code = tsk->mm->start_code;
-       dump->start_stack = regs->ARM_sp & ~(PAGE_SIZE - 1);
-
-       dump->u_tsize = (tsk->mm->end_code - tsk->mm->start_code) >> PAGE_SHIFT;
-       dump->u_dsize = (tsk->mm->brk - tsk->mm->start_data + PAGE_SIZE - 1) >> PAGE_SHIFT;
-       dump->u_ssize = 0;
-
-       memset(dump->u_debugreg, 0, sizeof(dump->u_debugreg));
-
-       if (dump->start_stack < 0x04000000)
-               dump->u_ssize = (0x04000000 - dump->start_stack) >> PAGE_SHIFT;
-
-       dump->regs = *regs;
-       dump->u_fpvalid = dump_fpu (regs, &dump->u_fp);
-}
-
-#endif /* __KERNEL__ */
-#endif /* _ASM_A_OUT_CORE_H */
index 8c25dc4e98514d85db8ce77f4d9e7fa8f828262d..9672e978d50df67d94c3dd86d23f3bcdd187c54d 100644 (file)
@@ -89,13 +89,18 @@ extern unsigned int processor_id;
                __val;                                                  \
        })
 
+/*
+ * The memory clobber prevents gcc 4.5 from reordering the mrc before
+ * any is_smp() tests, which can cause undefined instruction aborts on
+ * ARM1136 r0 due to the missing extended CP15 registers.
+ */
 #define read_cpuid_ext(ext_reg)                                                \
        ({                                                              \
                unsigned int __val;                                     \
                asm("mrc        p15, 0, %0, c0, " ext_reg               \
                    : "=r" (__val)                                      \
                    :                                                   \
-                   : "cc");                                            \
+                   : "memory");                                        \
                __val;                                                  \
        })
 
diff --git a/arch/arm/include/asm/hardware/debug-8250.S b/arch/arm/include/asm/hardware/debug-8250.S
deleted file mode 100644 (file)
index 22c6892..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * arch/arm/include/asm/hardware/debug-8250.S
- *
- *  Copyright (C) 1994-1999 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/serial_reg.h>
-
-               .macro  senduart,rd,rx
-               strb    \rd, [\rx, #UART_TX << UART_SHIFT]
-               .endm
-
-               .macro  busyuart,rd,rx
-1002:          ldrb    \rd, [\rx, #UART_LSR << UART_SHIFT]
-               and     \rd, \rd, #UART_LSR_TEMT | UART_LSR_THRE
-               teq     \rd, #UART_LSR_TEMT | UART_LSR_THRE
-               bne     1002b
-               .endm
-
-               .macro  waituart,rd,rx
-#ifdef FLOW_CONTROL
-1001:          ldrb    \rd, [\rx, #UART_MSR << UART_SHIFT]
-               tst     \rd, #UART_MSR_CTS
-               beq     1001b
-#endif
-               .endm
index 441efc491b50aa0f402bf60fbe6ecd6020456875..69b879ac0289fde3a1ce8776b7d3602078286be7 100644 (file)
@@ -65,12 +65,12 @@ struct machine_desc {
 /*
  * Current machine - only accessible during boot.
  */
-extern struct machine_desc *machine_desc;
+extern const struct machine_desc *machine_desc;
 
 /*
  * Machine type table - also only accessible during boot
  */
-extern struct machine_desc __arch_info_begin[], __arch_info_end[];
+extern const struct machine_desc __arch_info_begin[], __arch_info_end[];
 #define for_each_machine_desc(p)                       \
        for (p = __arch_info_begin; p < __arch_info_end; p++)
 
index 00ca5f92648ea56616afe8bfbd4a25ff8f0b0e27..c2f5102ae6595b19b9e3d6494395d052ec74687d 100644 (file)
@@ -4,8 +4,7 @@
 struct meminfo;
 struct machine_desc;
 
-extern void arm_memblock_init(struct meminfo *, struct machine_desc *);
-
+void arm_memblock_init(struct meminfo *, const struct machine_desc *);
 phys_addr_t arm_memblock_steal(phys_addr_t size, phys_addr_t align);
 
 #endif
index e3d55547e75592a9eb98fa1704ee8df9e872c2c5..d1b4998e4f43987d0151d070cada4c1247fb302e 100644 (file)
@@ -6,6 +6,8 @@
 typedef struct {
 #ifdef CONFIG_CPU_HAS_ASID
        atomic64_t      id;
+#else
+       int             switch_pending;
 #endif
        unsigned int    vmalloc_seq;
 } mm_context_t;
index b5792b7fd8d3149c94c87f5650410b3ece3a2bd2..9b32f76bb0ddaa6d6e485d79cc9f2bdfeb24d776 100644 (file)
@@ -56,7 +56,7 @@ static inline void check_and_switch_context(struct mm_struct *mm,
                 * on non-ASID CPUs, the old mm will remain valid until the
                 * finish_arch_post_lock_switch() call.
                 */
-               set_ti_thread_flag(task_thread_info(tsk), TIF_SWITCH_MM);
+               mm->context.switch_pending = 1;
        else
                cpu_switch_mm(mm->pgd, mm);
 }
@@ -65,9 +65,21 @@ static inline void check_and_switch_context(struct mm_struct *mm,
        finish_arch_post_lock_switch
 static inline void finish_arch_post_lock_switch(void)
 {
-       if (test_and_clear_thread_flag(TIF_SWITCH_MM)) {
-               struct mm_struct *mm = current->mm;
-               cpu_switch_mm(mm->pgd, mm);
+       struct mm_struct *mm = current->mm;
+
+       if (mm && mm->context.switch_pending) {
+               /*
+                * Preemption must be disabled during cpu_switch_mm() as we
+                * have some stateful cache flush implementations. Check
+                * switch_pending again in case we were preempted and the
+                * switch to this mm was already done.
+                */
+               preempt_disable();
+               if (mm->context.switch_pending) {
+                       mm->context.switch_pending = 0;
+                       cpu_switch_mm(mm->pgd, mm);
+               }
+               preempt_enable_no_resched();
        }
 }
 
diff --git a/arch/arm/include/asm/neon.h b/arch/arm/include/asm/neon.h
new file mode 100644 (file)
index 0000000..8f730fe
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * linux/arch/arm/include/asm/neon.h
+ *
+ * Copyright (C) 2013 Linaro Ltd <ard.biesheuvel@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <asm/hwcap.h>
+
+#define cpu_has_neon()         (!!(elf_hwcap & HWCAP_NEON))
+
+#ifdef __ARM_NEON__
+
+/*
+ * If you are affected by the BUILD_BUG below, it probably means that you are
+ * using NEON code /and/ calling the kernel_neon_begin() function from the same
+ * compilation unit. To prevent issues that may arise from GCC reordering or
+ * generating(1) NEON instructions outside of these begin/end functions, the
+ * only supported way of using NEON code in the kernel is by isolating it in a
+ * separate compilation unit, and calling it from another unit from inside a
+ * kernel_neon_begin/kernel_neon_end pair.
+ *
+ * (1) Current GCC (4.7) might generate NEON instructions at O3 level if
+ *     -mpfu=neon is set.
+ */
+
+#define kernel_neon_begin() \
+       BUILD_BUG_ON_MSG(1, "kernel_neon_begin() called from NEON code")
+
+#else
+void kernel_neon_begin(void);
+#endif
+void kernel_neon_end(void);
index 06e7d509eaac218864cc9d089ce9e6f4177c22f9..413f3876341cd6fd2e7bc4b1c6a71873cadaa887 100644 (file)
@@ -54,7 +54,6 @@ struct thread_struct {
 
 #define start_thread(regs,pc,sp)                                       \
 ({                                                                     \
-       unsigned long *stack = (unsigned long *)sp;                     \
        memset(regs->uregs, 0, sizeof(regs->uregs));                    \
        if (current->personality & ADDR_LIMIT_32BIT)                    \
                regs->ARM_cpsr = USR_MODE;                              \
@@ -65,9 +64,6 @@ struct thread_struct {
        regs->ARM_cpsr |= PSR_ENDSTATE;                                 \
        regs->ARM_pc = pc & ~1;         /* pc */                        \
        regs->ARM_sp = sp;              /* sp */                        \
-       regs->ARM_r2 = stack[2];        /* r2 (envp) */                 \
-       regs->ARM_r1 = stack[1];        /* r1 (argv) */                 \
-       regs->ARM_r0 = stack[0];        /* r0 (argc) */                 \
        nommu_start_thread(regs);                                       \
 })
 
index a219227c3e43815417887e2425d2c900d856333e..4a2985e21969ab283889935c20ad44a486ed1dcd 100644 (file)
 
 #ifdef CONFIG_OF
 
-extern struct machine_desc *setup_machine_fdt(unsigned int dt_phys);
+extern const struct machine_desc *setup_machine_fdt(unsigned int dt_phys);
 extern void arm_dt_memblock_reserve(void);
 extern void __init arm_dt_init_cpu_maps(void);
 
 #else /* CONFIG_OF */
 
-static inline struct machine_desc *setup_machine_fdt(unsigned int dt_phys)
+static inline const struct machine_desc *setup_machine_fdt(unsigned int dt_phys)
 {
        return NULL;
 }
index 214d4158089afce9c04102604fe07c5257c454e5..2b8114fcba09a3c5b9d6aceefbc6e456a8c9050a 100644 (file)
@@ -156,7 +156,6 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *,
 #define TIF_USING_IWMMXT       17
 #define TIF_MEMDIE             18      /* is terminating due to OOM killer */
 #define TIF_RESTORE_SIGMASK    20
-#define TIF_SWITCH_MM          22      /* deferred switch_mm */
 
 #define _TIF_SIGPENDING                (1 << TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED      (1 << TIF_NEED_RESCHED)
index fdbb9e369745c4b09d776a4568caa52702b7e9a7..f467e9b3f8d5d5b35c1d6fce386c718eb1b21e8f 100644 (file)
@@ -443,7 +443,18 @@ static inline void local_flush_bp_all(void)
                isb();
 }
 
+#include <asm/cputype.h>
 #ifdef CONFIG_ARM_ERRATA_798181
+static inline int erratum_a15_798181(void)
+{
+       unsigned int midr = read_cpuid_id();
+
+       /* Cortex-A15 r0p0..r3p2 affected */
+       if ((midr & 0xff0ffff0) != 0x410fc0f0 || midr > 0x413fc0f2)
+               return 0;
+       return 1;
+}
+
 static inline void dummy_flush_tlb_a15_erratum(void)
 {
        /*
@@ -453,6 +464,11 @@ static inline void dummy_flush_tlb_a15_erratum(void)
        dsb();
 }
 #else
+static inline int erratum_a15_798181(void)
+{
+       return 0;
+}
+
 static inline void dummy_flush_tlb_a15_erratum(void)
 {
 }
index 50af92bac7373eb7fbc01c8f38c4d7dfd6ccb05d..4371f45c578401c7f233e565dbb5fd36d9d59d52 100644 (file)
@@ -29,6 +29,7 @@
 #define BOOT_CPU_MODE_MISMATCH PSR_N_BIT
 
 #ifndef __ASSEMBLY__
+#include <asm/cacheflush.h>
 
 #ifdef CONFIG_ARM_VIRT_EXT
 /*
  */
 extern int __boot_cpu_mode;
 
+static inline void sync_boot_mode(void)
+{
+       /*
+        * As secondaries write to __boot_cpu_mode with caches disabled, we
+        * must flush the corresponding cache entries to ensure the visibility
+        * of their writes.
+        */
+       sync_cache_r(&__boot_cpu_mode);
+}
+
 void __hyp_set_vectors(unsigned long phys_vector_base);
 unsigned long __hyp_get_vectors(void);
 #else
 #define __boot_cpu_mode        (SVC_MODE)
+#define sync_boot_mode()
 #endif
 
 #ifndef ZIMAGE
index 7604673dc4278609b4f7ba68985d8b996b49ec47..4ffb26d4cad8d9f5225b83e15b9c20c1d3ef7c00 100644 (file)
@@ -7,7 +7,10 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+#include <linux/hardirq.h>
 #include <asm-generic/xor.h>
+#include <asm/hwcap.h>
+#include <asm/neon.h>
 
 #define __XOR(a1, a2) a1 ^= a2
 
@@ -138,4 +141,74 @@ static struct xor_block_template xor_block_arm4regs = {
                xor_speed(&xor_block_arm4regs); \
                xor_speed(&xor_block_8regs);    \
                xor_speed(&xor_block_32regs);   \
+               NEON_TEMPLATES;                 \
        } while (0)
+
+#ifdef CONFIG_KERNEL_MODE_NEON
+
+extern struct xor_block_template const xor_block_neon_inner;
+
+static void
+xor_neon_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
+{
+       if (in_interrupt()) {
+               xor_arm4regs_2(bytes, p1, p2);
+       } else {
+               kernel_neon_begin();
+               xor_block_neon_inner.do_2(bytes, p1, p2);
+               kernel_neon_end();
+       }
+}
+
+static void
+xor_neon_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+               unsigned long *p3)
+{
+       if (in_interrupt()) {
+               xor_arm4regs_3(bytes, p1, p2, p3);
+       } else {
+               kernel_neon_begin();
+               xor_block_neon_inner.do_3(bytes, p1, p2, p3);
+               kernel_neon_end();
+       }
+}
+
+static void
+xor_neon_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+               unsigned long *p3, unsigned long *p4)
+{
+       if (in_interrupt()) {
+               xor_arm4regs_4(bytes, p1, p2, p3, p4);
+       } else {
+               kernel_neon_begin();
+               xor_block_neon_inner.do_4(bytes, p1, p2, p3, p4);
+               kernel_neon_end();
+       }
+}
+
+static void
+xor_neon_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+               unsigned long *p3, unsigned long *p4, unsigned long *p5)
+{
+       if (in_interrupt()) {
+               xor_arm4regs_5(bytes, p1, p2, p3, p4, p5);
+       } else {
+               kernel_neon_begin();
+               xor_block_neon_inner.do_5(bytes, p1, p2, p3, p4, p5);
+               kernel_neon_end();
+       }
+}
+
+static struct xor_block_template xor_block_neon = {
+       .name   = "neon",
+       .do_2   = xor_neon_2,
+       .do_3   = xor_neon_3,
+       .do_4   = xor_neon_4,
+       .do_5   = xor_neon_5
+};
+
+#define NEON_TEMPLATES \
+       do { if (cpu_has_neon()) xor_speed(&xor_block_neon); } while (0)
+#else
+#define NEON_TEMPLATES
+#endif
diff --git a/arch/arm/include/debug/8250.S b/arch/arm/include/debug/8250.S
new file mode 100644 (file)
index 0000000..7a2baf9
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * arch/arm/include/debug/8250.S
+ *
+ *  Copyright (C) 1994-2013 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/serial_reg.h>
+
+               .macro  addruart, rp, rv, tmp
+               ldr     \rp, =CONFIG_DEBUG_UART_PHYS
+               ldr     \rv, =CONFIG_DEBUG_UART_VIRT
+               .endm
+
+#ifdef CONFIG_DEBUG_UART_8250_WORD
+               .macro  store, rd, rx:vararg
+               str     \rd, \rx
+               .endm
+
+               .macro  load, rd, rx:vararg
+               ldr     \rd, \rx
+               .endm
+#else
+               .macro  store, rd, rx:vararg
+               strb    \rd, \rx
+               .endm
+
+               .macro  load, rd, rx:vararg
+               ldrb    \rd, \rx
+               .endm
+#endif
+
+#define UART_SHIFT CONFIG_DEBUG_UART_8250_SHIFT
+
+               .macro  senduart,rd,rx
+               store   \rd, [\rx, #UART_TX << UART_SHIFT]
+               .endm
+
+               .macro  busyuart,rd,rx
+1002:          load    \rd, [\rx, #UART_LSR << UART_SHIFT]
+               and     \rd, \rd, #UART_LSR_TEMT | UART_LSR_THRE
+               teq     \rd, #UART_LSR_TEMT | UART_LSR_THRE
+               bne     1002b
+               .endm
+
+               .macro  waituart,rd,rx
+#ifdef CONFIG_DEBUG_UART_8250_FLOW_CONTROL
+1001:          load    \rd, [\rx, #UART_MSR << UART_SHIFT]
+               tst     \rd, #UART_MSR_CTS
+               beq     1001b
+#endif
+               .endm
diff --git a/arch/arm/include/debug/8250_32.S b/arch/arm/include/debug/8250_32.S
deleted file mode 100644 (file)
index 8db01ee..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2011 Picochip Ltd., Jamie Iles
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Derived from arch/arm/mach-davinci/include/mach/debug-macro.S to use 32-bit
- * accesses to the 8250.
- */
-
-#include <linux/serial_reg.h>
-
-               .macro  senduart,rd,rx
-               str     \rd, [\rx, #UART_TX << UART_SHIFT]
-               .endm
-
-               .macro  busyuart,rd,rx
-1002:          ldr     \rd, [\rx, #UART_LSR << UART_SHIFT]
-               and     \rd, \rd, #UART_LSR_TEMT | UART_LSR_THRE
-               teq     \rd, #UART_LSR_TEMT | UART_LSR_THRE
-               bne     1002b
-               .endm
-
-               /* The UART's don't have any flow control IO's wired up. */
-               .macro  waituart,rd,rx
-               .endm
diff --git a/arch/arm/include/debug/bcm2835.S b/arch/arm/include/debug/bcm2835.S
deleted file mode 100644 (file)
index aed9199..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Debugging macro include header
- *
- * Copyright (C) 2010 Broadcom
- * Copyright (C) 1994-1999 Russell King
- * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-#define BCM2835_DEBUG_PHYS 0x20201000
-#define BCM2835_DEBUG_VIRT 0xf0201000
-
-       .macro  addruart, rp, rv, tmp
-       ldr     \rp, =BCM2835_DEBUG_PHYS
-       ldr     \rv, =BCM2835_DEBUG_VIRT
-       .endm
-
-#include <asm/hardware/debug-pl01x.S>
diff --git a/arch/arm/include/debug/cns3xxx.S b/arch/arm/include/debug/cns3xxx.S
deleted file mode 100644 (file)
index d04c150..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Debugging macro include header
- *
- * Copyright 1994-1999 Russell King
- * Copyright 2008 Cavium Networks
- * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
- *
- * This file is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, Version 2, as
- * published by the Free Software Foundation.
- */
-
-               .macro  addruart,rp,rv,tmp
-               mov     \rp, #0x00009000
-               orr     \rv, \rp, #0xf0000000   @ virtual base
-               orr     \rp, \rp, #0x10000000
-               .endm
-
-#include <asm/hardware/debug-pl01x.S>
diff --git a/arch/arm/include/debug/highbank.S b/arch/arm/include/debug/highbank.S
deleted file mode 100644 (file)
index 8cad432..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Debugging macro include header
- *
- *  Copyright (C) 1994-1999 Russell King
- *  Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-               .macro  addruart,rp,rv,tmp
-               ldr     \rv, =0xfee36000
-               ldr     \rp, =0xfff36000
-               .endm
-
-#include <asm/hardware/debug-pl01x.S>
diff --git a/arch/arm/include/debug/keystone.S b/arch/arm/include/debug/keystone.S
deleted file mode 100644 (file)
index 9aef9ba..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Early serial debug output macro for Keystone SOCs
- *
- * Copyright 2013 Texas Instruments, Inc.
- *     Santosh Shilimkar <santosh.shilimkar@ti.com>
- *
- * Based on RMKs low level debug code.
- *  Copyright (C) 1994-1999 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/serial_reg.h>
-
-#define UART_SHIFT 2
-#if defined(CONFIG_DEBUG_KEYSTONE_UART0)
-#define UART_PHYS              0x02530c00
-#define UART_VIRT              0xfeb30c00
-#elif defined(CONFIG_DEBUG_KEYSTONE_UART1)
-#define UART_PHYS              0x02531000
-#define UART_VIRT              0xfeb31000
-#endif
-
-       .macro  addruart, rp, rv, tmp
-       ldr     \rv, =UART_VIRT                 @ physical base address
-       ldr     \rp, =UART_PHYS                 @ virtual base address
-       .endm
-
-       .macro  senduart,rd,rx
-       str     \rd, [\rx, #UART_TX << UART_SHIFT]
-       .endm
-
-       .macro  busyuart,rd,rx
-1002:  ldr     \rd, [\rx, #UART_LSR << UART_SHIFT]
-       and     \rd, \rd, #UART_LSR_TEMT | UART_LSR_THRE
-       teq     \rd, #UART_LSR_TEMT | UART_LSR_THRE
-       bne     1002b
-       .endm
-
-       .macro  waituart,rd,rx
-       .endm
diff --git a/arch/arm/include/debug/mvebu.S b/arch/arm/include/debug/mvebu.S
deleted file mode 100644 (file)
index 6517311..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Early serial output macro for Marvell  SoC
- *
- * Copyright (C) 2012 Marvell
- *
- * Lior Amsalem <alior@marvell.com>
- * Gregory Clement <gregory.clement@free-electrons.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifdef CONFIG_DEBUG_MVEBU_UART_ALTERNATE
-#define ARMADA_370_XP_REGS_PHYS_BASE   0xf1000000
-#else
-#define ARMADA_370_XP_REGS_PHYS_BASE   0xd0000000
-#endif
-
-#define ARMADA_370_XP_REGS_VIRT_BASE   0xfec00000
-
-       .macro  addruart, rp, rv, tmp
-       ldr     \rp, =ARMADA_370_XP_REGS_PHYS_BASE
-       ldr     \rv, =ARMADA_370_XP_REGS_VIRT_BASE
-       orr     \rp, \rp, #0x00012000
-       orr     \rv, \rv, #0x00012000
-       .endm
-
-#define UART_SHIFT     2
-#include <asm/hardware/debug-8250.S>
diff --git a/arch/arm/include/debug/mxs.S b/arch/arm/include/debug/mxs.S
deleted file mode 100644 (file)
index d869515..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/* arch/arm/mach-mxs/include/mach/debug-macro.S
- *
- * Debugging macro include header
- *
- *  Copyright (C) 1994-1999 Russell King
- *  Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-#ifdef CONFIG_DEBUG_IMX23_UART
-#define UART_PADDR     0x80070000
-#elif defined (CONFIG_DEBUG_IMX28_UART)
-#define UART_PADDR     0x80074000
-#endif
-
-#define UART_VADDR     0xfe100000
-
-               .macro  addruart, rp, rv, tmp
-               ldr     \rp, =UART_PADDR        @ physical
-               ldr     \rv, =UART_VADDR        @ virtual
-               .endm
-
-#include <asm/hardware/debug-pl01x.S>
diff --git a/arch/arm/include/debug/nomadik.S b/arch/arm/include/debug/nomadik.S
deleted file mode 100644 (file)
index 7354179..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Debugging macro include header
- *
- *  Copyright (C) 1994-1999 Russell King
- *  Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
-*/
-
-               .macro  addruart, rp, rv, tmp
-               mov     \rp, #0x00100000
-               add     \rp, \rp, #0x000fb000
-               add     \rv, \rp, #0xf0000000   @ virtual base
-               add     \rp, \rp, #0x10000000   @ physical base address
-               .endm
-
-#include <asm/hardware/debug-pl01x.S>
diff --git a/arch/arm/include/debug/nspire.S b/arch/arm/include/debug/nspire.S
deleted file mode 100644 (file)
index 886fd27..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- *     linux/arch/arm/include/debug/nspire.S
- *
- *     Copyright (C) 2013 Daniel Tang <tangrs@tangrs.id.au>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2, as
- * published by the Free Software Foundation.
- *
- */
-
-#define NSPIRE_EARLY_UART_PHYS_BASE       0x90020000
-#define NSPIRE_EARLY_UART_VIRT_BASE       0xfee20000
-
-.macro addruart, rp, rv, tmp
-       ldr \rp, =(NSPIRE_EARLY_UART_PHYS_BASE)         @ physical base address
-       ldr \rv, =(NSPIRE_EARLY_UART_VIRT_BASE)         @ virtual base address
-.endm
-
-
-#ifdef CONFIG_DEBUG_NSPIRE_CX_UART
-#include <asm/hardware/debug-pl01x.S>
-#endif
-
-#ifdef CONFIG_DEBUG_NSPIRE_CLASSIC_UART
-#define UART_SHIFT 2
-#include <asm/hardware/debug-8250.S>
-#endif
diff --git a/arch/arm/include/debug/picoxcell.S b/arch/arm/include/debug/picoxcell.S
deleted file mode 100644 (file)
index bc1f07c..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (c) 2011 Picochip Ltd., Jamie Iles
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-#define UART_SHIFT 2
-#define PICOXCELL_UART1_BASE           0x80230000
-#define PHYS_TO_IO(x)                  (((x) & 0x00ffffff) | 0xfe000000)
-
-               .macro  addruart, rp, rv, tmp
-               ldr     \rv, =PHYS_TO_IO(PICOXCELL_UART1_BASE)
-               ldr     \rp, =PICOXCELL_UART1_BASE
-               .endm
-
-#include "8250_32.S"
similarity index 78%
rename from arch/arm/include/asm/hardware/debug-pl01x.S
rename to arch/arm/include/debug/pl01x.S
index f9fd083eff630dd29b0710d603c11447919b9d54..37c6895b87e6d72ce5837e57a4bae0a367339cb2 100644 (file)
@@ -1,4 +1,4 @@
-/* arch/arm/include/asm/hardware/debug-pl01x.S
+/* arch/arm/include/debug/pl01x.S
  *
  * Debugging macro include header
  *
 */
 #include <linux/amba/serial.h>
 
+#ifdef CONFIG_DEBUG_UART_PHYS
+               .macro  addruart, rp, rv, tmp
+               ldr     \rp, =CONFIG_DEBUG_UART_PHYS
+               ldr     \rv, =CONFIG_DEBUG_UART_VIRT
+               .endm
+#endif
+
                .macro  senduart,rd,rx
                strb    \rd, [\rx, #UART01x_DR]
                .endm
diff --git a/arch/arm/include/debug/pxa.S b/arch/arm/include/debug/pxa.S
deleted file mode 100644 (file)
index e1e795a..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Early serial output macro for Marvell PXA/MMP SoC
- *
- * Copyright (C) 1994-1999 Russell King
- * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
- *
- * Copyright (C) 2013 Haojian Zhuang
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#if defined(CONFIG_DEBUG_PXA_UART1)
-#define PXA_UART_REG_PHYS_BASE 0x40100000
-#define PXA_UART_REG_VIRT_BASE 0xf2100000
-#elif defined(CONFIG_DEBUG_MMP_UART2)
-#define PXA_UART_REG_PHYS_BASE 0xd4017000
-#define PXA_UART_REG_VIRT_BASE 0xfe017000
-#elif defined(CONFIG_DEBUG_MMP_UART3)
-#define PXA_UART_REG_PHYS_BASE 0xd4018000
-#define PXA_UART_REG_VIRT_BASE 0xfe018000
-#else
-#error "Select uart for DEBUG_LL"
-#endif
-
-       .macro  addruart, rp, rv, tmp
-       ldr     \rp, =PXA_UART_REG_PHYS_BASE
-       ldr     \rv, =PXA_UART_REG_VIRT_BASE
-       .endm
-
-#define UART_SHIFT     2
-#include <asm/hardware/debug-8250.S>
diff --git a/arch/arm/include/debug/rockchip.S b/arch/arm/include/debug/rockchip.S
deleted file mode 100644 (file)
index cfd883e..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Early serial output macro for Rockchip SoCs
- *
- * Copyright (C) 2012 Maxime Ripard
- *
- * Maxime Ripard <maxime.ripard@free-electrons.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#if defined(CONFIG_DEBUG_RK29_UART0)
-#define ROCKCHIP_UART_DEBUG_PHYS_BASE 0x20060000
-#define ROCKCHIP_UART_DEBUG_VIRT_BASE 0xfed60000
-#elif defined(CONFIG_DEBUG_RK29_UART1)
-#define ROCKCHIP_UART_DEBUG_PHYS_BASE 0x20064000
-#define ROCKCHIP_UART_DEBUG_VIRT_BASE 0xfed64000
-#elif defined(CONFIG_DEBUG_RK29_UART2)
-#define ROCKCHIP_UART_DEBUG_PHYS_BASE 0x20068000
-#define ROCKCHIP_UART_DEBUG_VIRT_BASE 0xfed68000
-#elif defined(CONFIG_DEBUG_RK3X_UART0)
-#define ROCKCHIP_UART_DEBUG_PHYS_BASE 0x10124000
-#define ROCKCHIP_UART_DEBUG_VIRT_BASE 0xfeb24000
-#elif defined(CONFIG_DEBUG_RK3X_UART1)
-#define ROCKCHIP_UART_DEBUG_PHYS_BASE 0x10126000
-#define ROCKCHIP_UART_DEBUG_VIRT_BASE 0xfeb26000
-#elif defined(CONFIG_DEBUG_RK3X_UART2)
-#define ROCKCHIP_UART_DEBUG_PHYS_BASE 0x20064000
-#define ROCKCHIP_UART_DEBUG_VIRT_BASE 0xfed64000
-#elif defined(CONFIG_DEBUG_RK3X_UART3)
-#define ROCKCHIP_UART_DEBUG_PHYS_BASE 0x20068000
-#define ROCKCHIP_UART_DEBUG_VIRT_BASE 0xfed68000
-#endif
-
-       .macro  addruart, rp, rv, tmp
-       ldr     \rp, =ROCKCHIP_UART_DEBUG_PHYS_BASE
-       ldr     \rv, =ROCKCHIP_UART_DEBUG_VIRT_BASE
-       .endm
-
-#define UART_SHIFT     2
-#include <asm/hardware/debug-8250.S>
diff --git a/arch/arm/include/debug/socfpga.S b/arch/arm/include/debug/socfpga.S
deleted file mode 100644 (file)
index 966b2f9..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- *  Copyright (C) 1994-1999 Russell King
- *  Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#define UART_SHIFT 2
-#define DEBUG_LL_UART_OFFSET   0x00002000
-
-               .macro  addruart, rp, rv, tmp
-               mov     \rp, #DEBUG_LL_UART_OFFSET
-               orr     \rp, \rp, #0x00c00000
-               orr     \rv, \rp, #0xfe000000   @ virtual base
-               orr     \rp, \rp, #0xff000000   @ physical base
-               .endm
-
-#include "8250_32.S"
-
diff --git a/arch/arm/include/debug/sunxi.S b/arch/arm/include/debug/sunxi.S
deleted file mode 100644 (file)
index 04eb56d..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Early serial output macro for Allwinner A1X SoCs
- *
- * Copyright (C) 2012 Maxime Ripard
- *
- * Maxime Ripard <maxime.ripard@free-electrons.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#if defined(CONFIG_DEBUG_SUNXI_UART0)
-#define SUNXI_UART_DEBUG_PHYS_BASE 0x01c28000
-#define SUNXI_UART_DEBUG_VIRT_BASE 0xf1c28000
-#elif defined(CONFIG_DEBUG_SUNXI_UART1)
-#define SUNXI_UART_DEBUG_PHYS_BASE 0x01c28400
-#define SUNXI_UART_DEBUG_VIRT_BASE 0xf1c28400
-#endif
-
-       .macro  addruart, rp, rv, tmp
-       ldr     \rp, =SUNXI_UART_DEBUG_PHYS_BASE
-       ldr     \rv, =SUNXI_UART_DEBUG_VIRT_BASE
-       .endm
-
-#define UART_SHIFT     2
-#include <asm/hardware/debug-8250.S>
diff --git a/arch/arm/include/debug/u300.S b/arch/arm/include/debug/u300.S
deleted file mode 100644 (file)
index 6f04f08..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (C) 2006-2013 ST-Ericsson AB
- * License terms: GNU General Public License (GPL) version 2
- * Debugging macro include header.
- * Author: Linus Walleij <linus.walleij@stericsson.com>
- */
-#define U300_SLOW_PER_PHYS_BASE                0xc0010000
-#define U300_SLOW_PER_VIRT_BASE                0xff000000
-
-       .macro  addruart, rp, rv, tmp
-       /* If we move the address using MMU, use this. */
-       ldr     \rp,      = U300_SLOW_PER_PHYS_BASE @ MMU off, physical address
-       ldr     \rv,      = U300_SLOW_PER_VIRT_BASE @ MMU on, virtual address
-       orr     \rp, \rp, #0x00003000
-       orr     \rv, \rv, #0x00003000
-       .endm
-
-#include <asm/hardware/debug-pl01x.S>
index fbd24beeb1fad70886ea044387c873a65ef455e2..aa7f63a8b5e03a2ed550044e459f51e34fc611cc 100644 (file)
@@ -45,4 +45,4 @@
        ldr     \rv, =UART_VIRT_BASE            @ yes, virtual address
        .endm
 
-#include <asm/hardware/debug-pl01x.S>
+#include <debug/pl01x.S>
index acafb229e2b691d4a4a467a3f0a17aba37c21a5d..524acd5a223e618940f0e04785a70b5bf64084e8 100644 (file)
 
                .endm
 
-#include <asm/hardware/debug-pl01x.S>
-
-#elif defined(CONFIG_DEBUG_VEXPRESS_UART0_CA9)
-
-               .macro  addruart,rp,rv,tmp
-               mov     \rp, #DEBUG_LL_UART_OFFSET
-               orr     \rv, \rp, #DEBUG_LL_VIRT_BASE
-               orr     \rp, \rp, #DEBUG_LL_PHYS_BASE
-               .endm
-
-#include <asm/hardware/debug-pl01x.S>
-
-#elif defined(CONFIG_DEBUG_VEXPRESS_UART0_RS1)
-
-               .macro  addruart,rp,rv,tmp
-               mov     \rp, #DEBUG_LL_UART_OFFSET_RS1
-               orr     \rv, \rp, #DEBUG_LL_VIRT_BASE
-               orr     \rp, \rp, #DEBUG_LL_PHYS_BASE_RS1
-               .endm
-
-#include <asm/hardware/debug-pl01x.S>
-
-#elif defined(CONFIG_DEBUG_VEXPRESS_UART0_CRX)
-
-               .macro  addruart,rp,tmp,tmp2
-               ldr     \rp, =DEBUG_LL_UART_PHYS_CRX
-               .endm
-
-#include <asm/hardware/debug-pl01x.S>
-
-#else /* CONFIG_DEBUG_LL_UART_NONE */
-
-               .macro  addruart, rp, rv, tmp
-               /* Safe dummy values */
-               mov     \rp, #0
-               mov     \rv, #DEBUG_LL_VIRT_BASE
-               .endm
-
-               .macro  senduart,rd,rx
-               .endm
-
-               .macro  waituart,rd,rx
-               .endm
-
-               .macro  busyuart,rd,rx
-               .endm
-
+#include <debug/pl01x.S>
 #endif
index 47bcb2d254af8e4fdb3bacee96131d88a0e4f37e..18d76fd5a2afb2bf27b91980f29c77094e6638c0 100644 (file)
@@ -1,7 +1,6 @@
 # UAPI Header export list
 include include/uapi/asm-generic/Kbuild.asm
 
-header-y += a.out.h
 header-y += byteorder.h
 header-y += fcntl.h
 header-y += hwcap.h
diff --git a/arch/arm/include/uapi/asm/a.out.h b/arch/arm/include/uapi/asm/a.out.h
deleted file mode 100644 (file)
index 083894b..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef __ARM_A_OUT_H__
-#define __ARM_A_OUT_H__
-
-#include <linux/personality.h>
-#include <linux/types.h>
-
-struct exec
-{
-  __u32 a_info;                /* Use macros N_MAGIC, etc for access */
-  __u32 a_text;                /* length of text, in bytes */
-  __u32 a_data;                /* length of data, in bytes */
-  __u32 a_bss;         /* length of uninitialized data area for file, in bytes */
-  __u32 a_syms;                /* length of symbol table data in file, in bytes */
-  __u32 a_entry;       /* start address */
-  __u32 a_trsize;      /* length of relocation info for text, in bytes */
-  __u32 a_drsize;      /* length of relocation info for data, in bytes */
-};
-
-/*
- * This is always the same
- */
-#define N_TXTADDR(a)   (0x00008000)
-
-#define N_TRSIZE(a)    ((a).a_trsize)
-#define N_DRSIZE(a)    ((a).a_drsize)
-#define N_SYMSIZE(a)   ((a).a_syms)
-
-#define M_ARM 103
-
-#ifndef LIBRARY_START_TEXT
-#define LIBRARY_START_TEXT     (0x00c00000)
-#endif
-
-#endif /* __A_OUT_GNU_H__ */
index 9edc9692332d1a368a293f38e0a9543c2102a751..ec4164da6e3018737c42022bef16b3ed6bcea350 100644 (file)
@@ -7,9 +7,10 @@ static inline void save_atags(struct tag *tags) { }
 void convert_to_tag_list(struct tag *tags);
 
 #ifdef CONFIG_ATAGS
-struct machine_desc *setup_machine_tags(phys_addr_t __atags_pointer, unsigned int machine_nr);
+const struct machine_desc *setup_machine_tags(phys_addr_t __atags_pointer,
+       unsigned int machine_nr);
 #else
-static inline struct machine_desc *
+static inline const struct machine_desc *
 setup_machine_tags(phys_addr_t __atags_pointer, unsigned int machine_nr)
 {
        early_print("no ATAGS support: can't continue\n");
index 14512e6931d87957b718445dd25b31283315a222..8c14de8180c0af46fea1531261a7a276177a91a8 100644 (file)
@@ -178,11 +178,11 @@ static void __init squash_mem_tags(struct tag *tag)
                        tag->hdr.tag = ATAG_NONE;
 }
 
-struct machine_desc * __init setup_machine_tags(phys_addr_t __atags_pointer,
-                                               unsigned int machine_nr)
+const struct machine_desc * __init
+setup_machine_tags(phys_addr_t __atags_pointer, unsigned int machine_nr)
 {
        struct tag *tags = (struct tag *)&default_tags;
-       struct machine_desc *mdesc = NULL, *p;
+       const struct machine_desc *mdesc = NULL, *p;
        char *from = default_command_line;
 
        default_tags.mem.start = PHYS_OFFSET;
index 5859c8bc727c4254bc7e8fa254a4271d6b214242..eae1976f859dd6ffee3da4385163c4c5ddb21cc2 100644 (file)
@@ -176,10 +176,10 @@ void __init arm_dt_init_cpu_maps(void)
  * If a dtb was passed to the kernel in r2, then use it to choose the
  * correct machine_desc and to setup the system.
  */
-struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)
+const struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)
 {
        struct boot_param_header *devtree;
-       struct machine_desc *mdesc, *mdesc_best = NULL;
+       const struct machine_desc *mdesc, *mdesc_best = NULL;
        unsigned int score, mdesc_score = ~1;
        unsigned long dt_root;
        const char *model;
@@ -188,7 +188,7 @@ struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)
        DT_MACHINE_START(GENERIC_DT, "Generic DT based system")
        MACHINE_END
 
-       mdesc_best = (struct machine_desc *)&__mach_desc_GENERIC_DT;
+       mdesc_best = &__mach_desc_GENERIC_DT;
 #endif
 
        if (!dt_phys)
index e00621f1403f7c44765103591cbefd6e3315702f..52b26432c9a9941e8281a4483dd7aed148a99995 100644 (file)
@@ -49,7 +49,7 @@ __irq_entry:
        mov     r1, sp
        stmdb   sp!, {lr}
        @ routine called with r0 = irq number, r1 = struct pt_regs *
-       bl      nvic_do_IRQ
+       bl      nvic_handle_irq
 
        pop     {lr}
        @
index b361de143756d4a3412f4512d794eebc173e25e8..14235ba64a90736ecebad575f5d88ea4568e8eaf 100644 (file)
@@ -87,6 +87,7 @@ ENTRY(stext)
 ENDPROC(stext)
 
 #ifdef CONFIG_SMP
+       .text
 ENTRY(secondary_startup)
        /*
         * Common entry point for secondary CPUs.
index 9cf6063020ae99ce68afb617bf88905ec5f6212f..2c7cc1e03473aee9463e86d7dbedfc999f6e51f7 100644 (file)
@@ -343,6 +343,7 @@ __turn_mmu_on_loc:
        .long   __turn_mmu_on_end
 
 #if defined(CONFIG_SMP)
+       .text
 ENTRY(secondary_startup)
        /*
         * Common entry point for secondary CPUs.
index 4910232c48330d4dc857d6bf32754bfd781008b5..797b1a6a4906da0f8ca3f942186ac0e033250ce6 100644 (file)
@@ -56,8 +56,8 @@ ENTRY(__boot_cpu_mode)
        ldr     \reg3, [\reg2]
        ldr     \reg1, [\reg2, \reg3]
        cmp     \mode, \reg1            @ matches primary CPU boot mode?
-       orrne   r7, r7, #BOOT_CPU_MODE_MISMATCH
-       strne   r7, [r5, r6]            @ record what happened and give up
+       orrne   \reg1, \reg1, #BOOT_CPU_MODE_MISMATCH
+       strne   \reg1, [\reg2, \reg3]   @ record what happened and give up
        .endm
 
 #else  /* ZIMAGE */
index d3ca4f6915af746d5f13c4427cb42bacbd61b694..08b47ebd31440fc7d799dc55c4192552b8d498b1 100644 (file)
@@ -197,6 +197,7 @@ void machine_shutdown(void)
  */
 void machine_halt(void)
 {
+       local_irq_disable();
        smp_send_stop();
 
        local_irq_disable();
@@ -211,6 +212,7 @@ void machine_halt(void)
  */
 void machine_power_off(void)
 {
+       local_irq_disable();
        smp_send_stop();
 
        if (pm_power_off)
@@ -230,6 +232,7 @@ void machine_power_off(void)
  */
 void machine_restart(char *cmd)
 {
+       local_irq_disable();
        smp_send_stop();
 
        arm_pm_restart(reboot_mode, cmd);
index 63af9a7ae5124f82484feb8b33a88114b915753d..7b31e63da26d7782f9fb3b84cada0f89386c36a5 100644 (file)
@@ -72,10 +72,10 @@ static int __init fpe_setup(char *line)
 __setup("fpe=", fpe_setup);
 #endif
 
-extern void paging_init(struct machine_desc *desc);
+extern void paging_init(const struct machine_desc *desc);
 extern void sanity_check_meminfo(void);
 extern enum reboot_mode reboot_mode;
-extern void setup_dma_zone(struct machine_desc *desc);
+extern void setup_dma_zone(const struct machine_desc *desc);
 
 unsigned int processor_id;
 EXPORT_SYMBOL(processor_id);
@@ -139,7 +139,7 @@ EXPORT_SYMBOL(elf_platform);
 static const char *cpu_name;
 static const char *machine_name;
 static char __initdata cmd_line[COMMAND_LINE_SIZE];
-struct machine_desc *machine_desc __initdata;
+const struct machine_desc *machine_desc __initdata;
 
 static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } };
 #define ENDIANNESS ((char)endian_test.l)
@@ -607,7 +607,7 @@ static void __init setup_processor(void)
 
 void __init dump_machine_table(void)
 {
-       struct machine_desc *p;
+       const struct machine_desc *p;
 
        early_print("Available machine support:\n\nID (hex)\tNAME\n");
        for_each_machine_desc(p)
@@ -694,7 +694,7 @@ static int __init early_mem(char *p)
 }
 early_param("mem", early_mem);
 
-static void __init request_standard_resources(struct machine_desc *mdesc)
+static void __init request_standard_resources(const struct machine_desc *mdesc)
 {
        struct memblock_region *region;
        struct resource *res;
@@ -836,6 +836,8 @@ static int __init meminfo_cmp(const void *_a, const void *_b)
 void __init hyp_mode_check(void)
 {
 #ifdef CONFIG_ARM_VIRT_EXT
+       sync_boot_mode();
+
        if (is_hyp_mode_available()) {
                pr_info("CPU: All CPU(s) started in HYP mode.\n");
                pr_info("CPU: Virtualization extensions available.\n");
@@ -850,7 +852,7 @@ void __init hyp_mode_check(void)
 
 void __init setup_arch(char **cmdline_p)
 {
-       struct machine_desc *mdesc;
+       const struct machine_desc *mdesc;
 
        setup_processor();
        mdesc = setup_machine_fdt(__atags_pointer);
@@ -971,6 +973,7 @@ static const char *hwcap_str[] = {
        "vfpv4",
        "idiva",
        "idivt",
+       "vfpd32",
        "lpae",
        NULL
 };
index a98b62dca2faf9bbce7fbcb786d4c325513f7231..c2edfff573c2c9e2e68193cf729a98f460ac1a2d 100644 (file)
@@ -70,23 +70,6 @@ static inline void ipi_flush_bp_all(void *ignored)
        local_flush_bp_all();
 }
 
-#ifdef CONFIG_ARM_ERRATA_798181
-static int erratum_a15_798181(void)
-{
-       unsigned int midr = read_cpuid_id();
-
-       /* Cortex-A15 r0p0..r3p2 affected */
-       if ((midr & 0xff0ffff0) != 0x410fc0f0 || midr > 0x413fc0f2)
-               return 0;
-       return 1;
-}
-#else
-static int erratum_a15_798181(void)
-{
-       return 0;
-}
-#endif
-
 static void ipi_flush_tlb_a15_erratum(void *arg)
 {
        dmb();
index af72969820b4951448c9d95135383ae9d8387cde..aaf3a87311360d5c9db1531db9c3436af26237cd 100644 (file)
@@ -45,3 +45,9 @@ lib-$(CONFIG_ARCH_SHARK)      += io-shark.o
 
 $(obj)/csumpartialcopy.o:      $(obj)/csumpartialcopygeneric.S
 $(obj)/csumpartialcopyuser.o:  $(obj)/csumpartialcopygeneric.S
+
+ifeq ($(CONFIG_KERNEL_MODE_NEON),y)
+  NEON_FLAGS                   := -mfloat-abi=softfp -mfpu=neon
+  CFLAGS_xor-neon.o            += $(NEON_FLAGS)
+  lib-$(CONFIG_XOR_BLOCKS)     += xor-neon.o
+endif
diff --git a/arch/arm/lib/xor-neon.c b/arch/arm/lib/xor-neon.c
new file mode 100644 (file)
index 0000000..f485e5a
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * linux/arch/arm/lib/xor-neon.c
+ *
+ * Copyright (C) 2013 Linaro Ltd <ard.biesheuvel@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/raid/xor.h>
+
+#ifndef __ARM_NEON__
+#error You should compile this file with '-mfloat-abi=softfp -mfpu=neon'
+#endif
+
+/*
+ * Pull in the reference implementations while instructing GCC (through
+ * -ftree-vectorize) to attempt to exploit implicit parallelism and emit
+ * NEON instructions.
+ */
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
+#pragma GCC optimize "tree-vectorize"
+#else
+/*
+ * While older versions of GCC do not generate incorrect code, they fail to
+ * recognize the parallel nature of these functions, and emit plain ARM code,
+ * which is known to be slower than the optimized ARM code in asm-arm/xor.h.
+ */
+#warning This code requires at least version 4.6 of GCC
+#endif
+
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#include <asm-generic/xor.h>
+
+struct xor_block_template const xor_block_neon_inner = {
+       .name   = "__inner_neon__",
+       .do_2   = xor_8regs_2,
+       .do_3   = xor_8regs_3,
+       .do_4   = xor_8regs_4,
+       .do_5   = xor_8regs_5,
+};
index bea6793a7ede41cb04822303956d28347037460b..9f09f45835f822fe1a730d5992edda88fd7ce9d6 100644 (file)
@@ -1249,12 +1249,10 @@ static struct vpif_capture_config da850_vpif_capture_config = {
 
 static struct adv7343_platform_data adv7343_pdata = {
        .mode_config = {
-               .dac_3 = 1,
-               .dac_2 = 1,
-               .dac_1 = 1,
+               .dac = { 1, 1, 1 },
        },
        .sd_config = {
-               .sd_dac_out1 = 1,
+               .sd_dac_out = { 1 },
        },
 };
 
index 36aef3a7dedb074c5e036ee5f7af8ccec5053bcf..f1ac1c94ac0f363123842f4e9077c2bd58e645df 100644 (file)
@@ -65,7 +65,7 @@ static struct cpuidle_driver davinci_idle_driver = {
        .states[1]              = {
                .enter                  = davinci_enter_idle,
                .exit_latency           = 10,
-               .target_residency       = 100000,
+               .target_residency       = 10000,
                .flags                  = CPUIDLE_FLAG_TIME_VALID,
                .name                   = "DDR SR",
                .desc                   = "WFI and DDR Self Refresh",
diff --git a/arch/arm/mach-davinci/include/mach/debug-macro.S b/arch/arm/mach-davinci/include/mach/debug-macro.S
deleted file mode 100644 (file)
index b18b8eb..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Debugging macro for DaVinci
- *
- * Author: Kevin Hilman, MontaVista Software, Inc. <source@mvista.com>
- *
- * 2007 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-/* Modifications
- * Jan 2009    Chaithrika U S  Added senduart, busyuart, waituart
- *                             macros, based on debug-8250.S file
- *                             but using 32-bit accesses required for
- *                              some davinci devices.
- */
-
-#include <linux/serial_reg.h>
-
-#include <mach/serial.h>
-
-#define UART_SHIFT     2
-
-#if defined(CONFIG_DEBUG_DAVINCI_DMx_UART0)
-#define UART_BASE      DAVINCI_UART0_BASE
-#elif defined(CONFIG_DEBUG_DAVINCI_DA8XX_UART1)
-#define UART_BASE      DA8XX_UART1_BASE
-#elif defined(CONFIG_DEBUG_DAVINCI_DA8XX_UART2)
-#define UART_BASE      DA8XX_UART2_BASE
-#elif defined(CONFIG_DEBUG_DAVINCI_TNETV107X_UART1)
-#define UART_BASE      TNETV107X_UART2_BASE
-#define UART_VIRTBASE  TNETV107X_UART2_VIRT
-#else
-#error "Select a specifc port for DEBUG_LL"
-#endif
-
-#ifndef UART_VIRTBASE
-#define UART_VIRTBASE  IO_ADDRESS(UART_BASE)
-#endif
-
-               .macro addruart, rp, rv, tmp
-               ldr     \rp, =UART_BASE
-               ldr     \rv, =UART_VIRTBASE
-               .endm
-
-               .macro  senduart,rd,rx
-               str     \rd, [\rx, #UART_TX << UART_SHIFT]
-               .endm
-
-               .macro  busyuart,rd,rx
-1002:          ldr     \rd, [\rx, #UART_LSR << UART_SHIFT]
-               and     \rd, \rd, #UART_LSR_TEMT | UART_LSR_THRE
-               teq     \rd, #UART_LSR_TEMT | UART_LSR_THRE
-               bne     1002b
-               .endm
-
-               .macro  waituart,rd,rx
-#ifdef FLOW_CONTROL
-1001:          ldr     \rd, [\rx, #UART_MSR << UART_SHIFT]
-               tst     \rd, #UART_MSR_CTS
-               beq     1001b
-#endif
-               .endm
-
diff --git a/arch/arm/mach-dove/include/mach/debug-macro.S b/arch/arm/mach-dove/include/mach/debug-macro.S
deleted file mode 100644 (file)
index 5929cbc..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * arch/arm/mach-dove/include/mach/debug-macro.S
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <mach/bridge-regs.h>
-
-       .macro  addruart, rp, rv, tmp
-       ldr     \rp, =DOVE_SB_REGS_PHYS_BASE
-       ldr     \rv, =DOVE_SB_REGS_VIRT_BASE
-       orr     \rp, \rp, #0x00012000
-       orr     \rv, \rv, #0x00012000
-       .endm
-
-#define UART_SHIFT     2
-#include <asm/hardware/debug-8250.S>
diff --git a/arch/arm/mach-ebsa110/include/mach/debug-macro.S b/arch/arm/mach-ebsa110/include/mach/debug-macro.S
deleted file mode 100644 (file)
index bb02c05..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/* arch/arm/mach-ebsa110/include/mach/debug-macro.S
- *
- * Debugging macro include header
- *
- *  Copyright (C) 1994-1999 Russell King
- *  Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
-**/
-
-               .macro  addruart, rp, rv, tmp
-               mov     \rp, #0xf0000000
-               orr     \rp, \rp, #0x00000be0
-               mov     \rp, \rv
-               .endm
-
-#define UART_SHIFT     2
-#define FLOW_CONTROL
-#include <asm/hardware/debug-8250.S>
index fe3c1fa5462b72d0d44c5700ade01a816a696542..93e54fd4e3d55900192f62e573d6d97a2919aa4b 100644 (file)
@@ -194,20 +194,6 @@ config MACH_VISION_EP9307
          Say 'Y' here if you want your kernel to support the
          Vision Engraving Systems EP9307 SoM.
 
-choice
-       prompt "Select a UART for early kernel messages"
-
-config EP93XX_EARLY_UART1
-       bool "UART1"
-
-config EP93XX_EARLY_UART2
-       bool "UART2"
-
-config EP93XX_EARLY_UART3
-       bool "UART3"
-
-endchoice
-
 endmenu
 
 endif
diff --git a/arch/arm/mach-ep93xx/include/mach/debug-macro.S b/arch/arm/mach-ep93xx/include/mach/debug-macro.S
deleted file mode 100644 (file)
index af54e43..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * arch/arm/mach-ep93xx/include/mach/debug-macro.S
- * Debugging macro include header
- *
- * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- */
-#include <mach/ep93xx-regs.h>
-
-               .macro  addruart, rp, rv, tmp
-               ldr     \rp, =EP93XX_APB_PHYS_BASE      @ Physical base
-               ldr     \rv, =EP93XX_APB_VIRT_BASE      @ virtual base
-               orr     \rp, \rp, #0x000c0000
-               orr     \rv, \rv, #0x000c0000
-               .endm
-
-#include <asm/hardware/debug-pl01x.S>
index b5cc77d2380bd59c24c2da80a9995d45c2277f85..03c42e5400d2e70e75b7986b04d4a2eb8f387cab 100644 (file)
@@ -31,18 +31,8 @@ static void __raw_writel(unsigned int value, unsigned int ptr)
        *((volatile unsigned int *)ptr) = value;
 }
 
-#if defined(CONFIG_EP93XX_EARLY_UART1)
-#define UART_BASE              EP93XX_UART1_PHYS_BASE
-#elif defined(CONFIG_EP93XX_EARLY_UART2)
-#define UART_BASE              EP93XX_UART2_PHYS_BASE
-#elif defined(CONFIG_EP93XX_EARLY_UART3)
-#define UART_BASE              EP93XX_UART3_PHYS_BASE
-#else
-#define UART_BASE              EP93XX_UART1_PHYS_BASE
-#endif
-
-#define PHYS_UART_DATA         (UART_BASE + 0x00)
-#define PHYS_UART_FLAG         (UART_BASE + 0x18)
+#define PHYS_UART_DATA         (CONFIG_DEBUG_UART_PHYS + 0x00)
+#define PHYS_UART_FLAG         (CONFIG_DEBUG_UART_PHYS + 0x18)
 #define UART_FLAG_TXFF         0x20
 
 static inline void putc(int c)
index c169f0c99b2a323ad2f88ff0f9d20fac4579a064..02247f313e944237151e9fe656d68b4f8114ea7e 100644 (file)
 
 #include <asm/hardware/dec21285.h>
 
-#ifndef CONFIG_DEBUG_DC21285_PORT
-       /* For NetWinder debugging */
-               .macro  addruart, rp, rv, tmp
-               mov     \rp, #0x000003f8
-               orr     \rv, \rp, #0xfe000000   @ virtual
-               orr     \rv, \rv, #0x00e00000   @ virtual
-               orr     \rp, \rp, #0x7c000000   @ physical
-               .endm
-
-#define UART_SHIFT     0
-#define FLOW_CONTROL
-#include <asm/hardware/debug-8250.S>
-
-#else
 #include <mach/hardware.h>
        /* For EBSA285 debugging */
                .equ    dc21285_high, ARMCSR_BASE & 0xff000000
@@ -54,4 +40,3 @@
 
                .macro  waituart,rd,rx
                .endm
-#endif
diff --git a/arch/arm/mach-gemini/include/mach/debug-macro.S b/arch/arm/mach-gemini/include/mach/debug-macro.S
deleted file mode 100644 (file)
index 8376707..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Debugging macro include header
- *
- *  Copyright (C) 1994-1999 Russell King
- *  Copyright (C) 2001-2006 Storlink, Corp.
- *  Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <mach/hardware.h>
-
-       .macro  addruart, rp, rv, tmp
-       ldr     \rp, =GEMINI_UART_BASE                  @ physical
-       ldr     \rv, =IO_ADDRESS(GEMINI_UART_BASE)      @ virtual
-       .endm
-
-#define UART_SHIFT     2
-#define FLOW_CONTROL
-#include <asm/hardware/debug-8250.S>
diff --git a/arch/arm/mach-integrator/include/mach/debug-macro.S b/arch/arm/mach-integrator/include/mach/debug-macro.S
deleted file mode 100644 (file)
index 411b116..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/* arch/arm/mach-integrator/include/mach/debug-macro.S
- *
- * Debugging macro include header
- *
- *  Copyright (C) 1994-1999 Russell King
- *  Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
-*/
-
-               .macro  addruart, rp, rv, tmp
-               mov     \rp, #0x16000000        @ physical base address
-               mov     \rv, #0xf0000000        @ virtual base
-               add     \rv, \rv, #0x16000000 >> 4
-               .endm
-
-#include <asm/hardware/debug-pl01x.S>
diff --git a/arch/arm/mach-iop13xx/include/mach/debug-macro.S b/arch/arm/mach-iop13xx/include/mach/debug-macro.S
deleted file mode 100644 (file)
index d869a6f..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * arch/arm/mach-iop13xx/include/mach/debug-macro.S
- *
- * Debugging macro include header
- *
- * Copyright (C) 1994-1999 Russell King
- * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-       .macro  addruart, rp, rv, tmp
-       mov     \rp, #0x00002300
-       orr     \rp, \rp, #0x00000040
-       orr     \rv, \rp, #0xfe000000   @ virtual
-       orr     \rv, \rv, #0x00e80000
-       orr     \rp, \rp, #0xff000000   @ physical
-       orr     \rp, \rp, #0x00d80000
-       .endm
-
-#define UART_SHIFT     2
-#include <asm/hardware/debug-8250.S>
diff --git a/arch/arm/mach-iop32x/include/mach/debug-macro.S b/arch/arm/mach-iop32x/include/mach/debug-macro.S
deleted file mode 100644 (file)
index 363bdf9..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * arch/arm/mach-iop32x/include/mach/debug-macro.S
- *
- * Debugging macro include header
- *
- * Copyright (C) 1994-1999 Russell King
- * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-               .macro  addruart, rp, rv, tmp
-               mov     \rp, #0xfe000000        @ physical as well as virtual
-               orr     \rp, \rp, #0x00800000   @ location of the UART
-               mov     \rv, \rp
-               .endm
-
-#define UART_SHIFT     0
-#include <asm/hardware/debug-8250.S>
diff --git a/arch/arm/mach-iop33x/include/mach/debug-macro.S b/arch/arm/mach-iop33x/include/mach/debug-macro.S
deleted file mode 100644 (file)
index 361be1f..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * arch/arm/mach-iop33x/include/mach/debug-macro.S
- *
- * Debugging macro include header
- *
- * Copyright (C) 1994-1999 Russell King
- * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-               .macro  addruart, rp, rv, tmp
-               mov     \rp, #0x00ff0000
-               orr     \rp, \rp, #0x0000f700
-               orr     \rv, #0xfe000000        @ virtual
-               orr     \rp, #0xff000000        @ physical
-               .endm
-
-#define UART_SHIFT     2
-#include <asm/hardware/debug-8250.S>
diff --git a/arch/arm/mach-ixp4xx/include/mach/debug-macro.S b/arch/arm/mach-ixp4xx/include/mach/debug-macro.S
deleted file mode 100644 (file)
index ff686cb..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/* arch/arm/mach-ixp4xx/include/mach/debug-macro.S
- *
- * Debugging macro include header
- *
- *  Copyright (C) 1994-1999 Russell King
- *  Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-                .macro  addruart, rp, rv, tmp
-#ifdef __ARMEB__
-                mov     \rp, #3         @ Uart regs are at off set of 3 if
-                                       @ byte writes used - Big Endian.
-#else
-               mov     \rp, #0
-#endif
-               orr     \rv, \rp, #0xfe000000   @ virtual
-               orr     \rv, \rv, #0x00f00000
-                orr     \rp, \rp, #0xc8000000  @ physical
-                .endm
-
-#define UART_SHIFT     2
-#include <asm/hardware/debug-8250.S>
diff --git a/arch/arm/mach-kirkwood/include/mach/debug-macro.S b/arch/arm/mach-kirkwood/include/mach/debug-macro.S
deleted file mode 100644 (file)
index f785d40..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * arch/arm/mach-kirkwood/include/mach/debug-macro.S
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <mach/bridge-regs.h>
-
-       .macro  addruart, rp, rv, tmp
-       ldr     \rp, =KIRKWOOD_REGS_PHYS_BASE
-       ldr     \rv, =KIRKWOOD_REGS_VIRT_BASE
-       orr     \rp, \rp, #0x00012000
-       orr     \rv, \rv, #0x00012000
-       .endm
-
-#define UART_SHIFT     2
-#include <asm/hardware/debug-8250.S>
diff --git a/arch/arm/mach-lpc32xx/include/mach/debug-macro.S b/arch/arm/mach-lpc32xx/include/mach/debug-macro.S
deleted file mode 100644 (file)
index 351bd6c..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * arch/arm/mach-lpc32xx/include/mach/debug-macro.S
- *
- * Author: Kevin Wells <kevin.wells@nxp.com>
- *
- * Copyright (C) 2010 NXP Semiconductors
- *
- * 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.
- */
-
-/*
- * Debug output is hardcoded to standard UART 5
-*/
-
-       .macro  addruart, rp, rv, tmp
-       ldreq   \rp, =0x40090000
-       ldrne   \rv, =0xF4090000
-       .endm
-
-#define UART_SHIFT     2
-#include <asm/hardware/debug-8250.S>
diff --git a/arch/arm/mach-mv78xx0/include/mach/debug-macro.S b/arch/arm/mach-mv78xx0/include/mach/debug-macro.S
deleted file mode 100644 (file)
index a7df02b..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * arch/arm/mach-mv78xx0/include/mach/debug-macro.S
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <mach/mv78xx0.h>
-
-       .macro  addruart, rp, rv, tmp
-       ldr     \rp, =MV78XX0_REGS_PHYS_BASE
-       ldr     \rv, =MV78XX0_REGS_VIRT_BASE
-       orr     \rp, \rp, #0x00012000
-       orr     \rv, \rv, #0x00012000
-       .endm
-
-#define UART_SHIFT     2
-#include <asm/hardware/debug-8250.S>
diff --git a/arch/arm/mach-orion5x/include/mach/debug-macro.S b/arch/arm/mach-orion5x/include/mach/debug-macro.S
deleted file mode 100644 (file)
index f340ed8..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * arch/arm/mach-orion5x/include/mach/debug-macro.S
- *
- * Debugging macro include header
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <mach/orion5x.h>
-
-       .macro  addruart, rp, rv, tmp
-       ldr     \rp, =ORION5X_REGS_PHYS_BASE
-       ldr     \rv, =ORION5X_REGS_VIRT_BASE
-       orr     \rp, \rp, #0x00012000
-       orr     \rv, \rv, #0x00012000
-       .endm
-
-#define UART_SHIFT     2
-#include <asm/hardware/debug-8250.S>
diff --git a/arch/arm/mach-realview/include/mach/debug-macro.S b/arch/arm/mach-realview/include/mach/debug-macro.S
deleted file mode 100644 (file)
index 8cc372d..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/* arch/arm/mach-realview/include/mach/debug-macro.S
- *
- * Debugging macro include header
- *
- *  Copyright (C) 1994-1999 Russell King
- *  Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifdef CONFIG_DEBUG_REALVIEW_STD_PORT
-#define DEBUG_LL_UART_OFFSET   0x00009000
-#elif defined(CONFIG_DEBUG_REALVIEW_PB1176_PORT)
-#define DEBUG_LL_UART_OFFSET   0x0010c000
-#endif
-
-#ifndef DEBUG_LL_UART_OFFSET
-#error "Unknown RealView platform"
-#endif
-
-               .macro  addruart, rp, rv, tmp
-               mov     \rp, #DEBUG_LL_UART_OFFSET
-               orr     \rv, \rp, #0xfb000000   @ virtual base
-               orr     \rp, \rp, #0x10000000   @ physical base
-               .endm
-
-#include <asm/hardware/debug-pl01x.S>
diff --git a/arch/arm/mach-rpc/include/mach/debug-macro.S b/arch/arm/mach-rpc/include/mach/debug-macro.S
deleted file mode 100644 (file)
index 6d28cc9..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/* arch/arm/mach-rpc/include/mach/debug-macro.S
- *
- * Debugging macro include header
- *
- *  Copyright (C) 1994-1999 Russell King
- *  Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
-*/
-
-               .macro  addruart, rp, rv, tmp
-               mov     \rp, #0x00010000
-               orr     \rp, \rp, #0x00000fe0
-               orr     \rv, \rp, #0xe0000000   @ virtual
-               orr     \rp, \rp, #0x03000000   @ physical
-               .endm
-
-#define UART_SHIFT     2
-#define FLOW_CONTROL
-#include <asm/hardware/debug-8250.S>
diff --git a/arch/arm/mach-spear/include/mach/debug-macro.S b/arch/arm/mach-spear/include/mach/debug-macro.S
deleted file mode 100644 (file)
index 75b05ad..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * arch/arm/plat-spear/include/plat/debug-macro.S
- *
- * Debugging macro include header for spear platform
- *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#include <linux/amba/serial.h>
-#include <mach/spear.h>
-
-               .macro  addruart, rp, rv, tmp
-               mov     \rp, #SPEAR_DBG_UART_BASE               @ Physical base
-               mov     \rv, #VA_SPEAR_DBG_UART_BASE            @ Virtual base
-               .endm
-
-               .macro  senduart, rd, rx
-               strb    \rd, [\rx, #UART01x_DR]                 @ ASC_TX_BUFFER
-               .endm
-
-               .macro  waituart, rd, rx
-1001:          ldr     \rd, [\rx, #UART01x_FR]                 @ FLAG REGISTER
-               tst     \rd, #UART01x_FR_TXFF                   @ TX_FULL
-               bne     1001b
-               .endm
-
-               .macro  busyuart, rd, rx
-1002:          ldr     \rd, [\rx, #UART01x_FR]                 @ FLAG REGISTER
-               tst     \rd, #UART011_FR_TXFE                   @ TX_EMPTY
-               beq     1002b
-               .endm
index cf3a5369eeca0c79f52a4f52fd9aa783db8da21b..5cdc53d9b6533cc914471b2c09588e0d96210be5 100644 (file)
@@ -39,7 +39,6 @@
 
 /* Debug uart for linux, will be used for debug and uncompress messages */
 #define SPEAR_DBG_UART_BASE            SPEAR_ICM1_UART_BASE
-#define VA_SPEAR_DBG_UART_BASE         VA_SPEAR_ICM1_UART_BASE
 
 /* Sysctl base for spear platform */
 #define SPEAR_SYS_CTRL_BASE            SPEAR_ICM3_SYS_CTRL_BASE
@@ -86,7 +85,6 @@
 
 /* Debug uart for linux, will be used for debug and uncompress messages */
 #define SPEAR_DBG_UART_BASE                    UART_BASE
-#define VA_SPEAR_DBG_UART_BASE                 VA_UART_BASE
 
 #endif /* SPEAR13XX */
 
index bf9b6be5b18091bc3b94464f74502939b596ee40..fe1f3e26b88b114b2c47ecb082b358a6a220bea7 100644 (file)
@@ -4,7 +4,6 @@
 
 obj-y                          := cpu.o devices.o devices-common.o \
                                   id.o usb.o timer.o pm.o
-obj-$(CONFIG_CPU_IDLE)          += cpuidle.o
 obj-$(CONFIG_CACHE_L2X0)       += cache-l2x0.o
 obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o devices-db8500.o
 obj-$(CONFIG_MACH_MOP500)      += board-mop500.o board-mop500-sdi.o \
diff --git a/arch/arm/mach-versatile/include/mach/debug-macro.S b/arch/arm/mach-versatile/include/mach/debug-macro.S
deleted file mode 100644 (file)
index d0fbd7f..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/* arch/arm/mach-versatile/include/mach/debug-macro.S
- *
- * Debugging macro include header
- *
- *  Copyright (C) 1994-1999 Russell King
- *  Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
-*/
-
-               .macro  addruart, rp, rv, tmp
-               mov     \rp,      #0x001F0000
-               orr     \rp, \rp, #0x00001000
-               orr     \rv, \rp, #0xf1000000   @ virtual base
-               orr     \rp, \rp,  #0x10000000  @ physical base
-               .endm
-
-#include <asm/hardware/debug-pl01x.S>
index b55b1015724b56931c57ad7b2920d760b80529e8..4a0544492f10e4cd63d490f61d3cff3e54adbd19 100644 (file)
@@ -245,7 +245,8 @@ void check_and_switch_context(struct mm_struct *mm, struct task_struct *tsk)
        if (cpumask_test_and_clear_cpu(cpu, &tlb_flush_pending)) {
                local_flush_bp_all();
                local_flush_tlb_all();
-               dummy_flush_tlb_a15_erratum();
+               if (erratum_a15_798181())
+                       dummy_flush_tlb_a15_erratum();
        }
 
        atomic64_set(&per_cpu(active_asids, cpu), asid);
index 3d1e4a205b0b9325f0b8bc7bc231e735f06871e7..66781bf34077cb540a67f845eeeb919c2decfc4e 100644 (file)
  * of type casting from pmd_t * to pte_t *.
  */
 
-pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
-{
-       pgd_t *pgd;
-       pud_t *pud;
-       pmd_t *pmd = NULL;
-
-       pgd = pgd_offset(mm, addr);
-       if (pgd_present(*pgd)) {
-               pud = pud_offset(pgd, addr);
-               if (pud_present(*pud))
-                       pmd = pmd_offset(pud, addr);
-       }
-
-       return (pte_t *)pmd;
-}
-
 struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address,
                              int write)
 {
@@ -68,33 +52,6 @@ int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep)
        return 0;
 }
 
-pte_t *huge_pte_alloc(struct mm_struct *mm,
-                       unsigned long addr, unsigned long sz)
-{
-       pgd_t *pgd;
-       pud_t *pud;
-       pte_t *pte = NULL;
-
-       pgd = pgd_offset(mm, addr);
-       pud = pud_alloc(mm, pgd, addr);
-       if (pud)
-               pte = (pte_t *)pmd_alloc(mm, pud, addr);
-
-       return pte;
-}
-
-struct page *
-follow_huge_pmd(struct mm_struct *mm, unsigned long address,
-               pmd_t *pmd, int write)
-{
-       struct page *page;
-
-       page = pte_page(*(pte_t *)pmd);
-       if (page)
-               page += ((address & ~PMD_MASK) >> PAGE_SHIFT);
-       return page;
-}
-
 int pmd_huge(pmd_t pmd)
 {
        return pmd_val(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT);
index 15225d829d7173b6169076ad063a388ceefe1248..2958e74fc42c8f45444fca0a48f5f38856f32a73 100644 (file)
@@ -231,7 +231,7 @@ static void __init arm_adjust_dma_zone(unsigned long *size, unsigned long *hole,
 }
 #endif
 
-void __init setup_dma_zone(struct machine_desc *mdesc)
+void __init setup_dma_zone(const struct machine_desc *mdesc)
 {
 #ifdef CONFIG_ZONE_DMA
        if (mdesc->dma_zone_size) {
@@ -335,7 +335,8 @@ phys_addr_t __init arm_memblock_steal(phys_addr_t size, phys_addr_t align)
        return phys;
 }
 
-void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc)
+void __init arm_memblock_init(struct meminfo *mi,
+       const struct machine_desc *mdesc)
 {
        int i;
 
index 4f56617a2392d58e52f96582a3631c4c49a4f5f2..81878e943d0ab93b16a14f75ce9a057f12f20742 100644 (file)
@@ -989,6 +989,7 @@ phys_addr_t arm_lowmem_limit __initdata = 0;
 
 void __init sanity_check_meminfo(void)
 {
+       phys_addr_t memblock_limit = 0;
        int i, j, highmem = 0;
        phys_addr_t vmalloc_limit = __pa(vmalloc_min - 1) + 1;
 
@@ -1052,9 +1053,32 @@ void __init sanity_check_meminfo(void)
                        bank->size = size_limit;
                }
 #endif
-               if (!bank->highmem && bank->start + bank->size > arm_lowmem_limit)
-                       arm_lowmem_limit = bank->start + bank->size;
+               if (!bank->highmem) {
+                       phys_addr_t bank_end = bank->start + bank->size;
 
+                       if (bank_end > arm_lowmem_limit)
+                               arm_lowmem_limit = bank_end;
+
+                       /*
+                        * Find the first non-section-aligned page, and point
+                        * memblock_limit at it. This relies on rounding the
+                        * limit down to be section-aligned, which happens at
+                        * the end of this function.
+                        *
+                        * With this algorithm, the start or end of almost any
+                        * bank can be non-section-aligned. The only exception
+                        * is that the start of the bank 0 must be section-
+                        * aligned, since otherwise memory would need to be
+                        * allocated when mapping the start of bank 0, which
+                        * occurs before any free memory is mapped.
+                        */
+                       if (!memblock_limit) {
+                               if (!IS_ALIGNED(bank->start, SECTION_SIZE))
+                                       memblock_limit = bank->start;
+                               else if (!IS_ALIGNED(bank_end, SECTION_SIZE))
+                                       memblock_limit = bank_end;
+                       }
+               }
                j++;
        }
 #ifdef CONFIG_HIGHMEM
@@ -1079,7 +1103,18 @@ void __init sanity_check_meminfo(void)
 #endif
        meminfo.nr_banks = j;
        high_memory = __va(arm_lowmem_limit - 1) + 1;
-       memblock_set_current_limit(arm_lowmem_limit);
+
+       /*
+        * Round the memblock limit down to a section size.  This
+        * helps to ensure that we will allocate memory from the
+        * last full section, which should be mapped.
+        */
+       if (memblock_limit)
+               memblock_limit = round_down(memblock_limit, SECTION_SIZE);
+       if (!memblock_limit)
+               memblock_limit = arm_lowmem_limit;
+
+       memblock_set_current_limit(memblock_limit);
 }
 
 static inline void prepare_page_table(void)
@@ -1151,7 +1186,7 @@ void __init arm_mm_memblock_reserve(void)
  * called function.  This means you can't use any function or debugging
  * method which may touch any device, otherwise the kernel _will_ crash.
  */
-static void __init devicemaps_init(struct machine_desc *mdesc)
+static void __init devicemaps_init(const struct machine_desc *mdesc)
 {
        struct map_desc map;
        unsigned long addr;
@@ -1272,12 +1307,10 @@ static void __init map_lowmem(void)
  * paging_init() sets up the page tables, initialises the zone memory
  * maps, and sets up the zero page, bad page and bad page tables.
  */
-void __init paging_init(struct machine_desc *mdesc)
+void __init paging_init(const struct machine_desc *mdesc)
 {
        void *zero_page;
 
-       memblock_set_current_limit(arm_lowmem_limit);
-
        build_mem_type_table();
        prepare_page_table();
        map_lowmem();
index 1fa50100ab6af1f57067af8ff06c4a05d1fcb3ff..34d4ab217babb39b563e493cb4d4643963d33a64 100644 (file)
@@ -299,7 +299,7 @@ void __init sanity_check_meminfo(void)
  * paging_init() sets up the page tables, initialises the zone memory
  * maps, and sets up the zero page, bad page and bad page tables.
  */
-void __init paging_init(struct machine_desc *mdesc)
+void __init paging_init(const struct machine_desc *mdesc)
 {
        early_trap_init((void *)CONFIG_VECTORS_BASE);
        mpu_setup();
index f64afb9f1bd595a9fb1b9c0cd8bb442c9fda0337..bdd3be4be77aa50c93dcc20c8afdaa3af3c0cf5f 100644 (file)
@@ -110,7 +110,7 @@ ENTRY(cpu_v7_set_pte_ext)
  ARM(  str     r3, [r0, #2048]! )
  THUMB(        add     r0, r0, #2048 )
  THUMB(        str     r3, [r0] )
-       ALT_SMP(mov     pc,lr)
+       ALT_SMP(W(nop))
        ALT_UP (mcr     p15, 0, r0, c7, c10, 1)         @ flush_pte
 #endif
        mov     pc, lr
index c36ac69488c8fa60b17d91d085d1f8efcae42cb6..01a719e18bb047c655694c336d5a42e1388d1062 100644 (file)
@@ -81,7 +81,7 @@ ENTRY(cpu_v7_set_pte_ext)
        tst     r3, #1 << (55 - 32)             @ L_PTE_DIRTY
        orreq   r2, #L_PTE_RDONLY
 1:     strd    r2, r3, [r0]
-       ALT_SMP(mov     pc, lr)
+       ALT_SMP(W(nop))
        ALT_UP (mcr     p15, 0, r0, c7, c10, 1)         @ flush_pte
 #endif
        mov     pc, lr
index 5c6d5a3050eac65f1f2f89465d8398c971f866e4..73398bcf9bd8ea8d7293803828cb837306742fb7 100644 (file)
@@ -75,13 +75,14 @@ ENTRY(cpu_v7_do_idle)
 ENDPROC(cpu_v7_do_idle)
 
 ENTRY(cpu_v7_dcache_clean_area)
-       ALT_SMP(mov     pc, lr)                 @ MP extensions imply L1 PTW
-       ALT_UP(W(nop))
-       dcache_line_size r2, r3
-1:     mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
+       ALT_SMP(W(nop))                 @ MP extensions imply L1 PTW
+       ALT_UP_B(1f)
+       mov     pc, lr
+1:     dcache_line_size r2, r3
+2:     mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
        add     r0, r0, r2
        subs    r1, r1, r2
-       bhi     1b
+       bhi     2b
        dsb
        mov     pc, lr
 ENDPROC(cpu_v7_dcache_clean_area)
index 8d10dc8a1e17b34776a366f4b71fcca68c21bf8a..3e5d3115a2a6847ee41fc3d6d23ffde8fa0a7917 100644 (file)
 ENTRY(vfp_support_entry)
        DBGSTR3 "instr %08x pc %08x state %p", r0, r2, r10
 
+       ldr     r3, [sp, #S_PSR]        @ Neither lazy restore nor FP exceptions
+       and     r3, r3, #MODE_MASK      @ are supported in kernel mode
+       teq     r3, #USR_MODE
+       bne     vfp_kmode_exception     @ Returns through lr
+
        VFPFMRX r1, FPEXC               @ Is the VFP enabled?
        DBGSTR1 "fpexc %08x", r1
        tst     r1, #FPEXC_EN
index 5dfbb0b8e7f4484ddeb97974080a51bfaec0dc3e..52b8f40b1c73d48d206d497a6fadc381b5ddd888 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/init.h>
 #include <linux/uaccess.h>
 #include <linux/user.h>
+#include <linux/export.h>
 
 #include <asm/cp15.h>
 #include <asm/cputype.h>
@@ -648,6 +649,72 @@ static int vfp_hotplug(struct notifier_block *b, unsigned long action,
        return NOTIFY_OK;
 }
 
+void vfp_kmode_exception(void)
+{
+       /*
+        * If we reach this point, a floating point exception has been raised
+        * while running in kernel mode. If the NEON/VFP unit was enabled at the
+        * time, it means a VFP instruction has been issued that requires
+        * software assistance to complete, something which is not currently
+        * supported in kernel mode.
+        * If the NEON/VFP unit was disabled, and the location pointed to below
+        * is properly preceded by a call to kernel_neon_begin(), something has
+        * caused the task to be scheduled out and back in again. In this case,
+        * rebuilding and running with CONFIG_DEBUG_ATOMIC_SLEEP enabled should
+        * be helpful in localizing the problem.
+        */
+       if (fmrx(FPEXC) & FPEXC_EN)
+               pr_crit("BUG: unsupported FP instruction in kernel mode\n");
+       else
+               pr_crit("BUG: FP instruction issued in kernel mode with FP unit disabled\n");
+}
+
+#ifdef CONFIG_KERNEL_MODE_NEON
+
+/*
+ * Kernel-side NEON support functions
+ */
+void kernel_neon_begin(void)
+{
+       struct thread_info *thread = current_thread_info();
+       unsigned int cpu;
+       u32 fpexc;
+
+       /*
+        * Kernel mode NEON is only allowed outside of interrupt context
+        * with preemption disabled. This will make sure that the kernel
+        * mode NEON register contents never need to be preserved.
+        */
+       BUG_ON(in_interrupt());
+       cpu = get_cpu();
+
+       fpexc = fmrx(FPEXC) | FPEXC_EN;
+       fmxr(FPEXC, fpexc);
+
+       /*
+        * Save the userland NEON/VFP state. Under UP,
+        * the owner could be a task other than 'current'
+        */
+       if (vfp_state_in_hw(cpu, thread))
+               vfp_save_state(&thread->vfpstate, fpexc);
+#ifndef CONFIG_SMP
+       else if (vfp_current_hw_state[cpu] != NULL)
+               vfp_save_state(vfp_current_hw_state[cpu], fpexc);
+#endif
+       vfp_current_hw_state[cpu] = NULL;
+}
+EXPORT_SYMBOL(kernel_neon_begin);
+
+void kernel_neon_end(void)
+{
+       /* Disable the NEON/VFP unit. */
+       fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
+       put_cpu();
+}
+EXPORT_SYMBOL(kernel_neon_end);
+
+#endif /* CONFIG_KERNEL_MODE_NEON */
+
 /*
  * VFP support code initialisation.
  */
@@ -731,4 +798,4 @@ static int __init vfp_init(void)
        return 0;
 }
 
-late_initcall(vfp_init);
+core_initcall(vfp_init);
index f71c37edca263a88038199514995cf92d8b79d9e..c9770ba5c7df5c3b68c909c32db7fa2fb7be39f1 100644 (file)
@@ -172,7 +172,7 @@ static void __init xen_percpu_init(void *unused)
        enable_percpu_irq(xen_events_irq, 0);
 }
 
-static void xen_restart(char str, const char *cmd)
+static void xen_restart(enum reboot_mode reboot_mode, const char *cmd)
 {
        struct sched_shutdown r = { .reason = SHUTDOWN_reboot };
        int rc;
index 7f8759a8a92a08b8ed8e772d9f08c9d3404d8697..a68f3cf7c3c1bda0f3d02dc8d45672a4f3db0793 100644 (file)
@@ -1983,6 +1983,9 @@ at32_add_device_nand(unsigned int id, struct atmel_nand_data *data)
                                ARRAY_SIZE(smc_cs3_resource)))
                goto fail;
 
+       /* For at32ap7000, we use the reset workaround for nand driver */
+       data->need_reset_workaround = true;
+
        if (platform_device_add_data(pdev, data,
                                sizeof(struct atmel_nand_data)))
                goto fail;
index 3201ddb8da6a039d3fd56b3fa13969648a004d08..c699d32598728552d81159815d5ec356f40b76b1 100644 (file)
@@ -99,9 +99,6 @@ config ETRAX_KMALLOCED_MODULES
        help
          Enable module allocation with kmalloc instead of vmalloc.
 
-config OOM_REBOOT
-       bool "Enable reboot at out of memory"
-
 source "kernel/Kconfig.preempt"
 
 source mm/Kconfig
@@ -175,12 +172,6 @@ config ETRAX_FLASH_BUSWIDTH
        help
          Width in bytes of the NOR Flash bus (1, 2 or 4). Is usually 2.
 
-config ETRAX_NANDFLASH_BUSWIDTH
-       int "Buswidth of NAND flash in bytes"
-       default "1"
-       help
-         Width in bytes of the NAND flash (1 or 2).
-
 config ETRAX_FLASH1_SIZE
        int "FLASH1 size (dec, in MB. 0 = Unknown)"
        default "0"
@@ -272,38 +263,6 @@ config ETRAX_AXISFLASHMAP
          This option enables MTD mapping of flash devices.  Needed to use
          flash memories.  If unsure, say Y.
 
-config ETRAX_RTC
-       bool "Real Time Clock support"
-       depends on ETRAX_I2C
-       help
-         Enables drivers for the Real-Time Clock battery-backed chips on
-         some products. The kernel reads the time when booting, and
-         the date can be set using ioctl(fd, RTC_SET_TIME, &rt) with rt a
-         rtc_time struct (see <file:arch/cris/include/asm/rtc.h>) on the
-         /dev/rtc device.  You can check the time with cat /proc/rtc, but
-         normal time reading should be done using libc function time and
-         friends.
-
-choice
-       prompt "RTC chip"
-       depends on ETRAX_RTC
-       default ETRAX_DS1302
-
-config ETRAX_DS1302
-       depends on ETRAX_ARCH_V10
-       bool "DS1302"
-       help
-         Enables the driver for the DS1302 Real-Time Clock battery-backed
-         chip on some products.
-
-config ETRAX_PCF8563
-       bool "PCF8563"
-       help
-         Enables the driver for the PCF8563 Real-Time Clock battery-backed
-         chip on some products.
-
-endchoice
-
 config ETRAX_SYNCHRONOUS_SERIAL
        bool "Synchronous serial-port support"
        help
@@ -578,26 +537,6 @@ config ETRAX_SERIAL_PORT3_DMA5_IN
        depends on ETRAX_ARCH_V10
        bool "DMA 5"
 
-config ETRAX_SERIAL_PORT3_DMA9_IN
-       bool "Ser3 uses DMA9 for input"
-       depends on ETRAXFS
-       help
-         Enables the DMA9 input channel for ser3 (ttyS3).
-         If you do not enable DMA, an interrupt for each character will be
-         used when receiving data.
-         Normally you want to use DMA, unless you use the DMA channel for
-         something else.
-
-config ETRAX_SERIAL_PORT3_DMA3_IN
-       bool "Ser3 uses DMA3 for input"
-       depends on CRIS_MACH_ARTPEC3
-       help
-         Enables the DMA3 input channel for ser3 (ttyS3).
-         If you do not enable DMA, an interrupt for each character will be
-         used when receiving data.
-         Normally you want to use DMA, unless you use the DMA channel for
-         something else.
-
 endchoice
 
 choice
@@ -615,26 +554,6 @@ config ETRAX_SERIAL_PORT3_DMA4_OUT
        depends on ETRAX_ARCH_V10
        bool "DMA 4"
 
-config ETRAX_SERIAL_PORT3_DMA8_OUT
-       bool "Ser3 uses DMA8 for output"
-       depends on ETRAXFS
-       help
-         Enables the DMA8 output channel for ser3 (ttyS3).
-         If you do not enable DMA, an interrupt for each character will be
-         used when transmitting data.
-         Normally you want to use DMA, unless you use the DMA channel for
-         something else.
-
-config ETRAX_SERIAL_PORT3_DMA2_OUT
-       bool "Ser3 uses DMA2 for output"
-       depends on CRIS_MACH_ARTPEC3
-       help
-         Enables the DMA2 output channel for ser3 (ttyS3).
-         If you do not enable DMA, an interrupt for each character will be
-         used when transmitting data.
-         Normally you want to use DMA, unless you use the DMA channel for
-         something else.
-
 endchoice
 
 endmenu
index daf5f19b61a12bd54e23acd09a0db76132228993..239dab0b95c131034a8aaba771bcb53c833be3e9 100644 (file)
@@ -417,16 +417,6 @@ config ETRAX_USB_HOST
           for CTRL and BULK traffic only, INTR traffic may work as well
           however (depending on the requirements of timeliness).
 
-config ETRAX_USB_HOST_PORT1
-       bool "USB port 1 enabled"
-       depends on ETRAX_USB_HOST
-       default n
-
-config ETRAX_USB_HOST_PORT2
-       bool "USB port 2 enabled"
-       depends on ETRAX_USB_HOST
-       default n
-
 config ETRAX_PTABLE_SECTOR
        int "Byte-offset of partition table sector"
        depends on ETRAX_AXISFLASHMAP
@@ -527,19 +517,6 @@ config ETRAX_GPIO
          Remember that you need to setup the port directions appropriately in
          the General configuration.
 
-config ETRAX_PA_BUTTON_BITMASK
-       hex "PA-buttons bitmask"
-       depends on ETRAX_GPIO
-       default "02"
-       help
-         This is a bitmask with information about what bits on PA that
-         are used for buttons.
-         Most products has a so called TEST button on PA1, if that's true
-         use 02 here.
-         Use 00 if there are no buttons on PA.
-         If the bitmask is <> 00 a button driver will be included in the gpio
-         driver. ETRAX general I/O support must be enabled.
-
 config ETRAX_PA_CHANGEABLE_DIR
        hex "PA user changeable dir mask"
        depends on ETRAX_GPIO
@@ -580,51 +557,4 @@ config ETRAX_PB_CHANGEABLE_BITS
          Bit set = changeable.
          You probably want 00 here.
 
-config ETRAX_DS1302_RST_ON_GENERIC_PORT
-       bool "DS1302 RST on Generic Port"
-       depends on ETRAX_DS1302
-       help
-         If your product has the RST signal line for the DS1302 RTC on the
-         Generic Port then say Y here, otherwise leave it as N in which
-         case the RST signal line is assumed to be connected to Port PB
-         (just like the SCL and SDA lines).
-
-config ETRAX_DS1302_RSTBIT
-       int "DS1302 RST bit number"
-       depends on ETRAX_DS1302
-       default "2"
-       help
-         This is the bit number for the RST signal line of the DS1302 RTC on
-         the selected port. If you have selected the generic port then it
-         should be bit 27, otherwise your best bet is bit 5.
-
-config ETRAX_DS1302_SCLBIT
-       int "DS1302 SCL bit number"
-       depends on ETRAX_DS1302
-       default "1"
-       help
-         This is the bit number for the SCL signal line of the DS1302 RTC on
-         Port PB. This is probably best left at 3.
-
-config ETRAX_DS1302_SDABIT
-       int "DS1302 SDA bit number"
-       depends on ETRAX_DS1302
-       default "0"
-       help
-         This is the bit number for the SDA signal line of the DS1302 RTC on
-         Port PB. This is probably best left at 2.
-
-config ETRAX_DS1302_TRICKLE_CHARGE
-       int "DS1302 Trickle charger value"
-       depends on ETRAX_DS1302
-       default "0"
-       help
-         This controls the initial value of the trickle charge register.
-         0 = disabled (use this if you are unsure or have a non rechargeable battery)
-         Otherwise the following values can be OR:ed together to control the
-         charge current:
-         1 = 2kohm, 2 = 4kohm, 3 = 4kohm
-         4 = 1 diode, 8 = 2 diodes
-         Allowed values are (increasing current): 0, 11, 10, 9, 7, 6, 5
-
 endif
index 44bf2e88c26e49a7308bcec4df4da97297bfa6c7..e5c13183b97c99fd52ad454cf2dfd7593bcb6c7d 100644 (file)
@@ -6,7 +6,5 @@ obj-$(CONFIG_ETRAX_AXISFLASHMAP)        += axisflashmap.o
 obj-$(CONFIG_ETRAX_I2C)                        += i2c.o
 obj-$(CONFIG_ETRAX_I2C_EEPROM)         += eeprom.o
 obj-$(CONFIG_ETRAX_GPIO)               += gpio.o
-obj-$(CONFIG_ETRAX_DS1302)             += ds1302.o
-obj-$(CONFIG_ETRAX_PCF8563)            += pcf8563.o
 obj-$(CONFIG_ETRAX_SYNCHRONOUS_SERIAL) += sync_serial.o
 
index 1d866d3ee2f85329bfbd4b94130c6ccaf1035804..6792503aaf79effd5adfcf50591d0978de6c729c 100644 (file)
@@ -19,64 +19,6 @@ config ETRAX_NO_PHY
          switch. This option should normally be disabled. If enabled,
          speed and duplex will be locked to 100 Mbit and full duplex.
 
-config ETRAX_ETHERNET_IFACE0
-       depends on ETRAX_ETHERNET
-       bool "Enable network interface 0"
-
-config ETRAX_ETHERNET_IFACE1
-       depends on (ETRAX_ETHERNET && ETRAXFS)
-       bool "Enable network interface 1 (uses DMA6 and DMA7)"
-
-config ETRAX_ETHERNET_GBIT
-       depends on (ETRAX_ETHERNET && CRIS_MACH_ARTPEC3)
-       bool "Enable gigabit Ethernet support"
-
-choice
-       prompt "Eth0 led group"
-       depends on ETRAX_ETHERNET_IFACE0
-       default ETRAX_ETH0_USE_LEDGRP0
-
-config ETRAX_ETH0_USE_LEDGRP0
-       bool "Use LED grp 0"
-       depends on ETRAX_NBR_LED_GRP_ONE || ETRAX_NBR_LED_GRP_TWO
-       help
-         Use LED grp 0 for eth0
-
-config ETRAX_ETH0_USE_LEDGRP1
-       bool "Use LED grp 1"
-       depends on ETRAX_NBR_LED_GRP_TWO
-       help
-         Use LED grp 1 for eth0
-
-config ETRAX_ETH0_USE_LEDGRPNULL
-       bool "Use no LEDs for eth0"
-       help
-         Use no LEDs for eth0
-endchoice
-
-choice
-       prompt "Eth1 led group"
-       depends on ETRAX_ETHERNET_IFACE1
-       default ETRAX_ETH1_USE_LEDGRP1
-
-config ETRAX_ETH1_USE_LEDGRP0
-       bool "Use LED grp 0"
-       depends on ETRAX_NBR_LED_GRP_ONE || ETRAX_NBR_LED_GRP_TWO
-       help
-         Use LED grp 0 for eth1
-
-config ETRAX_ETH1_USE_LEDGRP1
-       bool "Use LED grp 1"
-       depends on ETRAX_NBR_LED_GRP_TWO
-       help
-         Use LED grp 1 for eth1
-
-config ETRAX_ETH1_USE_LEDGRPNULL
-       bool "Use no LEDs for eth1"
-       help
-         Use no LEDs for eth1
-endchoice
-
 config ETRAXFS_SERIAL
        bool "Serial-port support"
        depends on ETRAX_ARCH_V32
@@ -108,261 +50,24 @@ config ETRAX_SERIAL_PORT0
          if you do not need DMA to something else.
          ser0 can use dma4 or dma6 for output and dma5 or dma7 for input.
 
-choice
-       prompt "Ser0 default port type "
-       depends on ETRAX_SERIAL_PORT0
-       default ETRAX_SERIAL_PORT0_TYPE_232
-       help
-         Type of serial port.
-
-config ETRAX_SERIAL_PORT0_TYPE_232
-       bool "Ser0 is a RS-232 port"
-       help
-         Configure serial port 0 to be a RS-232 port.
-
-config ETRAX_SERIAL_PORT0_TYPE_485HD
-       bool "Ser0 is a half duplex RS-485 port"
-       depends on ETRAX_RS485
-       help
-         Configure serial port 0 to be a half duplex (two wires) RS-485 port.
-
-config ETRAX_SERIAL_PORT0_TYPE_485FD
-       bool "Ser0 is a full duplex RS-485 port"
-       depends on ETRAX_RS485
-       help
-         Configure serial port 0 to be a full duplex (four wires) RS-485 port.
-endchoice
-
-config ETRAX_SER0_DTR_BIT
-       string "Ser 0 DTR bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT0
-
-config ETRAX_SER0_RI_BIT
-       string "Ser 0 RI bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT0
-
-config ETRAX_SER0_DSR_BIT
-       string "Ser 0 DSR bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT0
-
-config ETRAX_SER0_CD_BIT
-       string "Ser 0 CD bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT0
-
 config ETRAX_SERIAL_PORT1
        bool "Serial port 1 enabled"
        depends on ETRAXFS_SERIAL
        help
          Enables the ETRAX FS serial driver for ser1 (ttyS1).
 
-choice
-       prompt "Ser1 default port type"
-       depends on ETRAX_SERIAL_PORT1
-       default ETRAX_SERIAL_PORT1_TYPE_232
-       help
-         Type of serial port.
-
-config ETRAX_SERIAL_PORT1_TYPE_232
-       bool "Ser1 is a RS-232 port"
-       help
-         Configure serial port 1 to be a RS-232 port.
-
-config ETRAX_SERIAL_PORT1_TYPE_485HD
-       bool "Ser1 is a half duplex RS-485 port"
-       depends on ETRAX_RS485
-       help
-         Configure serial port 1 to be a half duplex (two wires) RS-485 port.
-
-config ETRAX_SERIAL_PORT1_TYPE_485FD
-       bool "Ser1 is a full duplex RS-485 port"
-       depends on ETRAX_RS485
-       help
-         Configure serial port 1 to be a full duplex (four wires) RS-485 port.
-endchoice
-
-config ETRAX_SER1_DTR_BIT
-       string "Ser 1 DTR bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT1
-
-config ETRAX_SER1_RI_BIT
-       string "Ser 1 RI bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT1
-
-config ETRAX_SER1_DSR_BIT
-       string "Ser 1 DSR bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT1
-
-config ETRAX_SER1_CD_BIT
-       string "Ser 1 CD bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT1
-
 config ETRAX_SERIAL_PORT2
        bool "Serial port 2 enabled"
        depends on ETRAXFS_SERIAL
        help
          Enables the ETRAX FS serial driver for ser2 (ttyS2).
 
-choice
-       prompt "Ser2 default port type"
-       depends on ETRAX_SERIAL_PORT2
-       default ETRAX_SERIAL_PORT2_TYPE_232
-       help
-         What DMA channel to use for ser2
-
-config ETRAX_SERIAL_PORT2_TYPE_232
-       bool "Ser2 is a RS-232 port"
-       help
-         Configure serial port 2 to be a RS-232 port.
-
-config ETRAX_SERIAL_PORT2_TYPE_485HD
-       bool "Ser2 is a half duplex RS-485 port"
-       depends on ETRAX_RS485
-       help
-         Configure serial port 2 to be a half duplex (two wires) RS-485 port.
-
-config ETRAX_SERIAL_PORT2_TYPE_485FD
-       bool "Ser2 is a full duplex RS-485 port"
-       depends on ETRAX_RS485
-       help
-         Configure serial port 2 to be a full duplex (four wires) RS-485 port.
-endchoice
-
-
-config ETRAX_SER2_DTR_BIT
-       string "Ser 2 DTR bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT2
-
-config ETRAX_SER2_RI_BIT
-       string "Ser 2 RI bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT2
-
-config ETRAX_SER2_DSR_BIT
-       string "Ser 2 DSR bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT2
-
-config ETRAX_SER2_CD_BIT
-       string "Ser 2 CD bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT2
-
 config ETRAX_SERIAL_PORT3
        bool "Serial port 3 enabled"
        depends on ETRAXFS_SERIAL
        help
          Enables the ETRAX FS serial driver for ser3 (ttyS3).
 
-choice
-       prompt "Ser3 default port type"
-       depends on ETRAX_SERIAL_PORT3
-       default ETRAX_SERIAL_PORT3_TYPE_232
-       help
-         What DMA channel to use for ser3.
-
-config ETRAX_SERIAL_PORT3_TYPE_232
-       bool "Ser3 is a RS-232 port"
-       help
-         Configure serial port 3 to be a RS-232 port.
-
-config ETRAX_SERIAL_PORT3_TYPE_485HD
-       bool "Ser3 is a half duplex RS-485 port"
-       depends on ETRAX_RS485
-       help
-         Configure serial port 3 to be a half duplex (two wires) RS-485 port.
-
-config ETRAX_SERIAL_PORT3_TYPE_485FD
-       bool "Ser3 is a full duplex RS-485 port"
-       depends on ETRAX_RS485
-       help
-         Configure serial port 3 to be a full duplex (four wires) RS-485 port.
-endchoice
-
-config ETRAX_SER3_DTR_BIT
-       string "Ser 3 DTR bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT3
-
-config ETRAX_SER3_RI_BIT
-       string "Ser 3 RI bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT3
-
-config ETRAX_SER3_DSR_BIT
-       string "Ser 3 DSR bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT3
-
-config ETRAX_SER3_CD_BIT
-       string "Ser 3 CD bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT3
-
-config ETRAX_SERIAL_PORT4
-       bool "Serial port 4 enabled"
-       depends on ETRAXFS_SERIAL && CRIS_MACH_ARTPEC3
-       help
-         Enables the ETRAX FS serial driver for ser4 (ttyS4).
-
-choice
-       prompt "Ser4 default port type"
-       depends on ETRAX_SERIAL_PORT4
-       default ETRAX_SERIAL_PORT4_TYPE_232
-       help
-         What DMA channel to use for ser4.
-
-config ETRAX_SERIAL_PORT4_TYPE_232
-       bool "Ser4 is a RS-232 port"
-       help
-         Configure serial port 4 to be a RS-232 port.
-
-config ETRAX_SERIAL_PORT4_TYPE_485HD
-       bool "Ser4 is a half duplex RS-485 port"
-       depends on ETRAX_RS485
-       help
-         Configure serial port 4 to be a half duplex (two wires) RS-485 port.
-
-config ETRAX_SERIAL_PORT4_TYPE_485FD
-       bool "Ser4 is a full duplex RS-485 port"
-       depends on ETRAX_RS485
-       help
-         Configure serial port 4 to be a full duplex (four wires) RS-485 port.
-endchoice
-
-choice
-       prompt "Ser4 DMA in channel "
-       depends on ETRAX_SERIAL_PORT4
-       default ETRAX_SERIAL_PORT4_NO_DMA_IN
-       help
-         What DMA channel to use for ser4.
-
-
-config ETRAX_SERIAL_PORT4_NO_DMA_IN
-       bool "Ser4 uses no DMA for input"
-       help
-         Do not use DMA for ser4 input.
-
-config ETRAX_SERIAL_PORT4_DMA9_IN
-       bool "Ser4 uses DMA9 for input"
-       depends on ETRAX_SERIAL_PORT4
-       help
-         Enables the DMA9 input channel for ser4 (ttyS4).
-         If you do not enable DMA, an interrupt for each character will be
-         used when receiving data.
-         Normally you want to use DMA, unless you use the DMA channel for
-         something else.
-
-endchoice
-
-config ETRAX_SER4_DTR_BIT
-       string "Ser 4 DTR bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT4
-
-config ETRAX_SER4_RI_BIT
-       string "Ser 4 RI bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT4
-
-config ETRAX_SER4_DSR_BIT
-       string "Ser 4 DSR bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT4
-
-config ETRAX_SER4_CD_BIT
-       string "Ser 4 CD bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT4
-
 config ETRAX_SYNCHRONOUS_SERIAL
        bool "Synchronous serial-port support"
        depends on ETRAX_ARCH_V32
@@ -703,32 +408,6 @@ config ETRAX_SPI_SSER0
          want to build it as a module, which will be named spi_crisv32_sser.
          (You need to select MMC separately.)
 
-config ETRAX_SPI_SSER0_DMA
-       bool "DMA for SPI on sser0 enabled"
-       depends on ETRAX_SPI_SSER0
-       depends on !ETRAX_SERIAL_PORT1_DMA4_OUT && !ETRAX_SERIAL_PORT1_DMA5_IN
-       default y
-       help
-         Say Y if using DMA (dma4/dma5) for SPI on synchronous serial port 0.
-
-config ETRAX_SPI_MMC_CD_SSER0_PIN
-       string "MMC/SD card detect pin for SPI on sser0"
-       depends on ETRAX_SPI_SSER0 && MMC_SPI
-       default "pd11"
-       help
-         The pin to use for SD/MMC card detect.  This pin should be pulled up
-         and grounded when a card is present.  If defined as " " (space), no
-         pin is selected.  A card must then always be inserted for proper
-         action.
-
-config ETRAX_SPI_MMC_WP_SSER0_PIN
-       string "MMC/SD card write-protect pin for SPI on sser0"
-       depends on ETRAX_SPI_SSER0 && MMC_SPI
-       default "pd10"
-       help
-         The pin to use for the SD/MMC write-protect signal for a memory
-         card.  If defined as " " (space), the card is considered writable.
-
 config ETRAX_SPI_SSER1
        tristate "SPI using synchronous serial port 1 (sser1)"
        depends on ETRAX_SPI_MMC
@@ -742,32 +421,6 @@ config ETRAX_SPI_SSER1
          want to build it as a module, which will be named spi_crisv32_sser.
          (You need to select MMC separately.)
 
-config ETRAX_SPI_SSER1_DMA
-       bool "DMA for SPI on sser1 enabled"
-       depends on ETRAX_SPI_SSER1 && !ETRAX_ETHERNET_IFACE1
-       depends on !ETRAX_SERIAL_PORT0_DMA6_OUT && !ETRAX_SERIAL_PORT0_DMA7_IN
-       default y
-       help
-         Say Y if using DMA (dma6/dma7) for SPI on synchronous serial port 1.
-
-config ETRAX_SPI_MMC_CD_SSER1_PIN
-       string "MMC/SD card detect pin for SPI on sser1"
-       depends on ETRAX_SPI_SSER1 && MMC_SPI
-       default "pd12"
-       help
-         The pin to use for SD/MMC card detect.  This pin should be pulled up
-         and grounded when a card is present.  If defined as " " (space), no
-         pin is selected.  A card must then always be inserted for proper
-         action.
-
-config ETRAX_SPI_MMC_WP_SSER1_PIN
-       string "MMC/SD card write-protect pin for SPI on sser1"
-       depends on ETRAX_SPI_SSER1 && MMC_SPI
-       default "pd9"
-       help
-         The pin to use for the SD/MMC write-protect signal for a memory
-         card.  If defined as " " (space), the card is considered writable.
-
 config ETRAX_SPI_GPIO
        tristate "Bitbanged SPI using gpio pins"
        depends on ETRAX_SPI_MMC
@@ -782,51 +435,4 @@ config ETRAX_SPI_GPIO
          Say m to build it as a module, which will be called spi_crisv32_gpio.
          (You need to select MMC separately.)
 
-# The default match that of sser0, only because that's how it was tested.
-config ETRAX_SPI_CS_PIN
-       string "SPI chip select pin"
-       depends on ETRAX_SPI_GPIO
-       default "pc3"
-       help
-         The pin to use for SPI chip select.
-
-config ETRAX_SPI_CLK_PIN
-       string "SPI clock pin"
-       depends on ETRAX_SPI_GPIO
-       default "pc1"
-       help
-         The pin to use for the SPI clock.
-
-config ETRAX_SPI_DATAIN_PIN
-       string "SPI MISO (data in) pin"
-       depends on ETRAX_SPI_GPIO
-       default "pc16"
-       help
-         The pin to use for SPI data in from the device.
-
-config ETRAX_SPI_DATAOUT_PIN
-       string "SPI MOSI (data out) pin"
-       depends on ETRAX_SPI_GPIO
-       default "pc0"
-       help
-         The pin to use for SPI data out to the device.
-
-config ETRAX_SPI_MMC_CD_GPIO_PIN
-       string "MMC/SD card detect pin for SPI using gpio (space for none)"
-       depends on ETRAX_SPI_GPIO && MMC_SPI
-       default "pd11"
-       help
-         The pin to use for SD/MMC card detect.  This pin should be pulled up
-         and grounded when a card is present.  If defined as " " (space), no
-         pin is selected.  A card must then always be inserted for proper
-         action.
-
-config ETRAX_SPI_MMC_WP_GPIO_PIN
-       string "MMC/SD card write-protect pin for SPI using gpio (space for none)"
-       depends on ETRAX_SPI_GPIO && MMC_SPI
-       default "pd10"
-       help
-         The pin to use for the SD/MMC write-protect signal for a memory
-         card.  If defined as " " (space), the card is considered writable.
-
 endif
index 7796aafc711e6582f006089c86d42ef6592dbcf4..87547271a595fca051e42e998a19f853a50a1a8f 100644 (file)
@@ -15,10 +15,6 @@ config ETRAX_SERIAL_PORTS
        int
        default 5
 
-config ETRAX_DDR
-       bool
-       default y
-
 config ETRAX_DDR2_MRS
        hex "DDR2 MRS"
        default "0"
index c0a29b96b92b032fdcdddb47702e3383724781e8..15b815df29c165809c4e6e229ede6a077d9e8e71 100644 (file)
@@ -47,7 +47,6 @@ struct task_struct;
  */
 
 #define task_pt_regs(task) user_regs(task_thread_info(task))
-#define current_regs() task_pt_regs(current)
 
 unsigned long get_wchan(struct task_struct *p);
 
diff --git a/arch/cris/include/uapi/asm/kvm_para.h b/arch/cris/include/uapi/asm/kvm_para.h
new file mode 100644 (file)
index 0000000..14fab8f
--- /dev/null
@@ -0,0 +1 @@
+#include <asm-generic/kvm_para.h>
index 0aa35f0eb0dbfa0cc5fc34c443645ae484c68dc3..deb67843693cddbf94ce2c2044999730a9425845 100644 (file)
@@ -320,7 +320,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases);
  *  are examined.
  */
 
-void __init pcibios_fixup_bus(struct pci_bus *bus)
+void pcibios_fixup_bus(struct pci_bus *bus)
 {
 #if 0
        printk("### PCIBIOS_FIXUP_BUS(%d)\n",bus->number);
index 7913695b2fcbe5605830b9e1da6441188a591b8b..9a21142630f6ac0b57bd884cfe7760553b81fdbd 100644 (file)
@@ -31,8 +31,8 @@ CONFIG_ACPI_FAN=m
 CONFIG_ACPI_DOCK=y
 CONFIG_ACPI_PROCESSOR=m
 CONFIG_ACPI_CONTAINER=m
-CONFIG_HOTPLUG_PCI=m
-CONFIG_HOTPLUG_PCI_ACPI=m
+CONFIG_HOTPLUG_PCI=y
+CONFIG_HOTPLUG_PCI_ACPI=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
 CONFIG_INET=y
index f8e91336542392236c878276ad8abcef4d786166..ea42ec525d48b9cd7a47f821e640124ff8aa8049 100644 (file)
@@ -25,8 +25,8 @@ CONFIG_ACPI_BUTTON=m
 CONFIG_ACPI_FAN=m
 CONFIG_ACPI_PROCESSOR=m
 CONFIG_ACPI_CONTAINER=m
-CONFIG_HOTPLUG_PCI=m
-CONFIG_HOTPLUG_PCI_ACPI=m
+CONFIG_HOTPLUG_PCI=y
+CONFIG_HOTPLUG_PCI_ACPI=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
 CONFIG_INET=y
index a5a9e02e60a05c94e9b9a4c6c35a6cf78eecf429..0e983435f1133f0a600c3853c24638bd71744b58 100644 (file)
@@ -31,8 +31,8 @@ CONFIG_ACPI_BUTTON=m
 CONFIG_ACPI_FAN=m
 CONFIG_ACPI_PROCESSOR=m
 CONFIG_ACPI_CONTAINER=m
-CONFIG_HOTPLUG_PCI=m
-CONFIG_HOTPLUG_PCI_ACPI=m
+CONFIG_HOTPLUG_PCI=y
+CONFIG_HOTPLUG_PCI_ACPI=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
 CONFIG_INET=y
index 37b9b422caadf9c89196aa63781d9cdb2a05830d..8baf2e6f126b1545ceafe32a2d95f5246f9d3aae 100644 (file)
@@ -32,8 +32,8 @@ CONFIG_ACPI_BUTTON=m
 CONFIG_ACPI_FAN=m
 CONFIG_ACPI_PROCESSOR=m
 CONFIG_ACPI_CONTAINER=m
-CONFIG_HOTPLUG_PCI=m
-CONFIG_HOTPLUG_PCI_ACPI=m
+CONFIG_HOTPLUG_PCI=y
+CONFIG_HOTPLUG_PCI_ACPI=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
 CONFIG_INET=y
index 1ed4c8fedb8370e7b8403e36244b2fce043e0aae..185d3d18d0ec08d8319a317432074de0a8abca54 100644 (file)
@@ -7,6 +7,6 @@
 /* Use normal IO mappings for DMI */
 #define dmi_ioremap ioremap
 #define dmi_iounmap(x,l) iounmap(x)
-#define dmi_alloc(l) kmalloc(l, GFP_ATOMIC)
+#define dmi_alloc(l) kzalloc(l, GFP_ATOMIC)
 
 #endif
index bac1639bc3207acf97192e3300e6a961eca10fa7..314458b9933a1f895975a468328e6a1e92f234c0 100644 (file)
@@ -11,8 +11,7 @@ Elf64_Half elf_core_extra_phdrs(void)
        return GATE_EHDR->e_phnum;
 }
 
-int elf_core_write_extra_phdrs(struct file *file, loff_t offset, size_t *size,
-                              unsigned long limit)
+int elf_core_write_extra_phdrs(struct coredump_params *cprm, loff_t offset)
 {
        const struct elf_phdr *const gate_phdrs =
                (const struct elf_phdr *) (GATE_ADDR + GATE_EHDR->e_phoff);
@@ -35,15 +34,13 @@ int elf_core_write_extra_phdrs(struct file *file, loff_t offset, size_t *size,
                        phdr.p_offset += ofs;
                }
                phdr.p_paddr = 0; /* match other core phdrs */
-               *size += sizeof(phdr);
-               if (*size > limit || !dump_write(file, &phdr, sizeof(phdr)))
+               if (!dump_emit(cprm, &phdr, sizeof(phdr)))
                        return 0;
        }
        return 1;
 }
 
-int elf_core_write_extra_data(struct file *file, size_t *size,
-                             unsigned long limit)
+int elf_core_write_extra_data(struct coredump_params *cprm)
 {
        const struct elf_phdr *const gate_phdrs =
                (const struct elf_phdr *) (GATE_ADDR + GATE_EHDR->e_phoff);
@@ -53,9 +50,7 @@ int elf_core_write_extra_data(struct file *file, size_t *size,
                if (gate_phdrs[i].p_type == PT_LOAD) {
                        void *addr = (void *)gate_phdrs[i].p_vaddr;
                        size_t memsz = PAGE_ALIGN(gate_phdrs[i].p_memsz);
-
-                       *size += memsz;
-                       if (*size > limit || !dump_write(file, addr, memsz))
+                       if (!dump_emit(cprm, addr, memsz))
                                return 0;
                        break;
                }
index 911ba472e6c4abbd83dac862a561d98eb22526aa..5b16f5d61b44cb4f2cbcb7372d4f98061bef6da0 100644 (file)
@@ -118,7 +118,7 @@ void (*mach_power_off)(void);
  *
  * Returns:
  */
-void parse_uboot_commandline(char *commandp, int size)
+static void __init parse_uboot_commandline(char *commandp, int size)
 {
        extern unsigned long _init_sp;
        unsigned long *sp;
index 2a16df3d931283f0f55ac4c95571dbe3629678c3..57fd286e4b0b410fe93cb0596c93488afa8b4b4e 100644 (file)
@@ -50,6 +50,7 @@
 #include <asm/pgtable.h>
 #include <asm/traps.h>
 #include <asm/ucontext.h>
+#include <asm/cacheflush.h>
 
 #ifdef CONFIG_MMU
 
@@ -181,6 +182,13 @@ static inline void push_cache (unsigned long vaddr)
                asm volatile ("movec %0,%%caar\n\t"
                              "movec %1,%%cacr"
                              : : "r" (vaddr + 4), "r" (temp));
+       } else {
+               /* CPU_IS_COLDFIRE */
+#if defined(CONFIG_CACHE_COPYBACK)
+               flush_cf_dcache(0, DCACHE_MAX_ADDR);
+#endif
+               /* Invalidate instruction cache for the pushed bytes */
+               clear_cf_icache(vaddr, vaddr + 8);
        }
 }
 
index a86eb66835aaaf11b7125960987a44ea9c84941d..e53caf4c3bfbf9d141e1f49857ce08f8da785cc2 100644 (file)
@@ -15,6 +15,7 @@
 
 /***************************************************************************/
 
+#include <linux/init.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/rtc.h>
@@ -42,7 +43,7 @@ void m68328_reset (void)
 
 /***************************************************************************/
 
-void config_BSP(char *command, int len)
+void __init config_BSP(char *command, int len)
 {
   printk(KERN_INFO "\n68328 support D. Jeff Dionne <jeff@uclinux.org>\n");
   printk(KERN_INFO "68328 support Kenneth Albanowski <kjahds@kjshds.com>\n");
index a6eb72d750084f9a19dae6a6d43a80724a8a9d7f..332b5e8605fcdf2d81772babc7b54bde55dd802d 100644 (file)
@@ -13,6 +13,7 @@
 
 /***************************************************************************/
 
+#include <linux/init.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/rtc.h>
@@ -52,7 +53,7 @@ _bsc1(unsigned char *, gethwaddr, int, a)
 _bsc1(char *, getbenv, char *, a)
 #endif
 
-void config_BSP(char *command, int len)
+void __init config_BSP(char *command, int len)
 {
   unsigned char *p;
 
index eb6964fbec09a7f703702b2f8219d5c27f85e564..fd6658358af1aa00c95848bf62f7aed8cf8d15c6 100644 (file)
@@ -14,6 +14,7 @@
 
 /***************************************************************************/
 
+#include <linux/init.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/kd.h>
@@ -59,7 +60,7 @@ static void m68vz328_reset(void)
        );
 }
 
-static void init_hardware(char *command, int size)
+static void __init init_hardware(char *command, int size)
 {
 #ifdef CONFIG_DIRECT_IO_ACCESS
        SCR = 0x10;                                     /* allow user access to internal registers */
@@ -145,7 +146,7 @@ _bsc0(char *, getserialnum)
 _bsc1(unsigned char *, gethwaddr, int, a)
 _bsc1(char *, getbenv, char *, a)
 
-static void init_hardware(char *command, int size)
+static void __init init_hardware(char *command, int size)
 {
        char *p;
 
@@ -167,7 +168,7 @@ static void m68vz328_reset(void)
 {
 }
 
-static void init_hardware(char *command, int size)
+static void __init init_hardware(char *command, int size)
 {
 }
 
@@ -175,7 +176,7 @@ static void init_hardware(char *command, int size)
 #endif
 /***************************************************************************/
 
-void config_BSP(char *command, int size)
+void __init config_BSP(char *command, int size)
 {
        printk(KERN_INFO "68VZ328 DragonBallVZ support (c) 2001 Lineo, Inc.\n");
 
index 8e4e10cc00803387b8386afdb0fe8c655f37a356..315727b7ff40f4170cc05e5d432bd4542dd1102f 100644 (file)
@@ -31,6 +31,7 @@
  */
 
 #include <linux/errno.h>
+#include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/param.h>
@@ -77,7 +78,7 @@ void m360_cpm_reset(void);
 
 
 
-void m360_cpm_reset()
+void __init m360_cpm_reset()
 {
 /*     pte_t              *pte; */
 
index 9877cefad1e7640dd27622410c04f882acdb37e3..0570741e5500b221003e3295f4596673cfa53b4b 100644 (file)
@@ -11,6 +11,7 @@
  */
 
 #include <stdarg.h>
+#include <linux/init.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
@@ -140,7 +141,7 @@ _bsc1(char *, getbenv, char *, a)
 #endif
 
 
-void config_BSP(char *command, int len)
+void __init config_BSP(char *command, int len)
 {
   unsigned char *p;
 
index 2a3c860c75250c15bc5bcf8c4c9532aa2772e2de..973640f46752f0247c75de8f5940c3005b23841b 100644 (file)
@@ -16,6 +16,8 @@ config META21_FPGA
 
 config SOC_TZ1090
        bool "Toumaz Xenif TZ1090 SoC (Comet)"
+       select ARCH_WANT_OPTIONAL_GPIOLIB
+       select IMGPDC_IRQ
        select METAG_LNKGET_AROUND_CACHE
        select METAG_META21
        select METAG_SMP_WRITE_REORDERING
index 853744652b93460875cc9a36caf2fad3fc3953b5..24ea7d2e9138032c713088e70f5175cfa26155a4 100644 (file)
@@ -8,6 +8,8 @@
 
 #include "skeleton.dtsi"
 
+#include <dt-bindings/interrupt-controller/irq.h>
+
 / {
        compatible = "toumaz,tz1090", "img,meta";
 
                #size-cells = <1>;
                ranges;
 
+               pdc: pdc@0x02006000 {
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+
+                       reg = <0x02006000 0x1000>;
+                       compatible = "img,pdc-intc";
+
+                       num-perips = <3>;
+                       num-syswakes = <3>;
+
+                       interrupts = <18 IRQ_TYPE_LEVEL_HIGH>, /* Syswakes */
+                                    <30 IRQ_TYPE_LEVEL_HIGH>, /* Perip 0 (RTC) */
+                                    <29 IRQ_TYPE_LEVEL_HIGH>, /* Perip 1 (IR) */
+                                    <31 IRQ_TYPE_LEVEL_HIGH>; /* Perip 2 (WDT) */
+               };
+
                pinctrl: pinctrl@02005800 {
                        #gpio-range-cells = <3>;
                        compatible = "img,tz1090-pinctrl";
                        compatible = "img,tz1090-pdc-pinctrl";
                        reg = <0x02006500 0x100>;
                };
+
+               gpios: gpios@02005800 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "img,tz1090-gpio";
+                       reg = <0x02005800 0x90>;
+
+                       gpios0: bank@0 {
+                               gpio-controller;
+                               interrupt-controller;
+                               #gpio-cells = <2>;
+                               #interrupt-cells = <2>;
+                               reg = <0>;
+                               interrupts = <13 IRQ_TYPE_LEVEL_HIGH>;
+                               gpio-ranges = <&pinctrl 0 0 30>;
+                       };
+                       gpios1: bank@1 {
+                               gpio-controller;
+                               interrupt-controller;
+                               #gpio-cells = <2>;
+                               #interrupt-cells = <2>;
+                               reg = <1>;
+                               interrupts = <14 IRQ_TYPE_LEVEL_HIGH>;
+                               gpio-ranges = <&pinctrl 0 30 30>;
+                       };
+                       gpios2: bank@2 {
+                               gpio-controller;
+                               interrupt-controller;
+                               #gpio-cells = <2>;
+                               #interrupt-cells = <2>;
+                               reg = <2>;
+                               interrupts = <15 IRQ_TYPE_LEVEL_HIGH>;
+                               gpio-ranges = <&pinctrl 0 60 30>;
+                       };
+               };
+
+               pdc_gpios: gpios@02006500 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       compatible = "img,tz1090-pdc-gpio";
+                       reg = <0x02006500 0x100>;
+
+                       interrupt-parent = <&pdc>;
+                       interrupts =    <8  IRQ_TYPE_NONE>,
+                                       <9  IRQ_TYPE_NONE>,
+                                       <10 IRQ_TYPE_NONE>;
+                       gpio-ranges = <&pdc_pinctrl 0 0 7>;
+               };
        };
 };
index bdb8ea100e73ee8637c8ea587378000292b0b37b..1b93bf0892a0d5550418bed47f99f1dfa07e4305 100644 (file)
@@ -657,67 +657,42 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
 void pci_process_bridge_OF_ranges(struct pci_controller *hose,
                                  struct device_node *dev, int primary)
 {
-       const u32 *ranges;
-       int rlen;
-       int pna = of_n_addr_cells(dev);
-       int np = pna + 5;
        int memno = 0, isa_hole = -1;
-       u32 pci_space;
-       unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size;
        unsigned long long isa_mb = 0;
        struct resource *res;
+       struct of_pci_range range;
+       struct of_pci_range_parser parser;
 
        pr_info("PCI host bridge %s %s ranges:\n",
               dev->full_name, primary ? "(primary)" : "");
 
-       /* Get ranges property */
-       ranges = of_get_property(dev, "ranges", &rlen);
-       if (ranges == NULL)
+       /* Check for ranges property */
+       if (of_pci_range_parser_init(&parser, dev))
                return;
 
-       /* Parse it */
        pr_debug("Parsing ranges property...\n");
-       while ((rlen -= np * 4) >= 0) {
+       for_each_of_pci_range(&parser, &range) {
                /* Read next ranges element */
-               pci_space = ranges[0];
-               pci_addr = of_read_number(ranges + 1, 2);
-               cpu_addr = of_translate_address(dev, ranges + 3);
-               size = of_read_number(ranges + pna + 3, 2);
-
                pr_debug("pci_space: 0x%08x pci_addr:0x%016llx ",
-                               pci_space, pci_addr);
+                               range.pci_space, range.pci_addr);
                pr_debug("cpu_addr:0x%016llx size:0x%016llx\n",
-                                       cpu_addr, size);
-
-               ranges += np;
+                                       range.cpu_addr, range.size);
 
                /* If we failed translation or got a zero-sized region
                 * (some FW try to feed us with non sensical zero sized regions
                 * such as power3 which look like some kind of attempt
                 * at exposing the VGA memory hole)
                 */
-               if (cpu_addr == OF_BAD_ADDR || size == 0)
+               if (range.cpu_addr == OF_BAD_ADDR || range.size == 0)
                        continue;
 
-               /* Now consume following elements while they are contiguous */
-               for (; rlen >= np * sizeof(u32);
-                    ranges += np, rlen -= np * 4) {
-                       if (ranges[0] != pci_space)
-                               break;
-                       pci_next = of_read_number(ranges + 1, 2);
-                       cpu_next = of_translate_address(dev, ranges + 3);
-                       if (pci_next != pci_addr + size ||
-                           cpu_next != cpu_addr + size)
-                               break;
-                       size += of_read_number(ranges + pna + 3, 2);
-               }
-
                /* Act based on address space type */
                res = NULL;
-               switch ((pci_space >> 24) & 0x3) {
-               case 1:         /* PCI IO space */
+               switch (range.flags & IORESOURCE_TYPE_BITS) {
+               case IORESOURCE_IO:
                        pr_info("  IO 0x%016llx..0x%016llx -> 0x%016llx\n",
-                              cpu_addr, cpu_addr + size - 1, pci_addr);
+                               range.cpu_addr, range.cpu_addr + range.size - 1,
+                               range.pci_addr);
 
                        /* We support only one IO range */
                        if (hose->pci_io_size) {
@@ -725,11 +700,12 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
                                continue;
                        }
                        /* On 32 bits, limit I/O space to 16MB */
-                       if (size > 0x01000000)
-                               size = 0x01000000;
+                       if (range.size > 0x01000000)
+                               range.size = 0x01000000;
 
                        /* 32 bits needs to map IOs here */
-                       hose->io_base_virt = ioremap(cpu_addr, size);
+                       hose->io_base_virt = ioremap(range.cpu_addr,
+                                               range.size);
 
                        /* Expect trouble if pci_addr is not 0 */
                        if (primary)
@@ -738,19 +714,20 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
                        /* pci_io_size and io_base_phys always represent IO
                         * space starting at 0 so we factor in pci_addr
                         */
-                       hose->pci_io_size = pci_addr + size;
-                       hose->io_base_phys = cpu_addr - pci_addr;
+                       hose->pci_io_size = range.pci_addr + range.size;
+                       hose->io_base_phys = range.cpu_addr - range.pci_addr;
 
                        /* Build resource */
                        res = &hose->io_resource;
-                       res->flags = IORESOURCE_IO;
-                       res->start = pci_addr;
+                       range.cpu_addr = range.pci_addr;
+
                        break;
-               case 2:         /* PCI Memory space */
-               case 3:         /* PCI 64 bits Memory space */
+               case IORESOURCE_MEM:
                        pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
-                              cpu_addr, cpu_addr + size - 1, pci_addr,
-                              (pci_space & 0x40000000) ? "Prefetch" : "");
+                               range.cpu_addr, range.cpu_addr + range.size - 1,
+                               range.pci_addr,
+                               (range.pci_space & 0x40000000) ?
+                               "Prefetch" : "");
 
                        /* We support only 3 memory ranges */
                        if (memno >= 3) {
@@ -758,13 +735,13 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
                                continue;
                        }
                        /* Handles ISA memory hole space here */
-                       if (pci_addr == 0) {
-                               isa_mb = cpu_addr;
+                       if (range.pci_addr == 0) {
+                               isa_mb = range.cpu_addr;
                                isa_hole = memno;
                                if (primary || isa_mem_base == 0)
-                                       isa_mem_base = cpu_addr;
-                               hose->isa_mem_phys = cpu_addr;
-                               hose->isa_mem_size = size;
+                                       isa_mem_base = range.cpu_addr;
+                               hose->isa_mem_phys = range.cpu_addr;
+                               hose->isa_mem_size = range.size;
                        }
 
                        /* We get the PCI/Mem offset from the first range or
@@ -772,30 +749,23 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
                         * hole. If they don't match, bugger.
                         */
                        if (memno == 0 ||
-                           (isa_hole >= 0 && pci_addr != 0 &&
+                           (isa_hole >= 0 && range.pci_addr != 0 &&
                             hose->pci_mem_offset == isa_mb))
-                               hose->pci_mem_offset = cpu_addr - pci_addr;
-                       else if (pci_addr != 0 &&
-                                hose->pci_mem_offset != cpu_addr - pci_addr) {
+                               hose->pci_mem_offset = range.cpu_addr -
+                                                       range.pci_addr;
+                       else if (range.pci_addr != 0 &&
+                                hose->pci_mem_offset != range.cpu_addr -
+                                                       range.pci_addr) {
                                pr_info(" \\--> Skipped (offset mismatch) !\n");
                                continue;
                        }
 
                        /* Build resource */
                        res = &hose->mem_resources[memno++];
-                       res->flags = IORESOURCE_MEM;
-                       if (pci_space & 0x40000000)
-                               res->flags |= IORESOURCE_PREFETCH;
-                       res->start = cpu_addr;
                        break;
                }
-               if (res != NULL) {
-                       res->name = dev->full_name;
-                       res->end = res->start + size - 1;
-                       res->parent = NULL;
-                       res->sibling = NULL;
-                       res->child = NULL;
-               }
+               if (res != NULL)
+                       of_pci_range_to_resource(&range, dev, res);
        }
 
        /* If there's an ISA hole and the pci_mem_offset is -not- matching
index c3abed332301fe70572e8de451eda0d70f51eadd..e12764c2a9d08163e7d066f276f4b8b87e16e208 100644 (file)
@@ -114,6 +114,7 @@ config BCM47XX
        select FW_CFE
        select HW_HAS_PCI
        select IRQ_CPU
+       select SYS_HAS_CPU_MIPS32_R1
        select NO_EXCEPT_FILL
        select SYS_SUPPORTS_32BIT_KERNEL
        select SYS_SUPPORTS_LITTLE_ENDIAN
index ba611927749b9f81def164126a2b2b1d00bf42c5..2b8b118398c458573652c5b9e058a302ddcaf766 100644 (file)
@@ -2,7 +2,6 @@ if BCM47XX
 
 config BCM47XX_SSB
        bool "SSB Support for Broadcom BCM47XX"
-       select SYS_HAS_CPU_MIPS32_R1
        select SSB
        select SSB_DRIVER_MIPS
        select SSB_DRIVER_EXTIF
index e652e578a679aa3d1c5c41e336121bedb298ad72..4b50d40f7451ad86eba859b8a02ea792ff060b35 100644 (file)
@@ -35,6 +35,8 @@ struct bcm963xx_nvram {
        u32     checksum_high;
 };
 
+#define BCM63XX_DEFAULT_PSI_SIZE       64
+
 static struct bcm963xx_nvram nvram;
 static int mac_addr_used;
 
@@ -114,3 +116,12 @@ int bcm63xx_nvram_get_mac_address(u8 *mac)
        return 0;
 }
 EXPORT_SYMBOL(bcm63xx_nvram_get_mac_address);
+
+int bcm63xx_nvram_get_psi_size(void)
+{
+       if (nvram.psi_size > 0)
+               return nvram.psi_size;
+
+       return BCM63XX_DEFAULT_PSI_SIZE;
+}
+EXPORT_SYMBOL(bcm63xx_nvram_get_psi_size);
index 48b08eb9d9e4bd29dc97f5ec97c3f763852ff4aa..b212ae12e5ac7dc8ca35dfb24324ba638353f85e 100644 (file)
@@ -8,6 +8,7 @@
  *   written by Ralf Baechle <ralf@linux-mips.org>
  */
 #include <linux/compiler.h>
+#include <linux/vmalloc.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/console.h>
@@ -1139,3 +1140,30 @@ static int __init edac_devinit(void)
        return err;
 }
 device_initcall(edac_devinit);
+
+static void __initdata *octeon_dummy_iospace;
+
+static int __init octeon_no_pci_init(void)
+{
+       /*
+        * Initially assume there is no PCI. The PCI/PCIe platform code will
+        * later re-initialize these to correct values if they are present.
+        */
+       octeon_dummy_iospace = vzalloc(IO_SPACE_LIMIT);
+       set_io_port_base((unsigned long)octeon_dummy_iospace);
+       ioport_resource.start = MAX_RESOURCE;
+       ioport_resource.end = 0;
+       return 0;
+}
+core_initcall(octeon_no_pci_init);
+
+static int __init octeon_no_pci_release(void)
+{
+       /*
+        * Release the allocated memory if a real IO space is there.
+        */
+       if ((unsigned long)octeon_dummy_iospace != mips_io_port_base)
+               vfree(octeon_dummy_iospace);
+       return 0;
+}
+late_initcall(octeon_no_pci_release);
index 9b54b7a403d446b59073fe39fec03e0db7a432e8..454ddf9bb76f8a5fc5660bc6ab02c4d5380f7593 100644 (file)
@@ -1,2 +1,15 @@
 # MIPS headers
+generic-y += cputime.h
+generic-y += current.h
+generic-y += emergency-restart.h
+generic-y += local64.h
+generic-y += mutex.h
+generic-y += parport.h
+generic-y += percpu.h
+generic-y += scatterlist.h
+generic-y += sections.h
+generic-y += segment.h
+generic-y += serial.h
 generic-y += trace_clock.h
+generic-y += ucontext.h
+generic-y += xor.h
index 632bbe5a79ea5bfe53769939964ce3a4d3bfd8e9..c19861518c322aa218eb4dadd49e4bae46c7008a 100644 (file)
 #define PRID_IMP_CAVIUM_CN68XX 0x9100
 #define PRID_IMP_CAVIUM_CN66XX 0x9200
 #define PRID_IMP_CAVIUM_CN61XX 0x9300
+#define PRID_IMP_CAVIUM_CNF71XX 0x9400
+#define PRID_IMP_CAVIUM_CN78XX 0x9500
+#define PRID_IMP_CAVIUM_CN70XX 0x9600
 
 /*
  * These are the PRID's for when 23:16 == PRID_COMP_INGENIC
@@ -272,7 +275,7 @@ enum cpu_type_enum {
         */
        CPU_5KC, CPU_5KE, CPU_20KC, CPU_25KF, CPU_SB1, CPU_SB1A, CPU_LOONGSON2,
        CPU_CAVIUM_OCTEON, CPU_CAVIUM_OCTEON_PLUS, CPU_CAVIUM_OCTEON2,
-       CPU_XLR, CPU_XLP,
+       CPU_CAVIUM_OCTEON3, CPU_XLR, CPU_XLP,
 
        CPU_LAST
 };
diff --git a/arch/mips/include/asm/cputime.h b/arch/mips/include/asm/cputime.h
deleted file mode 100644 (file)
index c00eacb..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __MIPS_CPUTIME_H
-#define __MIPS_CPUTIME_H
-
-#include <asm-generic/cputime.h>
-
-#endif /* __MIPS_CPUTIME_H */
diff --git a/arch/mips/include/asm/current.h b/arch/mips/include/asm/current.h
deleted file mode 100644 (file)
index 4c51401..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/current.h>
diff --git a/arch/mips/include/asm/emergency-restart.h b/arch/mips/include/asm/emergency-restart.h
deleted file mode 100644 (file)
index 108d8c4..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_EMERGENCY_RESTART_H
-#define _ASM_EMERGENCY_RESTART_H
-
-#include <asm-generic/emergency-restart.h>
-
-#endif /* _ASM_EMERGENCY_RESTART_H */
diff --git a/arch/mips/include/asm/local64.h b/arch/mips/include/asm/local64.h
deleted file mode 100644 (file)
index 36c93b5..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/local64.h>
index 4e0b6bc1165edcbae2f44663390daa2c63c017d9..348df49dcc9f35ad7ce4129bde4ab66d1a103b00 100644 (file)
@@ -30,4 +30,6 @@ u8 *bcm63xx_nvram_get_name(void);
  */
 int bcm63xx_nvram_get_mac_address(u8 *mac);
 
+int bcm63xx_nvram_get_psi_size(void);
+
 #endif /* BCM63XX_NVRAM_H */
index 5b2f2e68e57f08210be7d4a98370cb3895111adf..9488fa5f886603fdef1ac258182bf82d61004faf 100644 (file)
 #else
 #define CAC_BASE               _AC(0x80000000, UL)
 #endif
+#ifndef IO_BASE
 #define IO_BASE                        _AC(0xa0000000, UL)
+#endif
+#ifndef UNCAC_BASE
 #define UNCAC_BASE             _AC(0xa0000000, UL)
+#endif
 
 #ifndef MAP_BASE
 #ifdef CONFIG_KVM_GUEST
diff --git a/arch/mips/include/asm/mutex.h b/arch/mips/include/asm/mutex.h
deleted file mode 100644 (file)
index 458c1f7..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * Pull in the generic implementation for the mutex fastpath.
- *
- * TODO: implement optimized primitives instead, or leave the generic
- * implementation in place, or pick the atomic_xchg() based generic
- * implementation. (see asm-generic/mutex-xchg.h for details)
- */
-
-#include <asm-generic/mutex-dec.h>
diff --git a/arch/mips/include/asm/parport.h b/arch/mips/include/asm/parport.h
deleted file mode 100644 (file)
index cf252af..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/parport.h>
diff --git a/arch/mips/include/asm/percpu.h b/arch/mips/include/asm/percpu.h
deleted file mode 100644 (file)
index 844e763..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_PERCPU_H
-#define __ASM_PERCPU_H
-
-#include <asm-generic/percpu.h>
-
-#endif /* __ASM_PERCPU_H */
diff --git a/arch/mips/include/asm/scatterlist.h b/arch/mips/include/asm/scatterlist.h
deleted file mode 100644 (file)
index 7ee0e64..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_SCATTERLIST_H
-#define __ASM_SCATTERLIST_H
-
-#include <asm-generic/scatterlist.h>
-
-#endif /* __ASM_SCATTERLIST_H */
diff --git a/arch/mips/include/asm/sections.h b/arch/mips/include/asm/sections.h
deleted file mode 100644 (file)
index b7e3726..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_SECTIONS_H
-#define _ASM_SECTIONS_H
-
-#include <asm-generic/sections.h>
-
-#endif /* _ASM_SECTIONS_H */
diff --git a/arch/mips/include/asm/segment.h b/arch/mips/include/asm/segment.h
deleted file mode 100644 (file)
index 92ac001..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_SEGMENT_H
-#define _ASM_SEGMENT_H
-
-/* Only here because we have some old header files that expect it.. */
-
-#endif /* _ASM_SEGMENT_H */
diff --git a/arch/mips/include/asm/serial.h b/arch/mips/include/asm/serial.h
deleted file mode 100644 (file)
index a0cb0ca..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/serial.h>
diff --git a/arch/mips/include/asm/ucontext.h b/arch/mips/include/asm/ucontext.h
deleted file mode 100644 (file)
index 9bc07b9..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/ucontext.h>
diff --git a/arch/mips/include/asm/xor.h b/arch/mips/include/asm/xor.h
deleted file mode 100644 (file)
index c82eb12..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/xor.h>
index 350ccccadcb99e3696540d77a208989b93ac01a4..be7196eacb8890a1875123a6473ee620d65f5514 100644 (file)
@@ -1,7 +1,9 @@
 # UAPI Header export list
 include include/uapi/asm-generic/Kbuild.asm
 
-header-y += auxvec.h
+generic-y += auxvec.h
+generic-y += ipcbuf.h
+
 header-y += bitsperlong.h
 header-y += break.h
 header-y += byteorder.h
@@ -11,7 +13,6 @@ header-y += fcntl.h
 header-y += inst.h
 header-y += ioctl.h
 header-y += ioctls.h
-header-y += ipcbuf.h
 header-y += kvm_para.h
 header-y += mman.h
 header-y += msgbuf.h
diff --git a/arch/mips/include/uapi/asm/auxvec.h b/arch/mips/include/uapi/asm/auxvec.h
deleted file mode 100644 (file)
index 7cf7f2d..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#ifndef _ASM_AUXVEC_H
-#define _ASM_AUXVEC_H
-
-#endif /* _ASM_AUXVEC_H */
diff --git a/arch/mips/include/uapi/asm/ipcbuf.h b/arch/mips/include/uapi/asm/ipcbuf.h
deleted file mode 100644 (file)
index 84c7e51..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/ipcbuf.h>
index b7a23064841f2171173dbaca04027381000e02d4..88e292b7719e99963f74692f0ffbd36e60e79c83 100644 (file)
@@ -25,11 +25,12 @@ struct siginfo;
 /*
  * Careful to keep union _sifields from shifting ...
  */
-#if __SIZEOF_LONG__ == 4
+#if _MIPS_SZLONG == 32
 #define __ARCH_SI_PREAMBLE_SIZE (3 * sizeof(int))
-#endif
-#if __SIZEOF_LONG__ == 8
+#elif _MIPS_SZLONG == 64
 #define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
+#else
+#error _MIPS_SZLONG neither 32 nor 64
 #endif
 
 #include <asm-generic/siginfo.h>
index f739aedcb509ada01eb9f579b98bc5c1752e03de..bd79c4f9bff403eeb2e320343b83d81d70855852 100644 (file)
@@ -54,7 +54,11 @@ LEAF(bmips_smp_movevec)
        /* set up CPU1 CBR; move BASE to 0xa000_0000 */
        li      k0, 0xff400000
        mtc0    k0, $22, 6
-       li      k1, CKSEG1 | BMIPS_RELO_VECTOR_CONTROL_1
+       /* set up relocation vector address based on thread ID */
+       mfc0    k1, $22, 3
+       srl     k1, 16
+       andi    k1, 0x8000
+       or      k1, CKSEG1 | BMIPS_RELO_VECTOR_CONTROL_0
        or      k0, k1
        li      k1, 0xa0080000
        sw      k1, 0(k0)
index 4c6167a178754ecab7b0b456129c6d979626b399..8e8feb851f6b999e0de558517262f9c7e1788ae7 100644 (file)
@@ -852,10 +852,17 @@ platform:
        case PRID_IMP_CAVIUM_CN63XX:
        case PRID_IMP_CAVIUM_CN66XX:
        case PRID_IMP_CAVIUM_CN68XX:
+       case PRID_IMP_CAVIUM_CNF71XX:
                c->cputype = CPU_CAVIUM_OCTEON2;
                __cpu_name[cpu] = "Cavium Octeon II";
                set_elf_platform(cpu, "octeon2");
                break;
+       case PRID_IMP_CAVIUM_CN70XX:
+       case PRID_IMP_CAVIUM_CN78XX:
+               c->cputype = CPU_CAVIUM_OCTEON3;
+               __cpu_name[cpu] = "Cavium Octeon III";
+               set_elf_platform(cpu, "octeon3");
+               break;
        default:
                printk(KERN_INFO "Unknown Octeon chip!\n");
                c->cputype = CPU_UNKNOWN;
index 0c655deeea4adff8fd575cd5d09b372cd3f820e5..42f8875d244444fb65f79592df7a6e4514a84e9d 100644 (file)
@@ -166,6 +166,7 @@ void __init check_wait(void)
        case CPU_CAVIUM_OCTEON:
        case CPU_CAVIUM_OCTEON_PLUS:
        case CPU_CAVIUM_OCTEON2:
+       case CPU_CAVIUM_OCTEON3:
        case CPU_JZRISC:
        case CPU_LOONGSON1:
        case CPU_XLR:
index c0bb4d59076a79bdc85cf59caf57fd2b2c87303c..159abc8842d214b263e93bd94d9558e997402541 100644 (file)
@@ -79,15 +79,9 @@ static void __init bmips_smp_setup(void)
         * MIPS interrupts 0,1 (SW INT 0,1) cross over to the other thread
         * MIPS interrupt 2 (HW INT 0) is the CPU0 L1 controller output
         * MIPS interrupt 3 (HW INT 1) is the CPU1 L1 controller output
-        *
-        * If booting from TP1, leave the existing CMT interrupt routing
-        * such that TP0 responds to SW1 and TP1 responds to SW0.
         */
-       if (boot_cpu == 0)
-               change_c0_brcm_cmt_intr(0xf8018000,
+       change_c0_brcm_cmt_intr(0xf8018000,
                                        (0x02 << 27) | (0x03 << 15));
-       else
-               change_c0_brcm_cmt_intr(0xf8018000, (0x1d << 27));
 
        /* single core, 2 threads (2 pipelines) */
        max_cpus = 2;
@@ -202,9 +196,15 @@ static void bmips_init_secondary(void)
 #if defined(CONFIG_CPU_BMIPS4350) || defined(CONFIG_CPU_BMIPS4380)
        void __iomem *cbr = BMIPS_GET_CBR();
        unsigned long old_vec;
+       unsigned long relo_vector;
+       int boot_cpu;
+
+       boot_cpu = !!(read_c0_brcm_cmt_local() & (1 << 31));
+       relo_vector = boot_cpu ? BMIPS_RELO_VECTOR_CONTROL_0 :
+                         BMIPS_RELO_VECTOR_CONTROL_1;
 
-       old_vec = __raw_readl(cbr + BMIPS_RELO_VECTOR_CONTROL_1);
-       __raw_writel(old_vec & ~0x20000000, cbr + BMIPS_RELO_VECTOR_CONTROL_1);
+       old_vec = __raw_readl(cbr + relo_vector);
+       __raw_writel(old_vec & ~0x20000000, cbr + relo_vector);
 
        clear_c0_cause(smp_processor_id() ? C_SW1 : C_SW0);
 #elif defined(CONFIG_CPU_BMIPS5000)
index a0bcdbb81d410c31fd41507dd4f0d200e3eb865b..729e7702b1de86212653cf56b49662aa0637c1d9 100644 (file)
@@ -224,6 +224,20 @@ static void probe_octeon(void)
                c->options |= MIPS_CPU_PREFETCH;
                break;
 
+       case CPU_CAVIUM_OCTEON3:
+               c->icache.linesz = 128;
+               c->icache.sets = 16;
+               c->icache.ways = 39;
+               c->icache.flags |= MIPS_CACHE_VTAG;
+               icache_size = c->icache.sets * c->icache.ways * c->icache.linesz;
+
+               c->dcache.linesz = 128;
+               c->dcache.ways = 32;
+               c->dcache.sets = 8;
+               dcache_size = c->dcache.sets * c->dcache.ways * c->dcache.linesz;
+               c->options |= MIPS_CPU_PREFETCH;
+               break;
+
        default:
                panic("Unsupported Cavium Networks CPU type");
                break;
index 30a494db99c2a0eb4d51aa64ca410de956801837..79bca3130bd15f51bccae23012fa9a821cadb653 100644 (file)
 
 #define FASTPATH_SIZE  128
 
+#ifdef CONFIG_MIPS_PGD_C0_CONTEXT
 LEAF(tlbmiss_handler_setup_pgd)
        .space          16 * 4
 END(tlbmiss_handler_setup_pgd)
 EXPORT(tlbmiss_handler_setup_pgd_end)
+#endif
 
 LEAF(handle_tlbm)
        .space          FASTPATH_SIZE * 4
index 556cb48157704d8c576da3fc0dda6fb10c375c3e..821b45175dc1a961c3f86a799228ab5a3eb512cf 100644 (file)
@@ -85,6 +85,7 @@ static int use_bbit_insns(void)
        case CPU_CAVIUM_OCTEON:
        case CPU_CAVIUM_OCTEON_PLUS:
        case CPU_CAVIUM_OCTEON2:
+       case CPU_CAVIUM_OCTEON3:
                return 1;
        default:
                return 0;
@@ -95,6 +96,7 @@ static int use_lwx_insns(void)
 {
        switch (current_cpu_type()) {
        case CPU_CAVIUM_OCTEON2:
+       case CPU_CAVIUM_OCTEON3:
                return 1;
        default:
                return 0;
index ef3897ef0dc711d05ea06383b2080f17d2eaa643..d5378ef3c0f7652f413b5de8247b323779d5af91 100644 (file)
@@ -75,8 +75,7 @@ static void nlm_usb_intr_en(int node, int port)
        port_addr = nlm_get_usb_regbase(node, port);
        val = nlm_read_usb_reg(port_addr, USB_INT_EN);
        val = USB_CTRL_INTERRUPT_EN  | USB_OHCI_INTERRUPT_EN |
-               USB_OHCI_INTERRUPT1_EN | USB_CTRL_INTERRUPT_EN  |
-               USB_OHCI_INTERRUPT_EN | USB_OHCI_INTERRUPT2_EN;
+               USB_OHCI_INTERRUPT1_EN | USB_OHCI_INTERRUPT2_EN;
        nlm_write_usb_reg(port_addr, USB_INT_EN, val);
 }
 
index 95c2ea815cacc4c6962025086fd4de4bcc0ef4a9..59cccd95688b500fa809b90edc71f24bf17a9859 100644 (file)
@@ -586,15 +586,16 @@ static int __init octeon_pci_setup(void)
        else
                octeon_dma_bar_type = OCTEON_DMA_BAR_TYPE_BIG;
 
-       /* PCI I/O and PCI MEM values */
-       set_io_port_base(OCTEON_PCI_IOSPACE_BASE);
-       ioport_resource.start = 0;
-       ioport_resource.end = OCTEON_PCI_IOSPACE_SIZE - 1;
        if (!octeon_is_pci_host()) {
                pr_notice("Not in host mode, PCI Controller not initialized\n");
                return 0;
        }
 
+       /* PCI I/O and PCI MEM values */
+       set_io_port_base(OCTEON_PCI_IOSPACE_BASE);
+       ioport_resource.start = 0;
+       ioport_resource.end = OCTEON_PCI_IOSPACE_SIZE - 1;
+
        pr_notice("%s Octeon big bar support\n",
                  (octeon_dma_bar_type ==
                  OCTEON_DMA_BAR_TYPE_BIG) ? "Enabling" : "Disabling");
index d22dc0d6f28922e0f6beefbc2cabad28da0d70e1..2b7e837dc2e2c275e698e101eb1fd961bc44d7ee 100644 (file)
@@ -206,11 +206,13 @@ static struct resource pnx833x_ethernet_resources[] = {
                .end   = PNX8335_IP3902_PORTS_END,
                .flags = IORESOURCE_MEM,
        },
+#ifdef CONFIG_SOC_PNX8335
        [1] = {
                .start = PNX8335_PIC_ETHERNET_INT,
                .end   = PNX8335_PIC_ETHERNET_INT,
                .flags = IORESOURCE_IRQ,
        },
+#endif
 };
 
 static struct platform_device pnx833x_ethernet_device = {
index 9f64c23878082c7e5622733486652381af0315b4..0238af1ba50383689138a929c268a1a592a1464d 100644 (file)
@@ -529,8 +529,7 @@ EXPORT_SYMBOL(asic_resource_get);
  */
 void platform_release_memory(void *ptr, int size)
 {
-       free_reserved_area((unsigned long)ptr, (unsigned long)(ptr + size),
-                          -1, NULL);
+       free_reserved_area(ptr, ptr + size, -1, NULL);
 }
 EXPORT_SYMBOL(platform_release_memory);
 
index c86fcb92358e27bc93bd723375d04c9e1c247071..0e8cfd09da2f65dd95197c2e8ca86d5ae6dfbf24 100644 (file)
@@ -58,7 +58,7 @@ CONFIG_SCHED_SMT=y
 CONFIG_PPC_DENORMALISATION=y
 CONFIG_PCCARD=y
 CONFIG_ELECTRA_CF=y
-CONFIG_HOTPLUG_PCI=m
+CONFIG_HOTPLUG_PCI=y
 CONFIG_HOTPLUG_PCI_RPA=m
 CONFIG_HOTPLUG_PCI_RPA_DLPAR=m
 CONFIG_PACKET=y
index 4b20f76172e2efb2f2d3d1e1c5a8c8bdbc6656dc..0085dc4642c5bb107b61bcbe80c9935449d64b8d 100644 (file)
@@ -32,7 +32,7 @@ CONFIG_IRQ_ALL_CPUS=y
 CONFIG_SPARSEMEM_MANUAL=y
 CONFIG_PCI_MSI=y
 CONFIG_PCCARD=y
-CONFIG_HOTPLUG_PCI=m
+CONFIG_HOTPLUG_PCI=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
 CONFIG_XFRM_USER=m
index bea8587c3af509b1540fe6138614f73dcbf97c9c..1d4b9763895df77dafcfd61bb4eea7bed6a18621 100644 (file)
@@ -53,7 +53,7 @@ CONFIG_PPC_64K_PAGES=y
 CONFIG_PPC_SUBPAGE_PROT=y
 CONFIG_SCHED_SMT=y
 CONFIG_PPC_DENORMALISATION=y
-CONFIG_HOTPLUG_PCI=m
+CONFIG_HOTPLUG_PCI=y
 CONFIG_HOTPLUG_PCI_RPA=m
 CONFIG_HOTPLUG_PCI_RPA_DLPAR=m
 CONFIG_PACKET=y
index 2dd7bfc459bed73eba9f1be705acf44d7fb36c3d..8b24926447544c2fed3eb44de6464071a20f15dc 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/types.h>
 #include <asm/hw_irq.h>
 #include <linux/device.h>
+#include <uapi/asm/perf_event.h>
 
 #define MAX_HWEVENTS           8
 #define MAX_EVENT_ALTERNATIVES 8
@@ -69,11 +70,6 @@ struct power_pmu {
 #define PPMU_LIMITED_PMC_REQD  2       /* have to put this on a limited PMC */
 #define PPMU_ONLY_COUNT_RUN    4       /* only counting in run state */
 
-/*
- * We use the event config bit 63 as a flag to request EBB.
- */
-#define EVENT_CONFIG_EBB_SHIFT 63
-
 extern int register_power_pmu(struct power_pmu *);
 
 struct pt_regs;
index ffbaabebcdca71eb1130ccaf12cfcf36c82501c4..48cfc858abd6dfa70c4c95172a5e4003fa62c53d 100644 (file)
@@ -145,6 +145,10 @@ extern void __cpu_die(unsigned int cpu);
 #define smp_setup_cpu_maps()
 static inline void inhibit_secondary_onlining(void) {}
 static inline void uninhibit_secondary_onlining(void) {}
+static inline const struct cpumask *cpu_sibling_mask(int cpu)
+{
+       return cpumask_of(cpu);
+}
 
 #endif /* CONFIG_SMP */
 
index 93f280e23279e77172cd56e373c4429e11be01b6..37b7ca39ec9f1b5ec2d3e574a8806de34ccff555 100644 (file)
@@ -235,6 +235,7 @@ extern long spu_sys_callback(struct spu_syscall_block *s);
 
 /* syscalls implemented in spufs */
 struct file;
+struct coredump_params;
 struct spufs_calls {
        long (*create_thread)(const char __user *name,
                                        unsigned int flags, umode_t mode,
@@ -242,7 +243,7 @@ struct spufs_calls {
        long (*spu_run)(struct file *filp, __u32 __user *unpc,
                                                __u32 __user *ustatus);
        int (*coredump_extra_notes_size)(void);
-       int (*coredump_extra_notes_write)(struct file *file, loff_t *foffset);
+       int (*coredump_extra_notes_write)(struct coredump_params *cprm);
        void (*notify_spus_active)(void);
        struct module *owner;
 };
index 5182c8622b54eea94ba18cfad7236872ae056865..48be855ef37b294cf034db138842cf56526ff4ea 100644 (file)
@@ -20,6 +20,7 @@ header-y += mman.h
 header-y += msgbuf.h
 header-y += nvram.h
 header-y += param.h
+header-y += perf_event.h
 header-y += poll.h
 header-y += posix_types.h
 header-y += ps3fb.h
diff --git a/arch/powerpc/include/uapi/asm/perf_event.h b/arch/powerpc/include/uapi/asm/perf_event.h
new file mode 100644 (file)
index 0000000..80a4d40
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2013 Michael Ellerman, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the
+ * License.
+ */
+
+#ifndef _UAPI_ASM_POWERPC_PERF_EVENT_H
+#define _UAPI_ASM_POWERPC_PERF_EVENT_H
+
+/*
+ * We use bit 63 of perf_event_attr.config as a flag to request EBB.
+ */
+#define PERF_EVENT_CONFIG_EBB_SHIFT    63
+
+#endif /* _UAPI_ASM_POWERPC_PERF_EVENT_H */
index 2e51cde616d2de1fc93cdb75547debab72cf66c2..c69440cef7af43413987f3cd4b2c936cd0e8f788 100644 (file)
@@ -362,7 +362,7 @@ int arch_show_interrupts(struct seq_file *p, int prec)
                seq_printf(p, "%10u ", per_cpu(irq_stat, j).spurious_irqs);
        seq_printf(p, "  Spurious interrupts\n");
 
-       seq_printf(p, "%*s: ", prec, "CNT");
+       seq_printf(p, "%*s: ", prec, "PMI");
        for_each_online_cpu(j)
                seq_printf(p, "%10u ", per_cpu(irq_stat, j).pmu_irqs);
        seq_printf(p, "  Performance monitoring interrupts\n");
index 08397217e8ace2d6ce3abc1a09a4fcc14977413f..5850798826cde0be9570368cb7968a9ea279b1e1 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/seq_file.h>
 #include <linux/uaccess.h>
 #include <linux/slab.h>
+#include <asm/cputhreads.h>
 #include <asm/sparsemem.h>
 #include <asm/prom.h>
 #include <asm/smp.h>
@@ -1318,7 +1319,8 @@ static int update_cpu_associativity_changes_mask(void)
                        }
                }
                if (changed) {
-                       cpumask_set_cpu(cpu, changes);
+                       cpumask_or(changes, changes, cpu_sibling_mask(cpu));
+                       cpu = cpu_last_thread_sibling(cpu);
                }
        }
 
@@ -1426,7 +1428,7 @@ static int update_cpu_topology(void *data)
        if (!data)
                return -EINVAL;
 
-       cpu = get_cpu();
+       cpu = smp_processor_id();
 
        for (update = data; update; update = update->next) {
                if (cpu != update->cpu)
@@ -1446,12 +1448,12 @@ static int update_cpu_topology(void *data)
  */
 int arch_update_cpu_topology(void)
 {
-       unsigned int cpu, changed = 0;
+       unsigned int cpu, sibling, changed = 0;
        struct topology_update_data *updates, *ud;
        unsigned int associativity[VPHN_ASSOC_BUFSIZE] = {0};
        cpumask_t updated_cpus;
        struct device *dev;
-       int weight, i = 0;
+       int weight, new_nid, i = 0;
 
        weight = cpumask_weight(&cpu_associativity_changes_mask);
        if (!weight)
@@ -1464,19 +1466,46 @@ int arch_update_cpu_topology(void)
        cpumask_clear(&updated_cpus);
 
        for_each_cpu(cpu, &cpu_associativity_changes_mask) {
-               ud = &updates[i++];
-               ud->cpu = cpu;
-               vphn_get_associativity(cpu, associativity);
-               ud->new_nid = associativity_to_nid(associativity);
-
-               if (ud->new_nid < 0 || !node_online(ud->new_nid))
-                       ud->new_nid = first_online_node;
+               /*
+                * If siblings aren't flagged for changes, updates list
+                * will be too short. Skip on this update and set for next
+                * update.
+                */
+               if (!cpumask_subset(cpu_sibling_mask(cpu),
+                                       &cpu_associativity_changes_mask)) {
+                       pr_info("Sibling bits not set for associativity "
+                                       "change, cpu%d\n", cpu);
+                       cpumask_or(&cpu_associativity_changes_mask,
+                                       &cpu_associativity_changes_mask,
+                                       cpu_sibling_mask(cpu));
+                       cpu = cpu_last_thread_sibling(cpu);
+                       continue;
+               }
 
-               ud->old_nid = numa_cpu_lookup_table[cpu];
-               cpumask_set_cpu(cpu, &updated_cpus);
+               /* Use associativity from first thread for all siblings */
+               vphn_get_associativity(cpu, associativity);
+               new_nid = associativity_to_nid(associativity);
+               if (new_nid < 0 || !node_online(new_nid))
+                       new_nid = first_online_node;
+
+               if (new_nid == numa_cpu_lookup_table[cpu]) {
+                       cpumask_andnot(&cpu_associativity_changes_mask,
+                                       &cpu_associativity_changes_mask,
+                                       cpu_sibling_mask(cpu));
+                       cpu = cpu_last_thread_sibling(cpu);
+                       continue;
+               }
 
-               if (i < weight)
-                       ud->next = &updates[i];
+               for_each_cpu(sibling, cpu_sibling_mask(cpu)) {
+                       ud = &updates[i++];
+                       ud->cpu = sibling;
+                       ud->new_nid = new_nid;
+                       ud->old_nid = numa_cpu_lookup_table[sibling];
+                       cpumask_set_cpu(sibling, &updated_cpus);
+                       if (i < weight)
+                               ud->next = &updates[i];
+               }
+               cpu = cpu_last_thread_sibling(cpu);
        }
 
        stop_machine(update_cpu_topology, &updates[0], &updated_cpus);
index 24a45f91c65f69480119055e6d8820f52f07582b..eeae308cf98253888a1af8792dd150e4410b08ef 100644 (file)
@@ -484,7 +484,7 @@ static bool is_ebb_event(struct perf_event *event)
         * use bit 63 of the event code for something else if they wish.
         */
        return (ppmu->flags & PPMU_EBB) &&
-              ((event->attr.config >> EVENT_CONFIG_EBB_SHIFT) & 1);
+              ((event->attr.config >> PERF_EVENT_CONFIG_EBB_SHIFT) & 1);
 }
 
 static int ebb_event_check(struct perf_event *event)
index 7466374d2787cca701ecef97da54b723dee09026..2ee4a707f0df85c37dba15c6ab5f4e7f84e553fc 100644 (file)
         (EVENT_UNIT_MASK      << EVENT_UNIT_SHIFT)             |       \
         (EVENT_COMBINE_MASK   << EVENT_COMBINE_SHIFT)          |       \
         (EVENT_MARKED_MASK    << EVENT_MARKED_SHIFT)           |       \
-        (EVENT_EBB_MASK       << EVENT_CONFIG_EBB_SHIFT)       |       \
+        (EVENT_EBB_MASK       << PERF_EVENT_CONFIG_EBB_SHIFT)  |       \
          EVENT_PSEL_MASK)
 
 /* MMCRA IFM bits - POWER8 */
@@ -233,10 +233,10 @@ static int power8_get_constraint(u64 event, unsigned long *maskp, unsigned long
        pmc   = (event >> EVENT_PMC_SHIFT)        & EVENT_PMC_MASK;
        unit  = (event >> EVENT_UNIT_SHIFT)       & EVENT_UNIT_MASK;
        cache = (event >> EVENT_CACHE_SEL_SHIFT)  & EVENT_CACHE_SEL_MASK;
-       ebb   = (event >> EVENT_CONFIG_EBB_SHIFT) & EVENT_EBB_MASK;
+       ebb   = (event >> PERF_EVENT_CONFIG_EBB_SHIFT) & EVENT_EBB_MASK;
 
        /* Clear the EBB bit in the event, so event checks work below */
-       event &= ~(EVENT_EBB_MASK << EVENT_CONFIG_EBB_SHIFT);
+       event &= ~(EVENT_EBB_MASK << PERF_EVENT_CONFIG_EBB_SHIFT);
 
        if (pmc) {
                if (pmc > 6)
index db4e638cf4081cd813eeed56d7203548eda19134..a238bc3f3a07e4e1e31e42e142701cbd40b52a1c 100644 (file)
@@ -126,7 +126,7 @@ int elf_coredump_extra_notes_size(void)
        return ret;
 }
 
-int elf_coredump_extra_notes_write(struct file *file, loff_t *foffset)
+int elf_coredump_extra_notes_write(struct coredump_params *cprm)
 {
        struct spufs_calls *calls;
        int ret;
@@ -135,7 +135,7 @@ int elf_coredump_extra_notes_write(struct file *file, loff_t *foffset)
        if (!calls)
                return 0;
 
-       ret = calls->coredump_extra_notes_write(file, foffset);
+       ret = calls->coredump_extra_notes_write(cprm);
 
        spufs_calls_put(calls);
 
index c9500ea7be2ff8dbf596eb4e19af87ffe6178ecc..8011c61dfc3ce0f86f953aa1966636c63096fee4 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/gfp.h>
 #include <linux/list.h>
 #include <linux/syscalls.h>
+#include <linux/coredump.h>
 
 #include <asm/uaccess.h>
 
@@ -48,44 +49,6 @@ static ssize_t do_coredump_read(int num, struct spu_context *ctx, void *buffer,
        return ++ret; /* count trailing NULL */
 }
 
-/*
- * These are the only things you should do on a core-file: use only these
- * functions to write out all the necessary info.
- */
-static int spufs_dump_write(struct file *file, const void *addr, int nr, loff_t *foffset)
-{
-       unsigned long limit = rlimit(RLIMIT_CORE);
-       ssize_t written;
-
-       if (*foffset + nr > limit)
-               return -EIO;
-
-       written = file->f_op->write(file, addr, nr, &file->f_pos);
-       *foffset += written;
-
-       if (written != nr)
-               return -EIO;
-
-       return 0;
-}
-
-static int spufs_dump_align(struct file *file, char *buf, loff_t new_off,
-                           loff_t *foffset)
-{
-       int rc, size;
-
-       size = min((loff_t)PAGE_SIZE, new_off - *foffset);
-       memset(buf, 0, size);
-
-       rc = 0;
-       while (rc == 0 && new_off > *foffset) {
-               size = min((loff_t)PAGE_SIZE, new_off - *foffset);
-               rc = spufs_dump_write(file, buf, size, foffset);
-       }
-
-       return rc;
-}
-
 static int spufs_ctx_note_size(struct spu_context *ctx, int dfd)
 {
        int i, sz, total = 0;
@@ -165,7 +128,7 @@ int spufs_coredump_extra_notes_size(void)
 }
 
 static int spufs_arch_write_note(struct spu_context *ctx, int i,
-                                 struct file *file, int dfd, loff_t *foffset)
+                                 struct coredump_params *cprm, int dfd)
 {
        loff_t pos = 0;
        int sz, rc, nread, total = 0;
@@ -186,23 +149,20 @@ static int spufs_arch_write_note(struct spu_context *ctx, int i,
        en.n_descsz = sz;
        en.n_type = NT_SPU;
 
-       rc = spufs_dump_write(file, &en, sizeof(en), foffset);
-       if (rc)
+       rc = -EIO;
+       if (!dump_emit(cprm, &en, sizeof(en)))
                goto out;
 
-       rc = spufs_dump_write(file, fullname, en.n_namesz, foffset);
-       if (rc)
+       if (!dump_emit(cprm, fullname, en.n_namesz))
                goto out;
 
-       rc = spufs_dump_align(file, buf, roundup(*foffset, 4), foffset);
-       if (rc)
+       if (!dump_align(cprm, 4))
                goto out;
 
        do {
                nread = do_coredump_read(i, ctx, buf, bufsz, &pos);
                if (nread > 0) {
-                       rc = spufs_dump_write(file, buf, nread, foffset);
-                       if (rc)
+                       if (!dump_emit(cprm, buf, nread))
                                goto out;
                        total += nread;
                }
@@ -213,15 +173,15 @@ static int spufs_arch_write_note(struct spu_context *ctx, int i,
                goto out;
        }
 
-       rc = spufs_dump_align(file, buf, roundup(*foffset - total + sz, 4),
-                             foffset);
-
+       if (!dump_align(cprm, 4))
+               goto out;
+       rc = 0;
 out:
        free_page((unsigned long)buf);
        return rc;
 }
 
-int spufs_coredump_extra_notes_write(struct file *file, loff_t *foffset)
+int spufs_coredump_extra_notes_write(struct coredump_params *cprm)
 {
        struct spu_context *ctx;
        int fd, j, rc;
@@ -233,7 +193,7 @@ int spufs_coredump_extra_notes_write(struct file *file, loff_t *foffset)
                        return rc;
 
                for (j = 0; spufs_coredump_read[j].name != NULL; j++) {
-                       rc = spufs_arch_write_note(ctx, j, file, fd, foffset);
+                       rc = spufs_arch_write_note(ctx, j, cprm, fd);
                        if (rc) {
                                spu_release_saved(ctx);
                                return rc;
index 67852ade4c013d813e49694d7e61e87173821846..28b89730ebfbaf96e828b672b74389f391f28af2 100644 (file)
@@ -252,7 +252,7 @@ long spufs_create(struct path *nd, struct dentry *dentry, unsigned int flags,
                        umode_t mode, struct file *filp);
 /* ELF coredump callbacks for writing SPU ELF notes */
 extern int spufs_coredump_extra_notes_size(void);
-extern int spufs_coredump_extra_notes_write(struct file *file, loff_t *foffset);
+extern int spufs_coredump_extra_notes_write(struct coredump_params *);
 
 extern const struct file_operations spufs_context_fops;
 
index 22f75b504f7f9bb8ef91ef80e8a1433995e6c6dc..8b7892bf6d8b0640f13e852330f0a2e7f83b1b15 100644 (file)
@@ -116,8 +116,10 @@ config S390
        select HAVE_FUNCTION_GRAPH_TRACER
        select HAVE_FUNCTION_TRACER
        select HAVE_FUNCTION_TRACE_MCOUNT_TEST
+       select HAVE_GENERIC_HARDIRQS
        select HAVE_KERNEL_BZIP2
        select HAVE_KERNEL_GZIP
+       select HAVE_KERNEL_LZ4
        select HAVE_KERNEL_LZMA
        select HAVE_KERNEL_LZO
        select HAVE_KERNEL_XZ
@@ -227,11 +229,12 @@ config MARCH_Z196
          not work on older machines.
 
 config MARCH_ZEC12
-       bool "IBM zEC12"
+       bool "IBM zBC12 and zEC12"
        select HAVE_MARCH_ZEC12_FEATURES if 64BIT
        help
-         Select this to enable optimizations for IBM zEC12 (2827 series). The
-         kernel will be slightly faster but will not work on older machines.
+         Select this to enable optimizations for IBM zBC12 and zEC12 (2828 and
+         2827 series). The kernel will be slightly faster but will not work on
+         older machines.
 
 endchoice
 
@@ -443,6 +446,16 @@ config PCI_NR_FUNCTIONS
          This allows you to specify the maximum number of PCI functions which
          this kernel will support.
 
+config PCI_NR_MSI
+       int "Maximum number of MSI interrupts (64-32768)"
+       range 64 32768
+       default "256"
+       help
+         This defines the number of virtual interrupts the kernel will
+         provide for MSI interrupts. If you configure your system to have
+         too few drivers will fail to allocate MSI interrupts for all
+         PCI devices.
+
 source "drivers/pci/Kconfig"
 source "drivers/pci/pcie/Kconfig"
 source "drivers/pci/hotplug/Kconfig"
@@ -709,6 +722,7 @@ config S390_GUEST
        def_bool y
        prompt "s390 support for virtio devices"
        depends on 64BIT
+       select TTY
        select VIRTUALIZATION
        select VIRTIO
        select VIRTIO_CONSOLE
index 3ad8f61c99852c3fe7183a15aacfcd96ace3535a..866ecbe670e499632ef59d514dd04a280f46b890 100644 (file)
@@ -6,9 +6,9 @@
 
 BITS := $(if $(CONFIG_64BIT),64,31)
 
-targets        := vmlinux.lds vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 \
-          vmlinux.bin.xz vmlinux.bin.lzma vmlinux.bin.lzo misc.o piggy.o \
-          sizes.h head$(BITS).o
+targets        := vmlinux.lds vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2
+targets += vmlinux.bin.xz vmlinux.bin.lzma vmlinux.bin.lzo vmlinux.bin.lz4
+targets += misc.o piggy.o sizes.h head$(BITS).o
 
 KBUILD_CFLAGS := -m$(BITS) -D__KERNEL__ $(LINUX_INCLUDE) -O2
 KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
@@ -48,6 +48,7 @@ vmlinux.bin.all-y := $(obj)/vmlinux.bin
 
 suffix-$(CONFIG_KERNEL_GZIP)  := gz
 suffix-$(CONFIG_KERNEL_BZIP2) := bz2
+suffix-$(CONFIG_KERNEL_LZ4)  := lz4
 suffix-$(CONFIG_KERNEL_LZMA)  := lzma
 suffix-$(CONFIG_KERNEL_LZO)  := lzo
 suffix-$(CONFIG_KERNEL_XZ)  := xz
@@ -56,6 +57,8 @@ $(obj)/vmlinux.bin.gz: $(vmlinux.bin.all-y)
        $(call if_changed,gzip)
 $(obj)/vmlinux.bin.bz2: $(vmlinux.bin.all-y)
        $(call if_changed,bzip2)
+$(obj)/vmlinux.bin.lz4: $(vmlinux.bin.all-y)
+       $(call if_changed,lz4)
 $(obj)/vmlinux.bin.lzma: $(vmlinux.bin.all-y)
        $(call if_changed,lzma)
 $(obj)/vmlinux.bin.lzo: $(vmlinux.bin.all-y)
index c4c6a1cf221bde749673b59dccb6e3c6113a0b4c..57cbaff1f39778b98b1de870e34f99cc14043687 100644 (file)
@@ -47,6 +47,10 @@ static unsigned long free_mem_end_ptr;
 #include "../../../../lib/decompress_bunzip2.c"
 #endif
 
+#ifdef CONFIG_KERNEL_LZ4
+#include "../../../../lib/decompress_unlz4.c"
+#endif
+
 #ifdef CONFIG_KERNEL_LZMA
 #include "../../../../lib/decompress_unlzma.c"
 #endif
index 4066cee0c2d2635e32a59fecb0eaf2e05c565776..4057acba67c4a67f9b071f776833d34264d0b483 100644 (file)
@@ -23,4 +23,41 @@ struct airq_struct {
 int register_adapter_interrupt(struct airq_struct *airq);
 void unregister_adapter_interrupt(struct airq_struct *airq);
 
+/* Adapter interrupt bit vector */
+struct airq_iv {
+       unsigned long *vector;  /* Adapter interrupt bit vector */
+       unsigned long *avail;   /* Allocation bit mask for the bit vector */
+       unsigned int *data;     /* 32 bit value associated with each bit */
+       unsigned long bits;     /* Number of bits in the vector */
+       unsigned long end;      /* Number of highest allocated bit + 1 */
+       spinlock_t lock;        /* Lock to protect alloc & free */
+};
+
+#define AIRQ_IV_ALLOC  1       /* Use an allocation bit mask */
+#define AIRQ_IV_DATA   2       /* Allocate the data array */
+
+struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags);
+void airq_iv_release(struct airq_iv *iv);
+unsigned long airq_iv_alloc_bit(struct airq_iv *iv);
+void airq_iv_free_bit(struct airq_iv *iv, unsigned long bit);
+unsigned long airq_iv_scan(struct airq_iv *iv, unsigned long start,
+                          unsigned long end);
+
+static inline unsigned long airq_iv_end(struct airq_iv *iv)
+{
+       return iv->end;
+}
+
+static inline void airq_iv_set_data(struct airq_iv *iv, unsigned long bit,
+                                   unsigned int data)
+{
+       iv->data[bit] = data;
+}
+
+static inline unsigned int airq_iv_get_data(struct airq_iv *iv,
+                                           unsigned long bit)
+{
+       return iv->data[bit];
+}
+
 #endif /* _ASM_S390_AIRQ_H */
index 4d8604e311f3aaf6b1799bd78760bcc52a5befab..7d46767587337c3874bd61c43e01a0a72f965303 100644 (file)
@@ -693,7 +693,7 @@ static inline int find_next_bit_left(const unsigned long *addr,
        size -= offset;
        p = addr + offset / BITS_PER_LONG;
        if (bit) {
-               set = __flo_word(0, *p & (~0UL << bit));
+               set = __flo_word(0, *p & (~0UL >> bit));
                if (set >= size)
                        return size + offset;
                if (set < BITS_PER_LONG)
index 0c82ba86e997d5d088b019daa677968fccdaf7e6..a908d2941c5d90ab305f8e7c490585e20113579a 100644 (file)
@@ -20,4 +20,9 @@
 
 #define HARDIRQ_BITS   8
 
+static inline void ack_bad_irq(unsigned int irq)
+{
+       printk(KERN_CRIT "unexpected IRQ trap at vector %02x\n", irq);
+}
+
 #endif /* __ASM_HARDIRQ_H */
index bd90359d6d22e723a8de5d3ed09450ef066a617e..11eae5f55b709d1e37e69f2b44eb762d48475e6e 100644 (file)
@@ -17,6 +17,9 @@
 
 void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
                     pte_t *ptep, pte_t pte);
+pte_t huge_ptep_get(pte_t *ptep);
+pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
+                             unsigned long addr, pte_t *ptep);
 
 /*
  * If the arch doesn't supply something else, assume that hugepage
@@ -38,147 +41,75 @@ static inline int prepare_hugepage_range(struct file *file,
 int arch_prepare_hugepage(struct page *page);
 void arch_release_hugepage(struct page *page);
 
-static inline pte_t huge_pte_wrprotect(pte_t pte)
+static inline void huge_pte_clear(struct mm_struct *mm, unsigned long addr,
+                                 pte_t *ptep)
 {
-       pte_val(pte) |= _PAGE_RO;
-       return pte;
+       pte_val(*ptep) = _SEGMENT_ENTRY_EMPTY;
 }
 
-static inline int huge_pte_none(pte_t pte)
+static inline void huge_ptep_clear_flush(struct vm_area_struct *vma,
+                                        unsigned long address, pte_t *ptep)
 {
-       return (pte_val(pte) & _SEGMENT_ENTRY_INV) &&
-               !(pte_val(pte) & _SEGMENT_ENTRY_RO);
+       huge_ptep_get_and_clear(vma->vm_mm, address, ptep);
 }
 
-static inline pte_t huge_ptep_get(pte_t *ptep)
+static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma,
+                                            unsigned long addr, pte_t *ptep,
+                                            pte_t pte, int dirty)
 {
-       pte_t pte = *ptep;
-       unsigned long mask;
-
-       if (!MACHINE_HAS_HPAGE) {
-               ptep = (pte_t *) (pte_val(pte) & _SEGMENT_ENTRY_ORIGIN);
-               if (ptep) {
-                       mask = pte_val(pte) &
-                               (_SEGMENT_ENTRY_INV | _SEGMENT_ENTRY_RO);
-                       pte = pte_mkhuge(*ptep);
-                       pte_val(pte) |= mask;
-               }
+       int changed = !pte_same(huge_ptep_get(ptep), pte);
+       if (changed) {
+               huge_ptep_get_and_clear(vma->vm_mm, addr, ptep);
+               set_huge_pte_at(vma->vm_mm, addr, ptep, pte);
        }
-       return pte;
+       return changed;
 }
 
-static inline void __pmd_csp(pmd_t *pmdp)
+static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
+                                          unsigned long addr, pte_t *ptep)
 {
-       register unsigned long reg2 asm("2") = pmd_val(*pmdp);
-       register unsigned long reg3 asm("3") = pmd_val(*pmdp) |
-                                              _SEGMENT_ENTRY_INV;
-       register unsigned long reg4 asm("4") = ((unsigned long) pmdp) + 5;
-
-       asm volatile(
-               "       csp %1,%3"
-               : "=m" (*pmdp)
-               : "d" (reg2), "d" (reg3), "d" (reg4), "m" (*pmdp) : "cc");
+       pte_t pte = huge_ptep_get_and_clear(mm, addr, ptep);
+       set_huge_pte_at(mm, addr, ptep, pte_wrprotect(pte));
 }
 
-static inline void huge_ptep_invalidate(struct mm_struct *mm,
-                                       unsigned long address, pte_t *ptep)
-{
-       pmd_t *pmdp = (pmd_t *) ptep;
-
-       if (MACHINE_HAS_IDTE)
-               __pmd_idte(address, pmdp);
-       else
-               __pmd_csp(pmdp);
-       pmd_val(*pmdp) = _SEGMENT_ENTRY_INV | _SEGMENT_ENTRY;
-}
-
-static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
-                                           unsigned long addr, pte_t *ptep)
-{
-       pte_t pte = huge_ptep_get(ptep);
-
-       huge_ptep_invalidate(mm, addr, ptep);
-       return pte;
-}
-
-#define huge_ptep_set_access_flags(__vma, __addr, __ptep, __entry, __dirty) \
-({                                                                         \
-       int __changed = !pte_same(huge_ptep_get(__ptep), __entry);          \
-       if (__changed) {                                                    \
-               huge_ptep_invalidate((__vma)->vm_mm, __addr, __ptep);       \
-               set_huge_pte_at((__vma)->vm_mm, __addr, __ptep, __entry);   \
-       }                                                                   \
-       __changed;                                                          \
-})
-
-#define huge_ptep_set_wrprotect(__mm, __addr, __ptep)                  \
-({                                                                     \
-       pte_t __pte = huge_ptep_get(__ptep);                            \
-       if (huge_pte_write(__pte)) {                                    \
-               huge_ptep_invalidate(__mm, __addr, __ptep);             \
-               set_huge_pte_at(__mm, __addr, __ptep,                   \
-                               huge_pte_wrprotect(__pte));             \
-       }                                                               \
-})
-
-static inline void huge_ptep_clear_flush(struct vm_area_struct *vma,
-                                        unsigned long address, pte_t *ptep)
+static inline pte_t mk_huge_pte(struct page *page, pgprot_t pgprot)
 {
-       huge_ptep_invalidate(vma->vm_mm, address, ptep);
+       return mk_pte(page, pgprot);
 }
 
-static inline pte_t mk_huge_pte(struct page *page, pgprot_t pgprot)
+static inline int huge_pte_none(pte_t pte)
 {
-       pte_t pte;
-       pmd_t pmd;
-
-       pmd = mk_pmd_phys(page_to_phys(page), pgprot);
-       pte_val(pte) = pmd_val(pmd);
-       return pte;
+       return pte_none(pte);
 }
 
 static inline int huge_pte_write(pte_t pte)
 {
-       pmd_t pmd;
-
-       pmd_val(pmd) = pte_val(pte);
-       return pmd_write(pmd);
+       return pte_write(pte);
 }
 
 static inline int huge_pte_dirty(pte_t pte)
 {
-       /* No dirty bit in the segment table entry. */
-       return 0;
+       return pte_dirty(pte);
 }
 
 static inline pte_t huge_pte_mkwrite(pte_t pte)
 {
-       pmd_t pmd;
-
-       pmd_val(pmd) = pte_val(pte);
-       pte_val(pte) = pmd_val(pmd_mkwrite(pmd));
-       return pte;
+       return pte_mkwrite(pte);
 }
 
 static inline pte_t huge_pte_mkdirty(pte_t pte)
 {
-       /* No dirty bit in the segment table entry. */
-       return pte;
+       return pte_mkdirty(pte);
 }
 
-static inline pte_t huge_pte_modify(pte_t pte, pgprot_t newprot)
+static inline pte_t huge_pte_wrprotect(pte_t pte)
 {
-       pmd_t pmd;
-
-       pmd_val(pmd) = pte_val(pte);
-       pte_val(pte) = pmd_val(pmd_modify(pmd, newprot));
-       return pte;
+       return pte_wrprotect(pte);
 }
 
-static inline void huge_pte_clear(struct mm_struct *mm, unsigned long addr,
-                                 pte_t *ptep)
+static inline pte_t huge_pte_modify(pte_t pte, pgprot_t newprot)
 {
-       pmd_clear((pmd_t *) ptep);
+       return pte_modify(pte, newprot);
 }
 
 #endif /* _ASM_S390_HUGETLB_H */
index 7e3d2586c1ffaa84adea001e6b40afc6fa65aa73..ee96a8b697f9479ce45e46f02b166efa6cfe54f8 100644 (file)
@@ -4,19 +4,8 @@
 #include <linux/msi.h>
 #include <linux/pci.h>
 
-static inline struct msi_desc *irq_get_msi_desc(unsigned int irq)
-{
-       return __irq_get_msi_desc(irq);
-}
-
-/* Must be called with msi map lock held */
-static inline int irq_set_msi_desc(unsigned int irq, struct msi_desc *msi)
-{
-       if (!msi)
-               return -EINVAL;
-
-       msi->irq = irq;
-       return 0;
-}
+void __init init_airq_interrupts(void);
+void __init init_cio_interrupts(void);
+void __init init_ext_interrupts(void);
 
 #endif
index 87c17bfb2968e8423fed70784417b36384754f91..1eaa3625803c1d30f41ee4a98847c82619a93857 100644 (file)
@@ -1,17 +1,28 @@
 #ifndef _ASM_IRQ_H
 #define _ASM_IRQ_H
 
+#define EXT_INTERRUPT  1
+#define IO_INTERRUPT   2
+#define THIN_INTERRUPT 3
+
+#define NR_IRQS_BASE   4
+
+#ifdef CONFIG_PCI_NR_MSI
+# define NR_IRQS       (NR_IRQS_BASE + CONFIG_PCI_NR_MSI)
+#else
+# define NR_IRQS       NR_IRQS_BASE
+#endif
+
+/* This number is used when no interrupt has been assigned */
+#define NO_IRQ         0
+
+#ifndef __ASSEMBLY__
+
 #include <linux/hardirq.h>
 #include <linux/percpu.h>
 #include <linux/cache.h>
 #include <linux/types.h>
 
-enum interruption_main_class {
-       EXTERNAL_INTERRUPT,
-       IO_INTERRUPT,
-       NR_IRQS
-};
-
 enum interruption_class {
        IRQEXT_CLK,
        IRQEXT_EXC,
@@ -72,14 +83,8 @@ void service_subclass_irq_unregister(void);
 void measurement_alert_subclass_register(void);
 void measurement_alert_subclass_unregister(void);
 
-#ifdef CONFIG_LOCKDEP
-#  define disable_irq_nosync_lockdep(irq)      disable_irq_nosync(irq)
-#  define disable_irq_nosync_lockdep_irqsave(irq, flags) \
-                                               disable_irq_nosync(irq)
-#  define disable_irq_lockdep(irq)             disable_irq(irq)
-#  define enable_irq_lockdep(irq)              enable_irq(irq)
-#  define enable_irq_lockdep_irqrestore(irq, flags) \
-                                               enable_irq(irq)
-#endif
+#define irq_canonicalize(irq)  (irq)
+
+#endif /* __ASSEMBLY__ */
 
 #endif /* _ASM_IRQ_H */
index 5d64fb7619ccfc41047c3b1bb6ad45ade2704d1d..27f04801ec8bc2178d6286f69a037190b64dbae5 100644 (file)
 
 void storage_key_init_range(unsigned long start, unsigned long end);
 
-static inline unsigned long pfmf(unsigned long function, unsigned long address)
-{
-       asm volatile(
-               "       .insn   rre,0xb9af0000,%[function],%[address]"
-               : [address] "+a" (address)
-               : [function] "d" (function)
-               : "memory");
-       return address;
-}
-
 static inline void clear_page(void *page)
 {
        register unsigned long reg1 asm ("1") = 0;
index 6e577ba0e5daa12256590018dfeddb4071a1e892..d0872769d44edb5e1438e02058efef6550fe40fc 100644 (file)
@@ -53,14 +53,9 @@ struct zpci_fmb {
        atomic64_t unmapped_pages;
 } __packed __aligned(16);
 
-struct msi_map {
-       unsigned long irq;
-       struct msi_desc *msi;
-       struct hlist_node msi_chain;
-};
-
-#define ZPCI_NR_MSI_VECS       64
-#define ZPCI_MSI_MASK          (ZPCI_NR_MSI_VECS - 1)
+#define ZPCI_MSI_VEC_BITS      11
+#define ZPCI_MSI_VEC_MAX       (1 << ZPCI_MSI_VEC_BITS)
+#define ZPCI_MSI_VEC_MASK      (ZPCI_MSI_VEC_MAX - 1)
 
 enum zpci_state {
        ZPCI_FN_STATE_RESERVED,
@@ -91,8 +86,7 @@ struct zpci_dev {
 
        /* IRQ stuff */
        u64             msi_addr;       /* MSI address */
-       struct zdev_irq_map *irq_map;
-       struct msi_map *msi_map[ZPCI_NR_MSI_VECS];
+       struct airq_iv *aibv;           /* adapter interrupt bit vector */
        unsigned int    aisb;           /* number of the summary bit */
 
        /* DMA stuff */
@@ -151,14 +145,6 @@ int clp_add_pci_device(u32, u32, int);
 int clp_enable_fh(struct zpci_dev *, u8);
 int clp_disable_fh(struct zpci_dev *);
 
-/* MSI */
-struct msi_desc *__irq_get_msi_desc(unsigned int);
-int zpci_msi_set_mask_bits(struct msi_desc *, u32, u32);
-int zpci_setup_msi_irq(struct zpci_dev *, struct msi_desc *, unsigned int, int);
-void zpci_teardown_msi_irq(struct zpci_dev *, struct msi_desc *);
-int zpci_msihash_init(void);
-void zpci_msihash_exit(void);
-
 #ifdef CONFIG_PCI
 /* Error handling and recovery */
 void zpci_event_error(void *);
index e6a2bdd4d7059e4e5bfa9e86c77a08554f6cfb1a..df6eac9f0cb4e324069e3bae65246a7a99f02888 100644 (file)
@@ -79,11 +79,11 @@ struct zpci_fib {
 } __packed;
 
 
-int s390pci_mod_fc(u64 req, struct zpci_fib *fib);
-int s390pci_refresh_trans(u64 fn, u64 addr, u64 range);
-int s390pci_load(u64 *data, u64 req, u64 offset);
-int s390pci_store(u64 data, u64 req, u64 offset);
-int s390pci_store_block(const u64 *data, u64 req, u64 offset);
-void set_irq_ctrl(u16 ctl, char *unused, u8 isc);
+int zpci_mod_fc(u64 req, struct zpci_fib *fib);
+int zpci_refresh_trans(u64 fn, u64 addr, u64 range);
+int zpci_load(u64 *data, u64 req, u64 offset);
+int zpci_store(u64 data, u64 req, u64 offset);
+int zpci_store_block(const u64 *data, u64 req, u64 offset);
+void zpci_set_irq_ctrl(u16 ctl, char *unused, u8 isc);
 
 #endif
index 83a9caa6ae530fb1f500d86c3bf207f32f2a8b21..d194d544d6943df1f39d31087cbe9acdf0fc449c 100644 (file)
@@ -36,7 +36,7 @@ static inline RETTYPE zpci_read_##RETTYPE(const volatile void __iomem *addr)  \
        u64 data;                                                               \
        int rc;                                                                 \
                                                                                \
-       rc = s390pci_load(&data, req, ZPCI_OFFSET(addr));                       \
+       rc = zpci_load(&data, req, ZPCI_OFFSET(addr));                          \
        if (rc)                                                                 \
                data = -1ULL;                                                   \
        return (RETTYPE) data;                                                  \
@@ -50,7 +50,7 @@ static inline void zpci_write_##VALTYPE(VALTYPE val,                          \
        u64 req = ZPCI_CREATE_REQ(entry->fh, entry->bar, LENGTH);               \
        u64 data = (VALTYPE) val;                                               \
                                                                                \
-       s390pci_store(data, req, ZPCI_OFFSET(addr));                            \
+       zpci_store(data, req, ZPCI_OFFSET(addr));                               \
 }
 
 zpci_read(8, u64)
@@ -83,7 +83,7 @@ static inline int zpci_write_single(u64 req, const u64 *data, u64 offset, u8 len
                val = 0;                /* let FW report error */
                break;
        }
-       return s390pci_store(val, req, offset);
+       return zpci_store(val, req, offset);
 }
 
 static inline int zpci_read_single(u64 req, u64 *dst, u64 offset, u8 len)
@@ -91,7 +91,7 @@ static inline int zpci_read_single(u64 req, u64 *dst, u64 offset, u8 len)
        u64 data;
        int cc;
 
-       cc = s390pci_load(&data, req, offset);
+       cc = zpci_load(&data, req, offset);
        if (cc)
                goto out;
 
@@ -115,7 +115,7 @@ out:
 
 static inline int zpci_write_block(u64 req, const u64 *data, u64 offset)
 {
-       return s390pci_store_block(data, req, offset);
+       return zpci_store_block(data, req, offset);
 }
 
 static inline u8 zpci_get_max_write_size(u64 src, u64 dst, int len, int max)
index 75fb726de91f802a68293d67c3b8541281044d3c..9ff99931f9aa0268c19e05793fbc914480670484 100644 (file)
@@ -217,63 +217,50 @@ extern unsigned long MODULES_END;
 
 /* Hardware bits in the page table entry */
 #define _PAGE_CO       0x100           /* HW Change-bit override */
-#define _PAGE_RO       0x200           /* HW read-only bit  */
+#define _PAGE_PROTECT  0x200           /* HW read-only bit  */
 #define _PAGE_INVALID  0x400           /* HW invalid bit    */
+#define _PAGE_LARGE    0x800           /* Bit to mark a large pte */
 
 /* Software bits in the page table entry */
-#define _PAGE_SWT      0x001           /* SW pte type bit t */
-#define _PAGE_SWX      0x002           /* SW pte type bit x */
-#define _PAGE_SWC      0x004           /* SW pte changed bit */
-#define _PAGE_SWR      0x008           /* SW pte referenced bit */
-#define _PAGE_SWW      0x010           /* SW pte write bit */
+#define _PAGE_PRESENT  0x001           /* SW pte present bit */
+#define _PAGE_TYPE     0x002           /* SW pte type bit */
+#define _PAGE_DIRTY    0x004           /* SW pte dirty bit */
+#define _PAGE_YOUNG    0x008           /* SW pte young bit */
+#define _PAGE_WRITE    0x010           /* SW pte write bit */
 #define _PAGE_SPECIAL  0x020           /* SW associated with special page */
 #define __HAVE_ARCH_PTE_SPECIAL
 
 /* Set of bits not changed in pte_modify */
 #define _PAGE_CHG_MASK         (PAGE_MASK | _PAGE_SPECIAL | _PAGE_CO | \
-                                _PAGE_SWC | _PAGE_SWR)
-
-/* Six different types of pages. */
-#define _PAGE_TYPE_EMPTY       0x400
-#define _PAGE_TYPE_NONE                0x401
-#define _PAGE_TYPE_SWAP                0x403
-#define _PAGE_TYPE_FILE                0x601   /* bit 0x002 is used for offset !! */
-#define _PAGE_TYPE_RO          0x200
-#define _PAGE_TYPE_RW          0x000
-
-/*
- * Only four types for huge pages, using the invalid bit and protection bit
- * of a segment table entry.
- */
-#define _HPAGE_TYPE_EMPTY      0x020   /* _SEGMENT_ENTRY_INV */
-#define _HPAGE_TYPE_NONE       0x220
-#define _HPAGE_TYPE_RO         0x200   /* _SEGMENT_ENTRY_RO  */
-#define _HPAGE_TYPE_RW         0x000
+                                _PAGE_DIRTY | _PAGE_YOUNG)
 
 /*
- * PTE type bits are rather complicated. handle_pte_fault uses pte_present,
- * pte_none and pte_file to find out the pte type WITHOUT holding the page
- * table lock. ptep_clear_flush on the other hand uses ptep_clear_flush to
- * invalidate a given pte. ipte sets the hw invalid bit and clears all tlbs
- * for the page. The page table entry is set to _PAGE_TYPE_EMPTY afterwards.
- * This change is done while holding the lock, but the intermediate step
- * of a previously valid pte with the hw invalid bit set can be observed by
- * handle_pte_fault. That makes it necessary that all valid pte types with
- * the hw invalid bit set must be distinguishable from the four pte types
- * empty, none, swap and file.
+ * handle_pte_fault uses pte_present, pte_none and pte_file to find out the
+ * pte type WITHOUT holding the page table lock. The _PAGE_PRESENT bit
+ * is used to distinguish present from not-present ptes. It is changed only
+ * with the page table lock held.
+ *
+ * The following table gives the different possible bit combinations for
+ * the pte hardware and software bits in the last 12 bits of a pte:
  *
- *                     irxt  ipte  irxt
- * _PAGE_TYPE_EMPTY    1000   ->   1000
- * _PAGE_TYPE_NONE     1001   ->   1001
- * _PAGE_TYPE_SWAP     1011   ->   1011
- * _PAGE_TYPE_FILE     11?1   ->   11?1
- * _PAGE_TYPE_RO       0100   ->   1100
- * _PAGE_TYPE_RW       0000   ->   1000
+ *                     842100000000
+ *                     000084210000
+ *                     000000008421
+ *                     .IR....wdytp
+ * empty               .10....00000
+ * swap                        .10....xxx10
+ * file                        .11....xxxx0
+ * prot-none, clean    .10....00x01
+ * prot-none, dirty    .10....01x01
+ * read-only, clean    .01....00x01
+ * read-only, dirty    .01....01x01
+ * read-write, clean   .01....10x01
+ * read-write, dirty   .00....11x01
  *
- * pte_none is true for bits combinations 1000, 1010, 1100, 1110
- * pte_present is true for bits combinations 0000, 0010, 0100, 0110, 1001
- * pte_file is true for bits combinations 1101, 1111
- * swap pte is 1011 and 0001, 0011, 0101, 0111 are invalid.
+ * pte_present is true for the bit pattern .xx...xxxxx1, (pte & 0x001) == 0x001
+ * pte_none    is true for the bit pattern .10...xxxx00, (pte & 0x603) == 0x400
+ * pte_file    is true for the bit pattern .11...xxxxx0, (pte & 0x601) == 0x600
+ * pte_swap    is true for the bit pattern .10...xxxx10, (pte & 0x603) == 0x402
  */
 
 #ifndef CONFIG_64BIT
@@ -287,13 +274,13 @@ extern unsigned long MODULES_END;
 
 /* Bits in the segment table entry */
 #define _SEGMENT_ENTRY_ORIGIN  0x7fffffc0UL    /* page table origin        */
-#define _SEGMENT_ENTRY_RO      0x200   /* page protection bit              */
-#define _SEGMENT_ENTRY_INV     0x20    /* invalid segment table entry      */
+#define _SEGMENT_ENTRY_PROTECT 0x200   /* page protection bit              */
+#define _SEGMENT_ENTRY_INVALID 0x20    /* invalid segment table entry      */
 #define _SEGMENT_ENTRY_COMMON  0x10    /* common segment bit               */
 #define _SEGMENT_ENTRY_PTL     0x0f    /* page table length                */
 
 #define _SEGMENT_ENTRY         (_SEGMENT_ENTRY_PTL)
-#define _SEGMENT_ENTRY_EMPTY   (_SEGMENT_ENTRY_INV)
+#define _SEGMENT_ENTRY_EMPTY   (_SEGMENT_ENTRY_INVALID)
 
 /* Page status table bits for virtualization */
 #define PGSTE_ACC_BITS 0xf0000000UL
@@ -324,8 +311,8 @@ extern unsigned long MODULES_END;
 
 /* Bits in the region table entry */
 #define _REGION_ENTRY_ORIGIN   ~0xfffUL/* region/segment table origin      */
-#define _REGION_ENTRY_RO       0x200   /* region protection bit            */
-#define _REGION_ENTRY_INV      0x20    /* invalid region table entry       */
+#define _REGION_ENTRY_PROTECT  0x200   /* region protection bit            */
+#define _REGION_ENTRY_INVALID  0x20    /* invalid region table entry       */
 #define _REGION_ENTRY_TYPE_MASK        0x0c    /* region/segment table type mask   */
 #define _REGION_ENTRY_TYPE_R1  0x0c    /* region first table type          */
 #define _REGION_ENTRY_TYPE_R2  0x08    /* region second table type         */
@@ -333,11 +320,11 @@ extern unsigned long MODULES_END;
 #define _REGION_ENTRY_LENGTH   0x03    /* region third length              */
 
 #define _REGION1_ENTRY         (_REGION_ENTRY_TYPE_R1 | _REGION_ENTRY_LENGTH)
-#define _REGION1_ENTRY_EMPTY   (_REGION_ENTRY_TYPE_R1 | _REGION_ENTRY_INV)
+#define _REGION1_ENTRY_EMPTY   (_REGION_ENTRY_TYPE_R1 | _REGION_ENTRY_INVALID)
 #define _REGION2_ENTRY         (_REGION_ENTRY_TYPE_R2 | _REGION_ENTRY_LENGTH)
-#define _REGION2_ENTRY_EMPTY   (_REGION_ENTRY_TYPE_R2 | _REGION_ENTRY_INV)
+#define _REGION2_ENTRY_EMPTY   (_REGION_ENTRY_TYPE_R2 | _REGION_ENTRY_INVALID)
 #define _REGION3_ENTRY         (_REGION_ENTRY_TYPE_R3 | _REGION_ENTRY_LENGTH)
-#define _REGION3_ENTRY_EMPTY   (_REGION_ENTRY_TYPE_R3 | _REGION_ENTRY_INV)
+#define _REGION3_ENTRY_EMPTY   (_REGION_ENTRY_TYPE_R3 | _REGION_ENTRY_INVALID)
 
 #define _REGION3_ENTRY_LARGE   0x400   /* RTTE-format control, large page  */
 #define _REGION3_ENTRY_RO      0x200   /* page protection bit              */
@@ -346,16 +333,17 @@ extern unsigned long MODULES_END;
 /* Bits in the segment table entry */
 #define _SEGMENT_ENTRY_ORIGIN_LARGE ~0xfffffUL /* large page address       */
 #define _SEGMENT_ENTRY_ORIGIN  ~0x7ffUL/* segment table origin             */
-#define _SEGMENT_ENTRY_RO      0x200   /* page protection bit              */
-#define _SEGMENT_ENTRY_INV     0x20    /* invalid segment table entry      */
+#define _SEGMENT_ENTRY_PROTECT 0x200   /* page protection bit              */
+#define _SEGMENT_ENTRY_INVALID 0x20    /* invalid segment table entry      */
 
 #define _SEGMENT_ENTRY         (0)
-#define _SEGMENT_ENTRY_EMPTY   (_SEGMENT_ENTRY_INV)
+#define _SEGMENT_ENTRY_EMPTY   (_SEGMENT_ENTRY_INVALID)
 
 #define _SEGMENT_ENTRY_LARGE   0x400   /* STE-format control, large page   */
 #define _SEGMENT_ENTRY_CO      0x100   /* change-recording override   */
+#define _SEGMENT_ENTRY_SPLIT   0x001   /* THP splitting bit */
+
 #define _SEGMENT_ENTRY_SPLIT_BIT 0     /* THP splitting bit number */
-#define _SEGMENT_ENTRY_SPLIT   (1UL << _SEGMENT_ENTRY_SPLIT_BIT)
 
 /* Set of bits not changed in pmd_modify */
 #define _SEGMENT_CHG_MASK      (_SEGMENT_ENTRY_ORIGIN | _SEGMENT_ENTRY_LARGE \
@@ -386,14 +374,13 @@ extern unsigned long MODULES_END;
 /*
  * Page protection definitions.
  */
-#define PAGE_NONE      __pgprot(_PAGE_TYPE_NONE)
-#define PAGE_RO                __pgprot(_PAGE_TYPE_RO)
-#define PAGE_RW                __pgprot(_PAGE_TYPE_RO | _PAGE_SWW)
-#define PAGE_RWC       __pgprot(_PAGE_TYPE_RW | _PAGE_SWW | _PAGE_SWC)
+#define PAGE_NONE      __pgprot(_PAGE_PRESENT | _PAGE_INVALID)
+#define PAGE_READ      __pgprot(_PAGE_PRESENT | _PAGE_PROTECT)
+#define PAGE_WRITE     __pgprot(_PAGE_PRESENT | _PAGE_WRITE | _PAGE_PROTECT)
 
-#define PAGE_KERNEL    PAGE_RWC
-#define PAGE_SHARED    PAGE_KERNEL
-#define PAGE_COPY      PAGE_RO
+#define PAGE_SHARED    __pgprot(_PAGE_PRESENT | _PAGE_WRITE | _PAGE_DIRTY)
+#define PAGE_KERNEL    __pgprot(_PAGE_PRESENT | _PAGE_WRITE | _PAGE_DIRTY)
+#define PAGE_KERNEL_RO __pgprot(_PAGE_PRESENT | _PAGE_PROTECT)
 
 /*
  * On s390 the page table entry has an invalid bit and a read-only bit.
@@ -402,29 +389,30 @@ extern unsigned long MODULES_END;
  */
          /*xwr*/
 #define __P000 PAGE_NONE
-#define __P001 PAGE_RO
-#define __P010 PAGE_RO
-#define __P011 PAGE_RO
-#define __P100 PAGE_RO
-#define __P101 PAGE_RO
-#define __P110 PAGE_RO
-#define __P111 PAGE_RO
+#define __P001 PAGE_READ
+#define __P010 PAGE_READ
+#define __P011 PAGE_READ
+#define __P100 PAGE_READ
+#define __P101 PAGE_READ
+#define __P110 PAGE_READ
+#define __P111 PAGE_READ
 
 #define __S000 PAGE_NONE
-#define __S001 PAGE_RO
-#define __S010 PAGE_RW
-#define __S011 PAGE_RW
-#define __S100 PAGE_RO
-#define __S101 PAGE_RO
-#define __S110 PAGE_RW
-#define __S111 PAGE_RW
+#define __S001 PAGE_READ
+#define __S010 PAGE_WRITE
+#define __S011 PAGE_WRITE
+#define __S100 PAGE_READ
+#define __S101 PAGE_READ
+#define __S110 PAGE_WRITE
+#define __S111 PAGE_WRITE
 
 /*
  * Segment entry (large page) protection definitions.
  */
-#define SEGMENT_NONE   __pgprot(_HPAGE_TYPE_NONE)
-#define SEGMENT_RO     __pgprot(_HPAGE_TYPE_RO)
-#define SEGMENT_RW     __pgprot(_HPAGE_TYPE_RW)
+#define SEGMENT_NONE   __pgprot(_SEGMENT_ENTRY_INVALID | \
+                                _SEGMENT_ENTRY_PROTECT)
+#define SEGMENT_READ   __pgprot(_SEGMENT_ENTRY_PROTECT)
+#define SEGMENT_WRITE  __pgprot(0)
 
 static inline int mm_exclusive(struct mm_struct *mm)
 {
@@ -467,7 +455,7 @@ static inline int pgd_none(pgd_t pgd)
 {
        if ((pgd_val(pgd) & _REGION_ENTRY_TYPE_MASK) < _REGION_ENTRY_TYPE_R2)
                return 0;
-       return (pgd_val(pgd) & _REGION_ENTRY_INV) != 0UL;
+       return (pgd_val(pgd) & _REGION_ENTRY_INVALID) != 0UL;
 }
 
 static inline int pgd_bad(pgd_t pgd)
@@ -478,7 +466,7 @@ static inline int pgd_bad(pgd_t pgd)
         * invalid for either table entry.
         */
        unsigned long mask =
-               ~_SEGMENT_ENTRY_ORIGIN & ~_REGION_ENTRY_INV &
+               ~_SEGMENT_ENTRY_ORIGIN & ~_REGION_ENTRY_INVALID &
                ~_REGION_ENTRY_TYPE_MASK & ~_REGION_ENTRY_LENGTH;
        return (pgd_val(pgd) & mask) != 0;
 }
@@ -494,7 +482,7 @@ static inline int pud_none(pud_t pud)
 {
        if ((pud_val(pud) & _REGION_ENTRY_TYPE_MASK) < _REGION_ENTRY_TYPE_R3)
                return 0;
-       return (pud_val(pud) & _REGION_ENTRY_INV) != 0UL;
+       return (pud_val(pud) & _REGION_ENTRY_INVALID) != 0UL;
 }
 
 static inline int pud_large(pud_t pud)
@@ -512,7 +500,7 @@ static inline int pud_bad(pud_t pud)
         * invalid for either table entry.
         */
        unsigned long mask =
-               ~_SEGMENT_ENTRY_ORIGIN & ~_REGION_ENTRY_INV &
+               ~_SEGMENT_ENTRY_ORIGIN & ~_REGION_ENTRY_INVALID &
                ~_REGION_ENTRY_TYPE_MASK & ~_REGION_ENTRY_LENGTH;
        return (pud_val(pud) & mask) != 0;
 }
@@ -521,21 +509,18 @@ static inline int pud_bad(pud_t pud)
 
 static inline int pmd_present(pmd_t pmd)
 {
-       unsigned long mask = _SEGMENT_ENTRY_INV | _SEGMENT_ENTRY_RO;
-       return (pmd_val(pmd) & mask) == _HPAGE_TYPE_NONE ||
-              !(pmd_val(pmd) & _SEGMENT_ENTRY_INV);
+       return pmd_val(pmd) != _SEGMENT_ENTRY_INVALID;
 }
 
 static inline int pmd_none(pmd_t pmd)
 {
-       return (pmd_val(pmd) & _SEGMENT_ENTRY_INV) &&
-              !(pmd_val(pmd) & _SEGMENT_ENTRY_RO);
+       return pmd_val(pmd) == _SEGMENT_ENTRY_INVALID;
 }
 
 static inline int pmd_large(pmd_t pmd)
 {
 #ifdef CONFIG_64BIT
-       return !!(pmd_val(pmd) & _SEGMENT_ENTRY_LARGE);
+       return (pmd_val(pmd) & _SEGMENT_ENTRY_LARGE) != 0;
 #else
        return 0;
 #endif
@@ -543,7 +528,7 @@ static inline int pmd_large(pmd_t pmd)
 
 static inline int pmd_bad(pmd_t pmd)
 {
-       unsigned long mask = ~_SEGMENT_ENTRY_ORIGIN & ~_SEGMENT_ENTRY_INV;
+       unsigned long mask = ~_SEGMENT_ENTRY_ORIGIN & ~_SEGMENT_ENTRY_INVALID;
        return (pmd_val(pmd) & mask) != _SEGMENT_ENTRY;
 }
 
@@ -563,7 +548,7 @@ extern int pmdp_clear_flush_young(struct vm_area_struct *vma,
 #define __HAVE_ARCH_PMD_WRITE
 static inline int pmd_write(pmd_t pmd)
 {
-       return (pmd_val(pmd) & _SEGMENT_ENTRY_RO) == 0;
+       return (pmd_val(pmd) & _SEGMENT_ENTRY_PROTECT) == 0;
 }
 
 static inline int pmd_young(pmd_t pmd)
@@ -571,23 +556,23 @@ static inline int pmd_young(pmd_t pmd)
        return 0;
 }
 
-static inline int pte_none(pte_t pte)
+static inline int pte_present(pte_t pte)
 {
-       return (pte_val(pte) & _PAGE_INVALID) && !(pte_val(pte) & _PAGE_SWT);
+       /* Bit pattern: (pte & 0x001) == 0x001 */
+       return (pte_val(pte) & _PAGE_PRESENT) != 0;
 }
 
-static inline int pte_present(pte_t pte)
+static inline int pte_none(pte_t pte)
 {
-       unsigned long mask = _PAGE_RO | _PAGE_INVALID | _PAGE_SWT | _PAGE_SWX;
-       return (pte_val(pte) & mask) == _PAGE_TYPE_NONE ||
-               (!(pte_val(pte) & _PAGE_INVALID) &&
-                !(pte_val(pte) & _PAGE_SWT));
+       /* Bit pattern: pte == 0x400 */
+       return pte_val(pte) == _PAGE_INVALID;
 }
 
 static inline int pte_file(pte_t pte)
 {
-       unsigned long mask = _PAGE_RO | _PAGE_INVALID | _PAGE_SWT;
-       return (pte_val(pte) & mask) == _PAGE_TYPE_FILE;
+       /* Bit pattern: (pte & 0x601) == 0x600 */
+       return (pte_val(pte) & (_PAGE_INVALID | _PAGE_PROTECT | _PAGE_PRESENT))
+               == (_PAGE_INVALID | _PAGE_PROTECT);
 }
 
 static inline int pte_special(pte_t pte)
@@ -634,6 +619,15 @@ static inline void pgste_set_unlock(pte_t *ptep, pgste_t pgste)
 #endif
 }
 
+static inline pgste_t pgste_get(pte_t *ptep)
+{
+       unsigned long pgste = 0;
+#ifdef CONFIG_PGSTE
+       pgste = *(unsigned long *)(ptep + PTRS_PER_PTE);
+#endif
+       return __pgste(pgste);
+}
+
 static inline void pgste_set(pte_t *ptep, pgste_t pgste)
 {
 #ifdef CONFIG_PGSTE
@@ -695,7 +689,7 @@ static inline pgste_t pgste_update_young(pte_t *ptep, pgste_t pgste)
        /* Transfer referenced bit to kvm user bits and pte */
        if (young) {
                pgste_val(pgste) |= PGSTE_UR_BIT;
-               pte_val(*ptep) |= _PAGE_SWR;
+               pte_val(*ptep) |= _PAGE_YOUNG;
        }
 #endif
        return pgste;
@@ -723,13 +717,13 @@ static inline void pgste_set_key(pte_t *ptep, pgste_t pgste, pte_t entry)
 
 static inline void pgste_set_pte(pte_t *ptep, pte_t entry)
 {
-       if (!MACHINE_HAS_ESOP && (pte_val(entry) & _PAGE_SWW)) {
+       if (!MACHINE_HAS_ESOP && (pte_val(entry) & _PAGE_WRITE)) {
                /*
                 * Without enhanced suppression-on-protection force
                 * the dirty bit on for all writable ptes.
                 */
-               pte_val(entry) |= _PAGE_SWC;
-               pte_val(entry) &= ~_PAGE_RO;
+               pte_val(entry) |= _PAGE_DIRTY;
+               pte_val(entry) &= ~_PAGE_PROTECT;
        }
        *ptep = entry;
 }
@@ -841,18 +835,18 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
  */
 static inline int pte_write(pte_t pte)
 {
-       return (pte_val(pte) & _PAGE_SWW) != 0;
+       return (pte_val(pte) & _PAGE_WRITE) != 0;
 }
 
 static inline int pte_dirty(pte_t pte)
 {
-       return (pte_val(pte) & _PAGE_SWC) != 0;
+       return (pte_val(pte) & _PAGE_DIRTY) != 0;
 }
 
 static inline int pte_young(pte_t pte)
 {
 #ifdef CONFIG_PGSTE
-       if (pte_val(pte) & _PAGE_SWR)
+       if (pte_val(pte) & _PAGE_YOUNG)
                return 1;
 #endif
        return 0;
@@ -880,12 +874,12 @@ static inline void pud_clear(pud_t *pud)
 
 static inline void pmd_clear(pmd_t *pmdp)
 {
-       pmd_val(*pmdp) = _SEGMENT_ENTRY_EMPTY;
+       pmd_val(*pmdp) = _SEGMENT_ENTRY_INVALID;
 }
 
 static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
-       pte_val(*ptep) = _PAGE_TYPE_EMPTY;
+       pte_val(*ptep) = _PAGE_INVALID;
 }
 
 /*
@@ -896,49 +890,49 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
        pte_val(pte) &= _PAGE_CHG_MASK;
        pte_val(pte) |= pgprot_val(newprot);
-       if ((pte_val(pte) & _PAGE_SWC) && (pte_val(pte) & _PAGE_SWW))
-               pte_val(pte) &= ~_PAGE_RO;
+       if ((pte_val(pte) & _PAGE_DIRTY) && (pte_val(pte) & _PAGE_WRITE))
+               pte_val(pte) &= ~_PAGE_PROTECT;
        return pte;
 }
 
 static inline pte_t pte_wrprotect(pte_t pte)
 {
-       pte_val(pte) &= ~_PAGE_SWW;
-       /* Do not clobber _PAGE_TYPE_NONE pages!  */
+       pte_val(pte) &= ~_PAGE_WRITE;
+       /* Do not clobber PROT_NONE pages!  */
        if (!(pte_val(pte) & _PAGE_INVALID))
-               pte_val(pte) |= _PAGE_RO;
+               pte_val(pte) |= _PAGE_PROTECT;
        return pte;
 }
 
 static inline pte_t pte_mkwrite(pte_t pte)
 {
-       pte_val(pte) |= _PAGE_SWW;
-       if (pte_val(pte) & _PAGE_SWC)
-               pte_val(pte) &= ~_PAGE_RO;
+       pte_val(pte) |= _PAGE_WRITE;
+       if (pte_val(pte) & _PAGE_DIRTY)
+               pte_val(pte) &= ~_PAGE_PROTECT;
        return pte;
 }
 
 static inline pte_t pte_mkclean(pte_t pte)
 {
-       pte_val(pte) &= ~_PAGE_SWC;
-       /* Do not clobber _PAGE_TYPE_NONE pages!  */
+       pte_val(pte) &= ~_PAGE_DIRTY;
+       /* Do not clobber PROT_NONE pages!  */
        if (!(pte_val(pte) & _PAGE_INVALID))
-               pte_val(pte) |= _PAGE_RO;
+               pte_val(pte) |= _PAGE_PROTECT;
        return pte;
 }
 
 static inline pte_t pte_mkdirty(pte_t pte)
 {
-       pte_val(pte) |= _PAGE_SWC;
-       if (pte_val(pte) & _PAGE_SWW)
-               pte_val(pte) &= ~_PAGE_RO;
+       pte_val(pte) |= _PAGE_DIRTY;
+       if (pte_val(pte) & _PAGE_WRITE)
+               pte_val(pte) &= ~_PAGE_PROTECT;
        return pte;
 }
 
 static inline pte_t pte_mkold(pte_t pte)
 {
 #ifdef CONFIG_PGSTE
-       pte_val(pte) &= ~_PAGE_SWR;
+       pte_val(pte) &= ~_PAGE_YOUNG;
 #endif
        return pte;
 }
@@ -957,7 +951,7 @@ static inline pte_t pte_mkspecial(pte_t pte)
 #ifdef CONFIG_HUGETLB_PAGE
 static inline pte_t pte_mkhuge(pte_t pte)
 {
-       pte_val(pte) |= (_SEGMENT_ENTRY_LARGE | _SEGMENT_ENTRY_CO);
+       pte_val(pte) |= _PAGE_LARGE;
        return pte;
 }
 #endif
@@ -1076,7 +1070,7 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
        pte = *ptep;
        if (!mm_exclusive(mm))
                __ptep_ipte(address, ptep);
-       pte_val(*ptep) = _PAGE_TYPE_EMPTY;
+       pte_val(*ptep) = _PAGE_INVALID;
 
        if (mm_has_pgste(mm)) {
                pgste = pgste_update_all(&pte, pgste);
@@ -1117,7 +1111,7 @@ static inline void ptep_modify_prot_commit(struct mm_struct *mm,
        pgste_t pgste;
 
        if (mm_has_pgste(mm)) {
-               pgste = *(pgste_t *)(ptep + PTRS_PER_PTE);
+               pgste = pgste_get(ptep);
                pgste_set_key(ptep, pgste, pte);
                pgste_set_pte(ptep, pte);
                pgste_set_unlock(ptep, pgste);
@@ -1139,7 +1133,7 @@ static inline pte_t ptep_clear_flush(struct vm_area_struct *vma,
 
        pte = *ptep;
        __ptep_ipte(address, ptep);
-       pte_val(*ptep) = _PAGE_TYPE_EMPTY;
+       pte_val(*ptep) = _PAGE_INVALID;
 
        if (mm_has_pgste(vma->vm_mm)) {
                pgste = pgste_update_all(&pte, pgste);
@@ -1163,18 +1157,17 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm,
        pgste_t pgste;
        pte_t pte;
 
-       if (mm_has_pgste(mm)) {
+       if (!full && mm_has_pgste(mm)) {
                pgste = pgste_get_lock(ptep);
-               if (!full)
-                       pgste = pgste_ipte_notify(mm, address, ptep, pgste);
+               pgste = pgste_ipte_notify(mm, address, ptep, pgste);
        }
 
        pte = *ptep;
        if (!full)
                __ptep_ipte(address, ptep);
-       pte_val(*ptep) = _PAGE_TYPE_EMPTY;
+       pte_val(*ptep) = _PAGE_INVALID;
 
-       if (mm_has_pgste(mm)) {
+       if (!full && mm_has_pgste(mm)) {
                pgste = pgste_update_all(&pte, pgste);
                pgste_set_unlock(ptep, pgste);
        }
@@ -1248,10 +1241,8 @@ static inline pte_t mk_pte(struct page *page, pgprot_t pgprot)
        unsigned long physpage = page_to_phys(page);
        pte_t __pte = mk_pte_phys(physpage, pgprot);
 
-       if ((pte_val(__pte) & _PAGE_SWW) && PageDirty(page)) {
-               pte_val(__pte) |= _PAGE_SWC;
-               pte_val(__pte) &= ~_PAGE_RO;
-       }
+       if (pte_write(__pte) && PageDirty(page))
+               __pte = pte_mkdirty(__pte);
        return __pte;
 }
 
@@ -1313,7 +1304,7 @@ static inline void __pmd_idte(unsigned long address, pmd_t *pmdp)
        unsigned long sto = (unsigned long) pmdp -
                            pmd_index(address) * sizeof(pmd_t);
 
-       if (!(pmd_val(*pmdp) & _SEGMENT_ENTRY_INV)) {
+       if (!(pmd_val(*pmdp) & _SEGMENT_ENTRY_INVALID)) {
                asm volatile(
                        "       .insn   rrf,0xb98e0000,%2,%3,0,0"
                        : "=m" (*pmdp)
@@ -1324,18 +1315,31 @@ static inline void __pmd_idte(unsigned long address, pmd_t *pmdp)
        }
 }
 
+static inline void __pmd_csp(pmd_t *pmdp)
+{
+       register unsigned long reg2 asm("2") = pmd_val(*pmdp);
+       register unsigned long reg3 asm("3") = pmd_val(*pmdp) |
+                                              _SEGMENT_ENTRY_INVALID;
+       register unsigned long reg4 asm("4") = ((unsigned long) pmdp) + 5;
+
+       asm volatile(
+               "       csp %1,%3"
+               : "=m" (*pmdp)
+               : "d" (reg2), "d" (reg3), "d" (reg4), "m" (*pmdp) : "cc");
+}
+
 #if defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined(CONFIG_HUGETLB_PAGE)
 static inline unsigned long massage_pgprot_pmd(pgprot_t pgprot)
 {
        /*
-        * pgprot is PAGE_NONE, PAGE_RO, or PAGE_RW (see __Pxxx / __Sxxx)
+        * pgprot is PAGE_NONE, PAGE_READ, or PAGE_WRITE (see __Pxxx / __Sxxx)
         * Convert to segment table entry format.
         */
        if (pgprot_val(pgprot) == pgprot_val(PAGE_NONE))
                return pgprot_val(SEGMENT_NONE);
-       if (pgprot_val(pgprot) == pgprot_val(PAGE_RO))
-               return pgprot_val(SEGMENT_RO);
-       return pgprot_val(SEGMENT_RW);
+       if (pgprot_val(pgprot) == pgprot_val(PAGE_READ))
+               return pgprot_val(SEGMENT_READ);
+       return pgprot_val(SEGMENT_WRITE);
 }
 
 static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
@@ -1354,9 +1358,9 @@ static inline pmd_t mk_pmd_phys(unsigned long physpage, pgprot_t pgprot)
 
 static inline pmd_t pmd_mkwrite(pmd_t pmd)
 {
-       /* Do not clobber _HPAGE_TYPE_NONE pages! */
-       if (!(pmd_val(pmd) & _SEGMENT_ENTRY_INV))
-               pmd_val(pmd) &= ~_SEGMENT_ENTRY_RO;
+       /* Do not clobber PROT_NONE pages! */
+       if (!(pmd_val(pmd) & _SEGMENT_ENTRY_INVALID))
+               pmd_val(pmd) &= ~_SEGMENT_ENTRY_PROTECT;
        return pmd;
 }
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE || CONFIG_HUGETLB_PAGE */
@@ -1378,7 +1382,7 @@ static inline int pmd_trans_splitting(pmd_t pmd)
 static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,
                              pmd_t *pmdp, pmd_t entry)
 {
-       if (!(pmd_val(entry) & _SEGMENT_ENTRY_INV) && MACHINE_HAS_EDAT1)
+       if (!(pmd_val(entry) & _SEGMENT_ENTRY_INVALID) && MACHINE_HAS_EDAT1)
                pmd_val(entry) |= _SEGMENT_ENTRY_CO;
        *pmdp = entry;
 }
@@ -1391,7 +1395,7 @@ static inline pmd_t pmd_mkhuge(pmd_t pmd)
 
 static inline pmd_t pmd_wrprotect(pmd_t pmd)
 {
-       pmd_val(pmd) |= _SEGMENT_ENTRY_RO;
+       pmd_val(pmd) |= _SEGMENT_ENTRY_PROTECT;
        return pmd;
 }
 
@@ -1547,7 +1551,7 @@ static inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
 {
        pte_t pte;
        offset &= __SWP_OFFSET_MASK;
-       pte_val(pte) = _PAGE_TYPE_SWAP | ((type & 0x1f) << 2) |
+       pte_val(pte) = _PAGE_INVALID | _PAGE_TYPE | ((type & 0x1f) << 2) |
                ((offset & 1UL) << 7) | ((offset & ~1UL) << 11);
        return pte;
 }
@@ -1570,7 +1574,7 @@ static inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
 
 #define pgoff_to_pte(__off) \
        ((pte_t) { ((((__off) & 0x7f) << 1) + (((__off) >> 7) << 12)) \
-                  | _PAGE_TYPE_FILE })
+                  | _PAGE_INVALID | _PAGE_PROTECT })
 
 #endif /* !__ASSEMBLY__ */
 
diff --git a/arch/s390/include/asm/serial.h b/arch/s390/include/asm/serial.h
new file mode 100644 (file)
index 0000000..5b3e48e
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _ASM_S390_SERIAL_H
+#define _ASM_S390_SERIAL_H
+
+#define BASE_BAUD 0
+
+#endif /* _ASM_S390_SERIAL_H */
index be7a408be7a16bafde657665edb36fcde01c8866..5ca70b4b72cb63d3585f68d97fb5d845db706ef6 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/unistd.h>
 #include <asm/page.h>
 #include <asm/sigp.h>
+#include <asm/irq.h>
 
 __PT_R0      = __PT_GPRS
 __PT_R1      = __PT_GPRS + 4
@@ -435,6 +436,11 @@ io_skip:
 io_loop:
        l       %r1,BASED(.Ldo_IRQ)
        lr      %r2,%r11                # pass pointer to pt_regs
+       lhi     %r3,IO_INTERRUPT
+       tm      __PT_INT_CODE+8(%r11),0x80      # adapter interrupt ?
+       jz      io_call
+       lhi     %r3,THIN_INTERRUPT
+io_call:
        basr    %r14,%r1                # call do_IRQ
        tm      __LC_MACHINE_FLAGS+2,0x10       # MACHINE_FLAG_LPAR
        jz      io_return
@@ -584,9 +590,10 @@ ext_skip:
        mvc     __PT_INT_CODE(4,%r11),__LC_EXT_CPU_ADDR
        mvc     __PT_INT_PARM(4,%r11),__LC_EXT_PARAMS
        TRACE_IRQS_OFF
+       l       %r1,BASED(.Ldo_IRQ)
        lr      %r2,%r11                # pass pointer to pt_regs
-       l       %r1,BASED(.Ldo_extint)
-       basr    %r14,%r1                # call do_extint
+       lhi     %r3,EXT_INTERRUPT
+       basr    %r14,%r1                # call do_IRQ
        j       io_return
 
 /*
@@ -902,7 +909,6 @@ cleanup_idle_wait:
 .Ldo_machine_check:    .long   s390_do_machine_check
 .Lhandle_mcck:         .long   s390_handle_mcck
 .Ldo_IRQ:              .long   do_IRQ
-.Ldo_extint:           .long   do_extint
 .Ldo_signal:           .long   do_signal
 .Ldo_notify_resume:    .long   do_notify_resume
 .Ldo_per_trap:         .long   do_per_trap
index 1c039d0c24c7e8b6b65e1aec20307adcabca581b..980c7aa1cc5ca2bee34c9af1f977f9e39783c31a 100644 (file)
@@ -19,6 +19,7 @@
 #include <asm/unistd.h>
 #include <asm/page.h>
 #include <asm/sigp.h>
+#include <asm/irq.h>
 
 __PT_R0      = __PT_GPRS
 __PT_R1      = __PT_GPRS + 8
@@ -468,6 +469,11 @@ io_skip:
        xc      __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
 io_loop:
        lgr     %r2,%r11                # pass pointer to pt_regs
+       lghi    %r3,IO_INTERRUPT
+       tm      __PT_INT_CODE+8(%r11),0x80      # adapter interrupt ?
+       jz      io_call
+       lghi    %r3,THIN_INTERRUPT
+io_call:
        brasl   %r14,do_IRQ
        tm      __LC_MACHINE_FLAGS+6,0x10       # MACHINE_FLAG_LPAR
        jz      io_return
@@ -623,7 +629,8 @@ ext_skip:
        TRACE_IRQS_OFF
        xc      __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
        lgr     %r2,%r11                # pass pointer to pt_regs
-       brasl   %r14,do_extint
+       lghi    %r3,EXT_INTERRUPT
+       brasl   %r14,do_IRQ
        j       io_return
 
 /*
index 54b0995514e8721508d9c98cb801d3bf36195c0a..b34ba0ea96a9e86e4f391ba6088a827b75b84b5b 100644 (file)
@@ -22,6 +22,7 @@
 #include <asm/cputime.h>
 #include <asm/lowcore.h>
 #include <asm/irq.h>
+#include <asm/hw_irq.h>
 #include "entry.h"
 
 DEFINE_PER_CPU_SHARED_ALIGNED(struct irq_stat, irq_stat);
@@ -42,9 +43,10 @@ struct irq_class {
  * Since the external and I/O interrupt fields are already sums we would end
  * up with having a sum which accounts each interrupt twice.
  */
-static const struct irq_class irqclass_main_desc[NR_IRQS] = {
-       [EXTERNAL_INTERRUPT] = {.name = "EXT"},
-       [IO_INTERRUPT]       = {.name = "I/O"}
+static const struct irq_class irqclass_main_desc[NR_IRQS_BASE] = {
+       [EXT_INTERRUPT]  = {.name = "EXT"},
+       [IO_INTERRUPT]   = {.name = "I/O"},
+       [THIN_INTERRUPT] = {.name = "AIO"},
 };
 
 /*
@@ -86,6 +88,28 @@ static const struct irq_class irqclass_sub_desc[NR_ARCH_IRQS] = {
        [CPU_RST]    = {.name = "RST", .desc = "[CPU] CPU Restart"},
 };
 
+void __init init_IRQ(void)
+{
+       irq_reserve_irqs(0, THIN_INTERRUPT);
+       init_cio_interrupts();
+       init_airq_interrupts();
+       init_ext_interrupts();
+}
+
+void do_IRQ(struct pt_regs *regs, int irq)
+{
+       struct pt_regs *old_regs;
+
+       old_regs = set_irq_regs(regs);
+       irq_enter();
+       if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator)
+               /* Serve timer interrupts first. */
+               clock_comparator_work();
+       generic_handle_irq(irq);
+       irq_exit();
+       set_irq_regs(old_regs);
+}
+
 /*
  * show_interrupts is needed by /proc/interrupts.
  */
@@ -100,27 +124,36 @@ int show_interrupts(struct seq_file *p, void *v)
                for_each_online_cpu(cpu)
                        seq_printf(p, "CPU%d       ", cpu);
                seq_putc(p, '\n');
+               goto out;
        }
        if (irq < NR_IRQS) {
+               if (irq >= NR_IRQS_BASE)
+                       goto out;
                seq_printf(p, "%s: ", irqclass_main_desc[irq].name);
                for_each_online_cpu(cpu)
-                       seq_printf(p, "%10u ", kstat_cpu(cpu).irqs[irq]);
+                       seq_printf(p, "%10u ", kstat_irqs_cpu(irq, cpu));
                seq_putc(p, '\n');
-               goto skip_arch_irqs;
+               goto out;
        }
        for (irq = 0; irq < NR_ARCH_IRQS; irq++) {
                seq_printf(p, "%s: ", irqclass_sub_desc[irq].name);
                for_each_online_cpu(cpu)
-                       seq_printf(p, "%10u ", per_cpu(irq_stat, cpu).irqs[irq]);
+                       seq_printf(p, "%10u ",
+                                  per_cpu(irq_stat, cpu).irqs[irq]);
                if (irqclass_sub_desc[irq].desc)
                        seq_printf(p, "  %s", irqclass_sub_desc[irq].desc);
                seq_putc(p, '\n');
        }
-skip_arch_irqs:
+out:
        put_online_cpus();
        return 0;
 }
 
+int arch_show_interrupts(struct seq_file *p, int prec)
+{
+       return 0;
+}
+
 /*
  * Switch to the asynchronous interrupt stack for softirq execution.
  */
@@ -159,14 +192,6 @@ asmlinkage void do_softirq(void)
        local_irq_restore(flags);
 }
 
-#ifdef CONFIG_PROC_FS
-void init_irq_proc(void)
-{
-       if (proc_mkdir("irq", NULL))
-               create_prof_cpu_mask();
-}
-#endif
-
 /*
  * ext_int_hash[index] is the list head for all external interrupts that hash
  * to this index.
@@ -183,14 +208,6 @@ struct ext_int_info {
 /* ext_int_hash_lock protects the handler lists for external interrupts */
 DEFINE_SPINLOCK(ext_int_hash_lock);
 
-static void __init init_external_interrupts(void)
-{
-       int idx;
-
-       for (idx = 0; idx < ARRAY_SIZE(ext_int_hash); idx++)
-               INIT_LIST_HEAD(&ext_int_hash[idx]);
-}
-
 static inline int ext_hash(u16 code)
 {
        return (code + (code >> 9)) & 0xff;
@@ -234,20 +251,13 @@ int unregister_external_interrupt(u16 code, ext_int_handler_t handler)
 }
 EXPORT_SYMBOL(unregister_external_interrupt);
 
-void __irq_entry do_extint(struct pt_regs *regs)
+static irqreturn_t do_ext_interrupt(int irq, void *dummy)
 {
+       struct pt_regs *regs = get_irq_regs();
        struct ext_code ext_code;
-       struct pt_regs *old_regs;
        struct ext_int_info *p;
        int index;
 
-       old_regs = set_irq_regs(regs);
-       irq_enter();
-       if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator) {
-               /* Serve timer interrupts first. */
-               clock_comparator_work();
-       }
-       kstat_incr_irqs_this_cpu(EXTERNAL_INTERRUPT, NULL);
        ext_code = *(struct ext_code *) &regs->int_code;
        if (ext_code.code != 0x1004)
                __get_cpu_var(s390_idle).nohz_delay = 1;
@@ -259,13 +269,25 @@ void __irq_entry do_extint(struct pt_regs *regs)
                        p->handler(ext_code, regs->int_parm,
                                   regs->int_parm_long);
        rcu_read_unlock();
-       irq_exit();
-       set_irq_regs(old_regs);
+
+       return IRQ_HANDLED;
 }
 
-void __init init_IRQ(void)
+static struct irqaction external_interrupt = {
+       .name    = "EXT",
+       .handler = do_ext_interrupt,
+};
+
+void __init init_ext_interrupts(void)
 {
-       init_external_interrupts();
+       int idx;
+
+       for (idx = 0; idx < ARRAY_SIZE(ext_int_hash); idx++)
+               INIT_LIST_HEAD(&ext_int_hash[idx]);
+
+       irq_set_chip_and_handler(EXT_INTERRUPT,
+                                &dummy_irq_chip, handle_percpu_irq);
+       setup_irq(EXT_INTERRUPT, &external_interrupt);
 }
 
 static DEFINE_SPINLOCK(sc_irq_lock);
@@ -313,69 +335,3 @@ void measurement_alert_subclass_unregister(void)
        spin_unlock(&ma_subclass_lock);
 }
 EXPORT_SYMBOL(measurement_alert_subclass_unregister);
-
-#ifdef CONFIG_SMP
-void synchronize_irq(unsigned int irq)
-{
-       /*
-        * Not needed, the handler is protected by a lock and IRQs that occur
-        * after the handler is deleted are just NOPs.
-        */
-}
-EXPORT_SYMBOL_GPL(synchronize_irq);
-#endif
-
-#ifndef CONFIG_PCI
-
-/* Only PCI devices have dynamically-defined IRQ handlers */
-
-int request_irq(unsigned int irq, irq_handler_t handler,
-               unsigned long irqflags, const char *devname, void *dev_id)
-{
-       return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(request_irq);
-
-void free_irq(unsigned int irq, void *dev_id)
-{
-       WARN_ON(1);
-}
-EXPORT_SYMBOL_GPL(free_irq);
-
-void enable_irq(unsigned int irq)
-{
-       WARN_ON(1);
-}
-EXPORT_SYMBOL_GPL(enable_irq);
-
-void disable_irq(unsigned int irq)
-{
-       WARN_ON(1);
-}
-EXPORT_SYMBOL_GPL(disable_irq);
-
-#endif /* !CONFIG_PCI */
-
-void disable_irq_nosync(unsigned int irq)
-{
-       disable_irq(irq);
-}
-EXPORT_SYMBOL_GPL(disable_irq_nosync);
-
-unsigned long probe_irq_on(void)
-{
-       return 0;
-}
-EXPORT_SYMBOL_GPL(probe_irq_on);
-
-int probe_irq_off(unsigned long val)
-{
-       return 0;
-}
-EXPORT_SYMBOL_GPL(probe_irq_off);
-
-unsigned int probe_irq_mask(unsigned long val)
-{
-       return val;
-}
-EXPORT_SYMBOL_GPL(probe_irq_mask);
index a6fc037671b11d0a2e96226256f9e36cd8e4d65d..500aa1029bcb2d2ed12ae352a91cec068322615b 100644 (file)
@@ -52,12 +52,13 @@ static struct kvm_s390_sie_block *sie_block(struct pt_regs *regs)
 
 static bool is_in_guest(struct pt_regs *regs)
 {
-       unsigned long ip = instruction_pointer(regs);
-
        if (user_mode(regs))
                return false;
-
-       return ip == (unsigned long) &sie_exit;
+#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE)
+       return instruction_pointer(regs) == (unsigned long) &sie_exit;
+#else
+       return false;
+#endif
 }
 
 static unsigned long guest_is_user_mode(struct pt_regs *regs)
index e9fadb04e3c61e0b71b6eb238a12941359edba0d..2bc08039140f651cc596e2ac10fb52686adb6460 100644 (file)
@@ -1299,7 +1299,7 @@ int regs_query_register_offset(const char *name)
 
        if (!name || *name != 'r')
                return -EINVAL;
-       if (strict_strtoul(name + 1, 10, &offset))
+       if (kstrtoul(name + 1, 10, &offset))
                return -EINVAL;
        if (offset >= NUM_GPRS)
                return -EINVAL;
index 497451ec5e267f3be025b9b719cf4f2278262d97..aeed8a61fa0d4f1b4862a98cab44e29beda63699 100644 (file)
@@ -994,6 +994,7 @@ static void __init setup_hwcaps(void)
                strcpy(elf_platform, "z196");
                break;
        case 0x2827:
+       case 0x2828:
                strcpy(elf_platform, "zEC12");
                break;
        }
index d7776281cb60ff0cd2738ab9c949d68c6f805d1f..05d75c413137879a30fded476638b0b9c4a001f5 100644 (file)
@@ -63,7 +63,7 @@ static int __init vdso_setup(char *s)
        else if (strncmp(s, "off", 4) == 0)
                vdso_enabled = 0;
        else {
-               rc = strict_strtoul(s, 0, &val);
+               rc = kstrtoul(s, 0, &val);
                vdso_enabled = rc ? 0 : !!val;
        }
        return !rc;
@@ -113,11 +113,11 @@ int vdso_alloc_per_cpu(struct _lowcore *lowcore)
 
        clear_table((unsigned long *) segment_table, _SEGMENT_ENTRY_EMPTY,
                    PAGE_SIZE << SEGMENT_ORDER);
-       clear_table((unsigned long *) page_table, _PAGE_TYPE_EMPTY,
+       clear_table((unsigned long *) page_table, _PAGE_INVALID,
                    256*sizeof(unsigned long));
 
        *(unsigned long *) segment_table = _SEGMENT_ENTRY + page_table;
-       *(unsigned long *) page_table = _PAGE_RO + page_frame;
+       *(unsigned long *) page_table = _PAGE_PROTECT + page_frame;
 
        psal = (u32 *) (page_table + 256*sizeof(unsigned long));
        aste = psal + 32;
index 50ea137a2d3c296859b600c0ef861c07fcce5209..1694d738b17527aad71850c8fc772e755d26ca54 100644 (file)
@@ -86,28 +86,28 @@ static unsigned long follow_table(struct mm_struct *mm,
        switch (mm->context.asce_bits & _ASCE_TYPE_MASK) {
        case _ASCE_TYPE_REGION1:
                table = table + ((address >> 53) & 0x7ff);
-               if (unlikely(*table & _REGION_ENTRY_INV))
+               if (unlikely(*table & _REGION_ENTRY_INVALID))
                        return -0x39UL;
                table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
                /* fallthrough */
        case _ASCE_TYPE_REGION2:
                table = table + ((address >> 42) & 0x7ff);
-               if (unlikely(*table & _REGION_ENTRY_INV))
+               if (unlikely(*table & _REGION_ENTRY_INVALID))
                        return -0x3aUL;
                table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
                /* fallthrough */
        case _ASCE_TYPE_REGION3:
                table = table + ((address >> 31) & 0x7ff);
-               if (unlikely(*table & _REGION_ENTRY_INV))
+               if (unlikely(*table & _REGION_ENTRY_INVALID))
                        return -0x3bUL;
                table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
                /* fallthrough */
        case _ASCE_TYPE_SEGMENT:
                table = table + ((address >> 20) & 0x7ff);
-               if (unlikely(*table & _SEGMENT_ENTRY_INV))
+               if (unlikely(*table & _SEGMENT_ENTRY_INVALID))
                        return -0x10UL;
                if (unlikely(*table & _SEGMENT_ENTRY_LARGE)) {
-                       if (write && (*table & _SEGMENT_ENTRY_RO))
+                       if (write && (*table & _SEGMENT_ENTRY_PROTECT))
                                return -0x04UL;
                        return (*table & _SEGMENT_ENTRY_ORIGIN_LARGE) +
                                (address & ~_SEGMENT_ENTRY_ORIGIN_LARGE);
@@ -117,7 +117,7 @@ static unsigned long follow_table(struct mm_struct *mm,
        table = table + ((address >> 12) & 0xff);
        if (unlikely(*table & _PAGE_INVALID))
                return -0x11UL;
-       if (write && (*table & _PAGE_RO))
+       if (write && (*table & _PAGE_PROTECT))
                return -0x04UL;
        return (*table & PAGE_MASK) + (address & ~PAGE_MASK);
 }
@@ -130,13 +130,13 @@ static unsigned long follow_table(struct mm_struct *mm,
        unsigned long *table = (unsigned long *)__pa(mm->pgd);
 
        table = table + ((address >> 20) & 0x7ff);
-       if (unlikely(*table & _SEGMENT_ENTRY_INV))
+       if (unlikely(*table & _SEGMENT_ENTRY_INVALID))
                return -0x10UL;
        table = (unsigned long *)(*table & _SEGMENT_ENTRY_ORIGIN);
        table = table + ((address >> 12) & 0xff);
        if (unlikely(*table & _PAGE_INVALID))
                return -0x11UL;
-       if (write && (*table & _PAGE_RO))
+       if (write && (*table & _PAGE_PROTECT))
                return -0x04UL;
        return (*table & PAGE_MASK) + (address & ~PAGE_MASK);
 }
index 3ad65b04ac1508a62290e57e7a7013d4edbe994d..46d517c3c76366c7459b7f539888a29064a43d78 100644 (file)
@@ -53,7 +53,7 @@ static void print_prot(struct seq_file *m, unsigned int pr, int level)
                seq_printf(m, "I\n");
                return;
        }
-       seq_printf(m, "%s", pr & _PAGE_RO ? "RO " : "RW ");
+       seq_printf(m, "%s", pr & _PAGE_PROTECT ? "RO " : "RW ");
        seq_printf(m, "%s", pr & _PAGE_CO ? "CO " : "   ");
        seq_putc(m, '\n');
 }
@@ -105,12 +105,12 @@ static void note_page(struct seq_file *m, struct pg_state *st,
 }
 
 /*
- * The actual page table walker functions. In order to keep the implementation
- * of print_prot() short, we only check and pass _PAGE_INVALID and _PAGE_RO
- * flags to note_page() if a region, segment or page table entry is invalid or
- * read-only.
- * After all it's just a hint that the current level being walked contains an
- * invalid or read-only entry.
+ * The actual page table walker functions. In order to keep the
+ * implementation of print_prot() short, we only check and pass
+ * _PAGE_INVALID and _PAGE_PROTECT flags to note_page() if a region,
+ * segment or page table entry is invalid or read-only.
+ * After all it's just a hint that the current level being walked
+ * contains an invalid or read-only entry.
  */
 static void walk_pte_level(struct seq_file *m, struct pg_state *st,
                           pmd_t *pmd, unsigned long addr)
@@ -122,14 +122,14 @@ static void walk_pte_level(struct seq_file *m, struct pg_state *st,
        for (i = 0; i < PTRS_PER_PTE && addr < max_addr; i++) {
                st->current_address = addr;
                pte = pte_offset_kernel(pmd, addr);
-               prot = pte_val(*pte) & (_PAGE_RO | _PAGE_INVALID);
+               prot = pte_val(*pte) & (_PAGE_PROTECT | _PAGE_INVALID);
                note_page(m, st, prot, 4);
                addr += PAGE_SIZE;
        }
 }
 
 #ifdef CONFIG_64BIT
-#define _PMD_PROT_MASK (_SEGMENT_ENTRY_RO | _SEGMENT_ENTRY_CO)
+#define _PMD_PROT_MASK (_SEGMENT_ENTRY_PROTECT | _SEGMENT_ENTRY_CO)
 #else
 #define _PMD_PROT_MASK 0
 #endif
index 1f5315d1215c2640f5691555801e9ff7885c7fcf..5d758db27bdced58d929d736363bcafc09c199ab 100644 (file)
@@ -24,7 +24,7 @@ static inline int gup_pte_range(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
        pte_t *ptep, pte;
        struct page *page;
 
-       mask = (write ? _PAGE_RO : 0) | _PAGE_INVALID | _PAGE_SPECIAL;
+       mask = (write ? _PAGE_PROTECT : 0) | _PAGE_INVALID | _PAGE_SPECIAL;
 
        ptep = ((pte_t *) pmd_deref(pmd)) + pte_index(addr);
        do {
@@ -55,8 +55,8 @@ static inline int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
        struct page *head, *page, *tail;
        int refs;
 
-       result = write ? 0 : _SEGMENT_ENTRY_RO;
-       mask = result | _SEGMENT_ENTRY_INV;
+       result = write ? 0 : _SEGMENT_ENTRY_PROTECT;
+       mask = result | _SEGMENT_ENTRY_INVALID;
        if ((pmd_val(pmd) & mask) != result)
                return 0;
        VM_BUG_ON(!pfn_valid(pmd_val(pmd) >> PAGE_SHIFT));
index 121089d578029191c61c71843b7e311c6be317df..4579f7d74bc19d93444df2cb10dd76bd76b5b8da 100644 (file)
 #include <linux/mm.h>
 #include <linux/hugetlb.h>
 
+static inline pmd_t __pte_to_pmd(pte_t pte)
+{
+       int none, prot;
+       pmd_t pmd;
+
+       /*
+        * Convert encoding       pte bits        pmd bits
+        *                      .IR.....wdtp    ..R...I.....
+        * empty                .10.....0000 -> ..0...1.....
+        * prot-none, clean     .10.....0001 -> ..1...1.....
+        * prot-none, dirty     .10.....0101 -> ..1...1.....
+        * read-only, clean     .01.....0001 -> ..1...0.....
+        * read-only, dirty     .01.....0101 -> ..1...0.....
+        * read-write, clean    .01.....1001 -> ..0...0.....
+        * read-write, dirty    .00.....1101 -> ..0...0.....
+        * Huge ptes are dirty by definition, a clean pte is made dirty
+        * by the conversion.
+        */
+       if (pte_present(pte)) {
+               pmd_val(pmd) = pte_val(pte) & _SEGMENT_ENTRY_ORIGIN;
+               if (pte_val(pte) & _PAGE_INVALID)
+                       pmd_val(pmd) |= _SEGMENT_ENTRY_INVALID;
+               none = (pte_val(pte) & _PAGE_PRESENT) &&
+                       (pte_val(pte) & _PAGE_INVALID);
+               prot = (pte_val(pte) & _PAGE_PROTECT);
+               if (prot || none)
+                       pmd_val(pmd) |= _SEGMENT_ENTRY_PROTECT;
+       } else
+               pmd_val(pmd) = _SEGMENT_ENTRY_INVALID;
+       return pmd;
+}
+
+static inline pte_t __pmd_to_pte(pmd_t pmd)
+{
+       pte_t pte;
+
+       /*
+        * Convert encoding       pmd bits        pte bits
+        *                      ..R...I.....    .IR.....wdtp
+        * empty                ..0...1..... -> .10.....0000
+        * prot-none, young     ..1...1..... -> .10.....0101
+        * read-only, young     ..1...0..... -> .01.....0101
+        * read-write, young    ..0...0..... -> .00.....1101
+        * Huge ptes are dirty by definition
+        */
+       if (pmd_present(pmd)) {
+               pte_val(pte) = _PAGE_PRESENT | _PAGE_LARGE | _PAGE_DIRTY |
+                       (pmd_val(pmd) & _SEGMENT_ENTRY_ORIGIN);
+               if (pmd_val(pmd) && _SEGMENT_ENTRY_INVALID)
+                       pte_val(pte) |= _PAGE_INVALID;
+               else {
+                       if (pmd_val(pmd) && _SEGMENT_ENTRY_PROTECT)
+                               pte_val(pte) |= _PAGE_PROTECT;
+                       else
+                               pte_val(pte) |= _PAGE_WRITE;
+               }
+       } else
+               pte_val(pte) = _PAGE_INVALID;
+       return pte;
+}
 
 void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
-                                  pte_t *pteptr, pte_t pteval)
+                    pte_t *ptep, pte_t pte)
 {
-       pmd_t *pmdp = (pmd_t *) pteptr;
-       unsigned long mask;
+       pmd_t pmd;
 
+       pmd = __pte_to_pmd(pte);
        if (!MACHINE_HAS_HPAGE) {
-               pteptr = (pte_t *) pte_page(pteval)[1].index;
-               mask = pte_val(pteval) &
-                               (_SEGMENT_ENTRY_INV | _SEGMENT_ENTRY_RO);
-               pte_val(pteval) = (_SEGMENT_ENTRY + __pa(pteptr)) | mask;
+               pmd_val(pmd) &= ~_SEGMENT_ENTRY_ORIGIN;
+               pmd_val(pmd) |= pte_page(pte)[1].index;
+       } else
+               pmd_val(pmd) |= _SEGMENT_ENTRY_LARGE | _SEGMENT_ENTRY_CO;
+       *(pmd_t *) ptep = pmd;
+}
+
+pte_t huge_ptep_get(pte_t *ptep)
+{
+       unsigned long origin;
+       pmd_t pmd;
+
+       pmd = *(pmd_t *) ptep;
+       if (!MACHINE_HAS_HPAGE && pmd_present(pmd)) {
+               origin = pmd_val(pmd) & _SEGMENT_ENTRY_ORIGIN;
+               pmd_val(pmd) &= ~_SEGMENT_ENTRY_ORIGIN;
+               pmd_val(pmd) |= *(unsigned long *) origin;
        }
+       return __pmd_to_pte(pmd);
+}
 
-       pmd_val(*pmdp) = pte_val(pteval);
+pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
+                             unsigned long addr, pte_t *ptep)
+{
+       pmd_t *pmdp = (pmd_t *) ptep;
+       pte_t pte = huge_ptep_get(ptep);
+
+       if (MACHINE_HAS_IDTE)
+               __pmd_idte(addr, pmdp);
+       else
+               __pmd_csp(pmdp);
+       pmd_val(*pmdp) = _SEGMENT_ENTRY_EMPTY;
+       return pte;
 }
 
 int arch_prepare_hugepage(struct page *page)
@@ -58,7 +144,7 @@ void arch_release_hugepage(struct page *page)
        ptep = (pte_t *) page[1].index;
        if (!ptep)
                return;
-       clear_table((unsigned long *) ptep, _PAGE_TYPE_EMPTY,
+       clear_table((unsigned long *) ptep, _PAGE_INVALID,
                    PTRS_PER_PTE * sizeof(pte_t));
        page_table_free(&init_mm, (unsigned long *) ptep);
        page[1].index = 0;
index ce36ea80e4f9157f5c754b51c1ff9c700106d689..ad446b0c55b6076d5aaf7f095f1ddc91b5e38bf4 100644 (file)
@@ -69,6 +69,7 @@ static void __init setup_zero_pages(void)
                order = 2;
                break;
        case 0x2827:    /* zEC12 */
+       case 0x2828:    /* zEC12 */
        default:
                order = 5;
                break;
index 80adfbf75065d487a572226eafd21450bc84962d..990397420e6bcf8262b92806b5f5b57bff273373 100644 (file)
@@ -118,7 +118,7 @@ void kernel_map_pages(struct page *page, int numpages, int enable)
                pte = pte_offset_kernel(pmd, address);
                if (!enable) {
                        __ptep_ipte(address, pte);
-                       pte_val(*pte) = _PAGE_TYPE_EMPTY;
+                       pte_val(*pte) = _PAGE_INVALID;
                        continue;
                }
                pte_val(*pte) = __pa(address);
index a8154a1a2c942ee0eb1a93d77c8dd872e26b3dd0..b9d35d63934ea60bc0dd9cf74891955b55bd780f 100644 (file)
@@ -161,7 +161,7 @@ static int gmap_unlink_segment(struct gmap *gmap, unsigned long *table)
        struct gmap_rmap *rmap;
        struct page *page;
 
-       if (*table & _SEGMENT_ENTRY_INV)
+       if (*table & _SEGMENT_ENTRY_INVALID)
                return 0;
        page = pfn_to_page(*table >> PAGE_SHIFT);
        mp = (struct gmap_pgtable *) page->index;
@@ -172,7 +172,7 @@ static int gmap_unlink_segment(struct gmap *gmap, unsigned long *table)
                kfree(rmap);
                break;
        }
-       *table = _SEGMENT_ENTRY_INV | _SEGMENT_ENTRY_RO | mp->vmaddr;
+       *table = mp->vmaddr | _SEGMENT_ENTRY_INVALID | _SEGMENT_ENTRY_PROTECT;
        return 1;
 }
 
@@ -258,7 +258,7 @@ static int gmap_alloc_table(struct gmap *gmap,
                return -ENOMEM;
        new = (unsigned long *) page_to_phys(page);
        crst_table_init(new, init);
-       if (*table & _REGION_ENTRY_INV) {
+       if (*table & _REGION_ENTRY_INVALID) {
                list_add(&page->lru, &gmap->crst_list);
                *table = (unsigned long) new | _REGION_ENTRY_LENGTH |
                        (*table & _REGION_ENTRY_TYPE_MASK);
@@ -292,22 +292,22 @@ int gmap_unmap_segment(struct gmap *gmap, unsigned long to, unsigned long len)
        for (off = 0; off < len; off += PMD_SIZE) {
                /* Walk the guest addr space page table */
                table = gmap->table + (((to + off) >> 53) & 0x7ff);
-               if (*table & _REGION_ENTRY_INV)
+               if (*table & _REGION_ENTRY_INVALID)
                        goto out;
                table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
                table = table + (((to + off) >> 42) & 0x7ff);
-               if (*table & _REGION_ENTRY_INV)
+               if (*table & _REGION_ENTRY_INVALID)
                        goto out;
                table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
                table = table + (((to + off) >> 31) & 0x7ff);
-               if (*table & _REGION_ENTRY_INV)
+               if (*table & _REGION_ENTRY_INVALID)
                        goto out;
                table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
                table = table + (((to + off) >> 20) & 0x7ff);
 
                /* Clear segment table entry in guest address space. */
                flush |= gmap_unlink_segment(gmap, table);
-               *table = _SEGMENT_ENTRY_INV;
+               *table = _SEGMENT_ENTRY_INVALID;
        }
 out:
        spin_unlock(&gmap->mm->page_table_lock);
@@ -345,17 +345,17 @@ int gmap_map_segment(struct gmap *gmap, unsigned long from,
        for (off = 0; off < len; off += PMD_SIZE) {
                /* Walk the gmap address space page table */
                table = gmap->table + (((to + off) >> 53) & 0x7ff);
-               if ((*table & _REGION_ENTRY_INV) &&
+               if ((*table & _REGION_ENTRY_INVALID) &&
                    gmap_alloc_table(gmap, table, _REGION2_ENTRY_EMPTY))
                        goto out_unmap;
                table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
                table = table + (((to + off) >> 42) & 0x7ff);
-               if ((*table & _REGION_ENTRY_INV) &&
+               if ((*table & _REGION_ENTRY_INVALID) &&
                    gmap_alloc_table(gmap, table, _REGION3_ENTRY_EMPTY))
                        goto out_unmap;
                table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
                table = table + (((to + off) >> 31) & 0x7ff);
-               if ((*table & _REGION_ENTRY_INV) &&
+               if ((*table & _REGION_ENTRY_INVALID) &&
                    gmap_alloc_table(gmap, table, _SEGMENT_ENTRY_EMPTY))
                        goto out_unmap;
                table = (unsigned long *) (*table & _REGION_ENTRY_ORIGIN);
@@ -363,7 +363,8 @@ int gmap_map_segment(struct gmap *gmap, unsigned long from,
 
                /* Store 'from' address in an invalid segment table entry. */
                flush |= gmap_unlink_segment(gmap, table);
-               *table = _SEGMENT_ENTRY_INV | _SEGMENT_ENTRY_RO | (from + off);
+               *table =  (from + off) | (_SEGMENT_ENTRY_INVALID |
+                                         _SEGMENT_ENTRY_PROTECT);
        }
        spin_unlock(&gmap->mm->page_table_lock);
        up_read(&gmap->mm->mmap_sem);
@@ -384,15 +385,15 @@ static unsigned long *gmap_table_walk(unsigned long address, struct gmap *gmap)
        unsigned long *table;
 
        table = gmap->table + ((address >> 53) & 0x7ff);
-       if (unlikely(*table & _REGION_ENTRY_INV))
+       if (unlikely(*table & _REGION_ENTRY_INVALID))
                return ERR_PTR(-EFAULT);
        table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
        table = table + ((address >> 42) & 0x7ff);
-       if (unlikely(*table & _REGION_ENTRY_INV))
+       if (unlikely(*table & _REGION_ENTRY_INVALID))
                return ERR_PTR(-EFAULT);
        table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
        table = table + ((address >> 31) & 0x7ff);
-       if (unlikely(*table & _REGION_ENTRY_INV))
+       if (unlikely(*table & _REGION_ENTRY_INVALID))
                return ERR_PTR(-EFAULT);
        table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
        table = table + ((address >> 20) & 0x7ff);
@@ -422,11 +423,11 @@ unsigned long __gmap_translate(unsigned long address, struct gmap *gmap)
                return PTR_ERR(segment_ptr);
        /* Convert the gmap address to an mm address. */
        segment = *segment_ptr;
-       if (!(segment & _SEGMENT_ENTRY_INV)) {
+       if (!(segment & _SEGMENT_ENTRY_INVALID)) {
                page = pfn_to_page(segment >> PAGE_SHIFT);
                mp = (struct gmap_pgtable *) page->index;
                return mp->vmaddr | (address & ~PMD_MASK);
-       } else if (segment & _SEGMENT_ENTRY_RO) {
+       } else if (segment & _SEGMENT_ENTRY_PROTECT) {
                vmaddr = segment & _SEGMENT_ENTRY_ORIGIN;
                return vmaddr | (address & ~PMD_MASK);
        }
@@ -517,8 +518,8 @@ static void gmap_disconnect_pgtable(struct mm_struct *mm, unsigned long *table)
        page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
        mp = (struct gmap_pgtable *) page->index;
        list_for_each_entry_safe(rmap, next, &mp->mapper, list) {
-               *rmap->entry =
-                       _SEGMENT_ENTRY_INV | _SEGMENT_ENTRY_RO | mp->vmaddr;
+               *rmap->entry = mp->vmaddr | (_SEGMENT_ENTRY_INVALID |
+                                            _SEGMENT_ENTRY_PROTECT);
                list_del(&rmap->list);
                kfree(rmap);
                flush = 1;
@@ -545,13 +546,13 @@ unsigned long __gmap_fault(unsigned long address, struct gmap *gmap)
        /* Convert the gmap address to an mm address. */
        while (1) {
                segment = *segment_ptr;
-               if (!(segment & _SEGMENT_ENTRY_INV)) {
+               if (!(segment & _SEGMENT_ENTRY_INVALID)) {
                        /* Page table is present */
                        page = pfn_to_page(segment >> PAGE_SHIFT);
                        mp = (struct gmap_pgtable *) page->index;
                        return mp->vmaddr | (address & ~PMD_MASK);
                }
-               if (!(segment & _SEGMENT_ENTRY_RO))
+               if (!(segment & _SEGMENT_ENTRY_PROTECT))
                        /* Nothing mapped in the gmap address space. */
                        break;
                rc = gmap_connect_pgtable(address, segment, segment_ptr, gmap);
@@ -586,25 +587,25 @@ void gmap_discard(unsigned long from, unsigned long to, struct gmap *gmap)
        while (address < to) {
                /* Walk the gmap address space page table */
                table = gmap->table + ((address >> 53) & 0x7ff);
-               if (unlikely(*table & _REGION_ENTRY_INV)) {
+               if (unlikely(*table & _REGION_ENTRY_INVALID)) {
                        address = (address + PMD_SIZE) & PMD_MASK;
                        continue;
                }
                table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
                table = table + ((address >> 42) & 0x7ff);
-               if (unlikely(*table & _REGION_ENTRY_INV)) {
+               if (unlikely(*table & _REGION_ENTRY_INVALID)) {
                        address = (address + PMD_SIZE) & PMD_MASK;
                        continue;
                }
                table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
                table = table + ((address >> 31) & 0x7ff);
-               if (unlikely(*table & _REGION_ENTRY_INV)) {
+               if (unlikely(*table & _REGION_ENTRY_INVALID)) {
                        address = (address + PMD_SIZE) & PMD_MASK;
                        continue;
                }
                table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
                table = table + ((address >> 20) & 0x7ff);
-               if (unlikely(*table & _SEGMENT_ENTRY_INV)) {
+               if (unlikely(*table & _SEGMENT_ENTRY_INVALID)) {
                        address = (address + PMD_SIZE) & PMD_MASK;
                        continue;
                }
@@ -687,7 +688,7 @@ int gmap_ipte_notify(struct gmap *gmap, unsigned long start, unsigned long len)
                        continue;
                /* Set notification bit in the pgste of the pte */
                entry = *ptep;
-               if ((pte_val(entry) & (_PAGE_INVALID | _PAGE_RO)) == 0) {
+               if ((pte_val(entry) & (_PAGE_INVALID | _PAGE_PROTECT)) == 0) {
                        pgste = pgste_get_lock(ptep);
                        pgste_val(pgste) |= PGSTE_IN_BIT;
                        pgste_set_unlock(ptep, pgste);
@@ -752,7 +753,7 @@ static inline unsigned long *page_table_alloc_pgste(struct mm_struct *mm,
        page->index = (unsigned long) mp;
        atomic_set(&page->_mapcount, 3);
        table = (unsigned long *) page_to_phys(page);
-       clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE/2);
+       clear_table(table, _PAGE_INVALID, PAGE_SIZE/2);
        clear_table(table + PTRS_PER_PTE, 0, PAGE_SIZE/2);
        return table;
 }
@@ -878,7 +879,7 @@ unsigned long *page_table_alloc(struct mm_struct *mm, unsigned long vmaddr)
                pgtable_page_ctor(page);
                atomic_set(&page->_mapcount, 1);
                table = (unsigned long *) page_to_phys(page);
-               clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE);
+               clear_table(table, _PAGE_INVALID, PAGE_SIZE);
                spin_lock_bh(&mm->context.list_lock);
                list_add(&page->lru, &mm->context.pgtable_list);
        } else {
@@ -1198,9 +1199,9 @@ pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp)
                list_del(lh);
        }
        ptep = (pte_t *) pgtable;
-       pte_val(*ptep) = _PAGE_TYPE_EMPTY;
+       pte_val(*ptep) = _PAGE_INVALID;
        ptep++;
-       pte_val(*ptep) = _PAGE_TYPE_EMPTY;
+       pte_val(*ptep) = _PAGE_INVALID;
        return pgtable;
 }
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
index 8b268fcc4612e92a1f9ab70eed81a4c664adaa8b..e1299d40818ddcb04967fc913a4893a6c5939b9a 100644 (file)
@@ -69,7 +69,7 @@ static pte_t __ref *vmem_pte_alloc(unsigned long address)
                pte = alloc_bootmem(PTRS_PER_PTE * sizeof(pte_t));
        if (!pte)
                return NULL;
-       clear_table((unsigned long *) pte, _PAGE_TYPE_EMPTY,
+       clear_table((unsigned long *) pte, _PAGE_INVALID,
                    PTRS_PER_PTE * sizeof(pte_t));
        return pte;
 }
@@ -101,7 +101,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
                    !(address & ~PUD_MASK) && (address + PUD_SIZE <= end)) {
                        pud_val(*pu_dir) = __pa(address) |
                                _REGION_ENTRY_TYPE_R3 | _REGION3_ENTRY_LARGE |
-                               (ro ? _REGION_ENTRY_RO : 0);
+                               (ro ? _REGION_ENTRY_PROTECT : 0);
                        address += PUD_SIZE;
                        continue;
                }
@@ -118,7 +118,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
                    !(address & ~PMD_MASK) && (address + PMD_SIZE <= end)) {
                        pmd_val(*pm_dir) = __pa(address) |
                                _SEGMENT_ENTRY | _SEGMENT_ENTRY_LARGE |
-                               (ro ? _SEGMENT_ENTRY_RO : 0);
+                               (ro ? _SEGMENT_ENTRY_PROTECT : 0);
                        address += PMD_SIZE;
                        continue;
                }
@@ -131,7 +131,8 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
                }
 
                pt_dir = pte_offset_kernel(pm_dir, address);
-               pte_val(*pt_dir) = __pa(address) | (ro ? _PAGE_RO : 0);
+               pte_val(*pt_dir) = __pa(address) |
+                       pgprot_val(ro ? PAGE_KERNEL_RO : PAGE_KERNEL);
                address += PAGE_SIZE;
        }
        ret = 0;
@@ -154,7 +155,7 @@ static void vmem_remove_range(unsigned long start, unsigned long size)
        pte_t *pt_dir;
        pte_t  pte;
 
-       pte_val(pte) = _PAGE_TYPE_EMPTY;
+       pte_val(pte) = _PAGE_INVALID;
        while (address < end) {
                pg_dir = pgd_offset_k(address);
                if (pgd_none(*pg_dir)) {
@@ -255,7 +256,8 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
                        new_page =__pa(vmem_alloc_pages(0));
                        if (!new_page)
                                goto out;
-                       pte_val(*pt_dir) = __pa(new_page);
+                       pte_val(*pt_dir) =
+                               __pa(new_page) | pgprot_val(PAGE_KERNEL);
                }
                address += PAGE_SIZE;
        }
index ffeb17ce7f313d914a38de3ee21dad5867991b9d..930783d2c99beb305b2346a220f414d98a4ba406 100644 (file)
@@ -440,7 +440,7 @@ static int oprofile_hwsampler_init(struct oprofile_operations *ops)
                switch (id.machine) {
                case 0x2097: case 0x2098: ops->cpu_type = "s390/z10"; break;
                case 0x2817: case 0x2818: ops->cpu_type = "s390/z196"; break;
-               case 0x2827:              ops->cpu_type = "s390/zEC12"; break;
+               case 0x2827: case 0x2828: ops->cpu_type = "s390/zEC12"; break;
                default: return -ENODEV;
                }
        }
index 086a2e37935d22cd48d9cb879d30651d89c03e2f..a9e1dc4ae442bacc688d392509de7e0607c7147d 100644 (file)
@@ -2,5 +2,5 @@
 # Makefile for the s390 PCI subsystem.
 #
 
-obj-$(CONFIG_PCI)      += pci.o pci_dma.o pci_clp.o pci_msi.o pci_sysfs.o \
+obj-$(CONFIG_PCI)      += pci.o pci_dma.o pci_clp.o pci_sysfs.o \
                           pci_event.o pci_debug.o pci_insn.o
index e2956ad39a4f59ac2e8ffbe2a8626b2d9c84d363..6d60ef5eb8719e31a5582905d77d3e13a7857cc7 100644 (file)
@@ -42,7 +42,6 @@
 #define        SIC_IRQ_MODE_SINGLE             1
 
 #define ZPCI_NR_DMA_SPACES             1
-#define ZPCI_MSI_VEC_BITS              6
 #define ZPCI_NR_DEVICES                        CONFIG_PCI_NR_FUNCTIONS
 
 /* list of all detected zpci devices */
@@ -51,36 +50,23 @@ EXPORT_SYMBOL_GPL(zpci_list);
 DEFINE_MUTEX(zpci_list_lock);
 EXPORT_SYMBOL_GPL(zpci_list_lock);
 
-static struct pci_hp_callback_ops *hotplug_ops;
 
-static DECLARE_BITMAP(zpci_domain, ZPCI_NR_DEVICES);
-static DEFINE_SPINLOCK(zpci_domain_lock);
+static void zpci_enable_irq(struct irq_data *data);
+static void zpci_disable_irq(struct irq_data *data);
 
-struct callback {
-       irq_handler_t   handler;
-       void            *data;
+static struct irq_chip zpci_irq_chip = {
+       .name = "zPCI",
+       .irq_unmask = zpci_enable_irq,
+       .irq_mask = zpci_disable_irq,
 };
 
-struct zdev_irq_map {
-       unsigned long   aibv;           /* AI bit vector */
-       int             msi_vecs;       /* consecutive MSI-vectors used */
-       int             __unused;
-       struct callback cb[ZPCI_NR_MSI_VECS]; /* callback handler array */
-       spinlock_t      lock;           /* protect callbacks against de-reg */
-};
+static struct pci_hp_callback_ops *hotplug_ops;
 
-struct intr_bucket {
-       /* amap of adapters, one bit per dev, corresponds to one irq nr */
-       unsigned long   *alloc;
-       /* AI summary bit, global page for all devices */
-       unsigned long   *aisb;
-       /* pointer to aibv and callback data in zdev */
-       struct zdev_irq_map *imap[ZPCI_NR_DEVICES];
-       /* protects the whole bucket struct */
-       spinlock_t      lock;
-};
+static DECLARE_BITMAP(zpci_domain, ZPCI_NR_DEVICES);
+static DEFINE_SPINLOCK(zpci_domain_lock);
 
-static struct intr_bucket *bucket;
+static struct airq_iv *zpci_aisb_iv;
+static struct airq_iv *zpci_aibv[ZPCI_NR_DEVICES];
 
 /* Adapter interrupt definitions */
 static void zpci_irq_handler(struct airq_struct *airq);
@@ -96,27 +82,8 @@ static DECLARE_BITMAP(zpci_iomap, ZPCI_IOMAP_MAX_ENTRIES);
 struct zpci_iomap_entry *zpci_iomap_start;
 EXPORT_SYMBOL_GPL(zpci_iomap_start);
 
-/* highest irq summary bit */
-static int __read_mostly aisb_max;
-
-static struct kmem_cache *zdev_irq_cache;
 static struct kmem_cache *zdev_fmb_cache;
 
-static inline int irq_to_msi_nr(unsigned int irq)
-{
-       return irq & ZPCI_MSI_MASK;
-}
-
-static inline int irq_to_dev_nr(unsigned int irq)
-{
-       return irq >> ZPCI_MSI_VEC_BITS;
-}
-
-static inline struct zdev_irq_map *get_imap(unsigned int irq)
-{
-       return bucket->imap[irq_to_dev_nr(irq)];
-}
-
 struct zpci_dev *get_zdev(struct pci_dev *pdev)
 {
        return (struct zpci_dev *) pdev->sysdata;
@@ -160,8 +127,7 @@ int pci_proc_domain(struct pci_bus *bus)
 EXPORT_SYMBOL_GPL(pci_proc_domain);
 
 /* Modify PCI: Register adapter interruptions */
-static int zpci_register_airq(struct zpci_dev *zdev, unsigned int aisb,
-                             u64 aibv)
+static int zpci_set_airq(struct zpci_dev *zdev)
 {
        u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, ZPCI_MOD_FC_REG_INT);
        struct zpci_fib *fib;
@@ -172,14 +138,14 @@ static int zpci_register_airq(struct zpci_dev *zdev, unsigned int aisb,
                return -ENOMEM;
 
        fib->isc = PCI_ISC;
-       fib->noi = zdev->irq_map->msi_vecs;
        fib->sum = 1;           /* enable summary notifications */
-       fib->aibv = aibv;
-       fib->aibvo = 0;         /* every function has its own page */
-       fib->aisb = (u64) bucket->aisb + aisb / 8;
-       fib->aisbo = aisb & ZPCI_MSI_MASK;
+       fib->noi = airq_iv_end(zdev->aibv);
+       fib->aibv = (unsigned long) zdev->aibv->vector;
+       fib->aibvo = 0;         /* each zdev has its own interrupt vector */
+       fib->aisb = (unsigned long) zpci_aisb_iv->vector + (zdev->aisb/64)*8;
+       fib->aisbo = zdev->aisb & 63;
 
-       rc = s390pci_mod_fc(req, fib);
+       rc = zpci_mod_fc(req, fib);
        pr_debug("%s mpcifc returned noi: %d\n", __func__, fib->noi);
 
        free_page((unsigned long) fib);
@@ -209,7 +175,7 @@ static int mod_pci(struct zpci_dev *zdev, int fn, u8 dmaas, struct mod_pci_args
        fib->iota = args->iota;
        fib->fmb_addr = args->fmb_addr;
 
-       rc = s390pci_mod_fc(req, fib);
+       rc = zpci_mod_fc(req, fib);
        free_page((unsigned long) fib);
        return rc;
 }
@@ -234,7 +200,7 @@ int zpci_unregister_ioat(struct zpci_dev *zdev, u8 dmaas)
 }
 
 /* Modify PCI: Unregister adapter interruptions */
-static int zpci_unregister_airq(struct zpci_dev *zdev)
+static int zpci_clear_airq(struct zpci_dev *zdev)
 {
        struct mod_pci_args args = { 0, 0, 0, 0 };
 
@@ -283,7 +249,7 @@ static int zpci_cfg_load(struct zpci_dev *zdev, int offset, u32 *val, u8 len)
        u64 data;
        int rc;
 
-       rc = s390pci_load(&data, req, offset);
+       rc = zpci_load(&data, req, offset);
        if (!rc) {
                data = data << ((8 - len) * 8);
                data = le64_to_cpu(data);
@@ -301,25 +267,46 @@ static int zpci_cfg_store(struct zpci_dev *zdev, int offset, u32 val, u8 len)
 
        data = cpu_to_le64(data);
        data = data >> ((8 - len) * 8);
-       rc = s390pci_store(data, req, offset);
+       rc = zpci_store(data, req, offset);
        return rc;
 }
 
-void enable_irq(unsigned int irq)
+static int zpci_msi_set_mask_bits(struct msi_desc *msi, u32 mask, u32 flag)
 {
-       struct msi_desc *msi = irq_get_msi_desc(irq);
+       int offset, pos;
+       u32 mask_bits;
+
+       if (msi->msi_attrib.is_msix) {
+               offset = msi->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
+                       PCI_MSIX_ENTRY_VECTOR_CTRL;
+               msi->masked = readl(msi->mask_base + offset);
+               writel(flag, msi->mask_base + offset);
+       } else if (msi->msi_attrib.maskbit) {
+               pos = (long) msi->mask_base;
+               pci_read_config_dword(msi->dev, pos, &mask_bits);
+               mask_bits &= ~(mask);
+               mask_bits |= flag & mask;
+               pci_write_config_dword(msi->dev, pos, mask_bits);
+       } else
+               return 0;
+
+       msi->msi_attrib.maskbit = !!flag;
+       return 1;
+}
+
+static void zpci_enable_irq(struct irq_data *data)
+{
+       struct msi_desc *msi = irq_get_msi_desc(data->irq);
 
        zpci_msi_set_mask_bits(msi, 1, 0);
 }
-EXPORT_SYMBOL_GPL(enable_irq);
 
-void disable_irq(unsigned int irq)
+static void zpci_disable_irq(struct irq_data *data)
 {
-       struct msi_desc *msi = irq_get_msi_desc(irq);
+       struct msi_desc *msi = irq_get_msi_desc(data->irq);
 
        zpci_msi_set_mask_bits(msi, 1, 1);
 }
-EXPORT_SYMBOL_GPL(disable_irq);
 
 void pcibios_fixup_bus(struct pci_bus *bus)
 {
@@ -404,152 +391,145 @@ static struct pci_ops pci_root_ops = {
        .write = pci_write,
 };
 
-/* store the last handled bit to implement fair scheduling of devices */
-static DEFINE_PER_CPU(unsigned long, next_sbit);
-
 static void zpci_irq_handler(struct airq_struct *airq)
 {
-       unsigned long sbit, mbit, last = 0, start = __get_cpu_var(next_sbit);
-       int rescan = 0, max = aisb_max;
-       struct zdev_irq_map *imap;
+       unsigned long si, ai;
+       struct airq_iv *aibv;
+       int irqs_on = 0;
 
        inc_irq_stat(IRQIO_PCI);
-       sbit = start;
-
-scan:
-       /* find summary_bit */
-       for_each_set_bit_left_cont(sbit, bucket->aisb, max) {
-               clear_bit(63 - (sbit & 63), bucket->aisb + (sbit >> 6));
-               last = sbit;
+       for (si = 0;;) {
+               /* Scan adapter summary indicator bit vector */
+               si = airq_iv_scan(zpci_aisb_iv, si, airq_iv_end(zpci_aisb_iv));
+               if (si == -1UL) {
+                       if (irqs_on++)
+                               /* End of second scan with interrupts on. */
+                               break;
+                       /* First scan complete, reenable interrupts. */
+                       zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC);
+                       si = 0;
+                       continue;
+               }
 
-               /* find vector bit */
-               imap = bucket->imap[sbit];
-               for_each_set_bit_left(mbit, &imap->aibv, imap->msi_vecs) {
+               /* Scan the adapter interrupt vector for this device. */
+               aibv = zpci_aibv[si];
+               for (ai = 0;;) {
+                       ai = airq_iv_scan(aibv, ai, airq_iv_end(aibv));
+                       if (ai == -1UL)
+                               break;
                        inc_irq_stat(IRQIO_MSI);
-                       clear_bit(63 - mbit, &imap->aibv);
-
-                       spin_lock(&imap->lock);
-                       if (imap->cb[mbit].handler)
-                               imap->cb[mbit].handler(mbit,
-                                       imap->cb[mbit].data);
-                       spin_unlock(&imap->lock);
+                       generic_handle_irq(airq_iv_get_data(aibv, ai));
                }
        }
-
-       if (rescan)
-               goto out;
-
-       /* scan the skipped bits */
-       if (start > 0) {
-               sbit = 0;
-               max = start;
-               start = 0;
-               goto scan;
-       }
-
-       /* enable interrupts again */
-       set_irq_ctrl(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC);
-
-       /* check again to not lose initiative */
-       rmb();
-       max = aisb_max;
-       sbit = find_first_bit_left(bucket->aisb, max);
-       if (sbit != max) {
-               rescan++;
-               goto scan;
-       }
-out:
-       /* store next device bit to scan */
-       __get_cpu_var(next_sbit) = (++last >= aisb_max) ? 0 : last;
 }
 
-/* msi_vecs - number of requested interrupts, 0 place function to error state */
-static int zpci_setup_msi(struct pci_dev *pdev, int msi_vecs)
+int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
 {
        struct zpci_dev *zdev = get_zdev(pdev);
-       unsigned int aisb, msi_nr;
+       unsigned int hwirq, irq, msi_vecs;
+       unsigned long aisb;
        struct msi_desc *msi;
+       struct msi_msg msg;
        int rc;
 
-       /* store the number of used MSI vectors */
-       zdev->irq_map->msi_vecs = min(msi_vecs, ZPCI_NR_MSI_VECS);
-
-       spin_lock(&bucket->lock);
-       aisb = find_first_zero_bit(bucket->alloc, PAGE_SIZE);
-       /* alloc map exhausted? */
-       if (aisb == PAGE_SIZE) {
-               spin_unlock(&bucket->lock);
-               return -EIO;
-       }
-       set_bit(aisb, bucket->alloc);
-       spin_unlock(&bucket->lock);
+       pr_debug("%s: requesting %d MSI-X interrupts...", __func__, nvec);
+       if (type != PCI_CAP_ID_MSIX && type != PCI_CAP_ID_MSI)
+               return -EINVAL;
+       msi_vecs = min(nvec, ZPCI_MSI_VEC_MAX);
+       msi_vecs = min_t(unsigned int, msi_vecs, CONFIG_PCI_NR_MSI);
 
+       /* Allocate adapter summary indicator bit */
+       rc = -EIO;
+       aisb = airq_iv_alloc_bit(zpci_aisb_iv);
+       if (aisb == -1UL)
+               goto out;
        zdev->aisb = aisb;
-       if (aisb + 1 > aisb_max)
-               aisb_max = aisb + 1;
 
-       /* wire up IRQ shortcut pointer */
-       bucket->imap[zdev->aisb] = zdev->irq_map;
-       pr_debug("%s: imap[%u] linked to %p\n", __func__, zdev->aisb, zdev->irq_map);
+       /* Create adapter interrupt vector */
+       rc = -ENOMEM;
+       zdev->aibv = airq_iv_create(msi_vecs, AIRQ_IV_DATA);
+       if (!zdev->aibv)
+               goto out_si;
 
-       /* TODO: irq number 0 wont be found if we return less than requested MSIs.
-        * ignore it for now and fix in common code.
-        */
-       msi_nr = aisb << ZPCI_MSI_VEC_BITS;
+       /* Wire up shortcut pointer */
+       zpci_aibv[aisb] = zdev->aibv;
 
+       /* Request MSI interrupts */
+       hwirq = 0;
        list_for_each_entry(msi, &pdev->msi_list, list) {
-               rc = zpci_setup_msi_irq(zdev, msi, msi_nr,
-                                         aisb << ZPCI_MSI_VEC_BITS);
+               rc = -EIO;
+               irq = irq_alloc_desc(0);        /* Alloc irq on node 0 */
+               if (irq == NO_IRQ)
+                       goto out_msi;
+               rc = irq_set_msi_desc(irq, msi);
                if (rc)
-                       return rc;
-               msi_nr++;
+                       goto out_msi;
+               irq_set_chip_and_handler(irq, &zpci_irq_chip,
+                                        handle_simple_irq);
+               msg.data = hwirq;
+               msg.address_lo = zdev->msi_addr & 0xffffffff;
+               msg.address_hi = zdev->msi_addr >> 32;
+               write_msi_msg(irq, &msg);
+               airq_iv_set_data(zdev->aibv, hwirq, irq);
+               hwirq++;
        }
 
-       rc = zpci_register_airq(zdev, aisb, (u64) &zdev->irq_map->aibv);
-       if (rc) {
-               clear_bit(aisb, bucket->alloc);
-               dev_err(&pdev->dev, "register MSI failed with: %d\n", rc);
-               return rc;
+       /* Enable adapter interrupts */
+       rc = zpci_set_airq(zdev);
+       if (rc)
+               goto out_msi;
+
+       return (msi_vecs == nvec) ? 0 : msi_vecs;
+
+out_msi:
+       list_for_each_entry(msi, &pdev->msi_list, list) {
+               if (hwirq-- == 0)
+                       break;
+               irq_set_msi_desc(msi->irq, NULL);
+               irq_free_desc(msi->irq);
+               msi->msg.address_lo = 0;
+               msi->msg.address_hi = 0;
+               msi->msg.data = 0;
+               msi->irq = 0;
        }
-       return (zdev->irq_map->msi_vecs == msi_vecs) ?
-               0 : zdev->irq_map->msi_vecs;
+       zpci_aibv[aisb] = NULL;
+       airq_iv_release(zdev->aibv);
+out_si:
+       airq_iv_free_bit(zpci_aisb_iv, aisb);
+out:
+       dev_err(&pdev->dev, "register MSI failed with: %d\n", rc);
+       return rc;
 }
 
-static void zpci_teardown_msi(struct pci_dev *pdev)
+void arch_teardown_msi_irqs(struct pci_dev *pdev)
 {
        struct zpci_dev *zdev = get_zdev(pdev);
        struct msi_desc *msi;
-       int aisb, rc;
+       int rc;
 
-       rc = zpci_unregister_airq(zdev);
+       pr_info("%s: on pdev: %p\n", __func__, pdev);
+
+       /* Disable adapter interrupts */
+       rc = zpci_clear_airq(zdev);
        if (rc) {
                dev_err(&pdev->dev, "deregister MSI failed with: %d\n", rc);
                return;
        }
 
-       msi = list_first_entry(&pdev->msi_list, struct msi_desc, list);
-       aisb = irq_to_dev_nr(msi->irq);
-
-       list_for_each_entry(msi, &pdev->msi_list, list)
-               zpci_teardown_msi_irq(zdev, msi);
-
-       clear_bit(aisb, bucket->alloc);
-       if (aisb + 1 == aisb_max)
-               aisb_max--;
-}
-
-int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
-{
-       pr_debug("%s: requesting %d MSI-X interrupts...", __func__, nvec);
-       if (type != PCI_CAP_ID_MSIX && type != PCI_CAP_ID_MSI)
-               return -EINVAL;
-       return zpci_setup_msi(pdev, nvec);
-}
+       /* Release MSI interrupts */
+       list_for_each_entry(msi, &pdev->msi_list, list) {
+               zpci_msi_set_mask_bits(msi, 1, 1);
+               irq_set_msi_desc(msi->irq, NULL);
+               irq_free_desc(msi->irq);
+               msi->msg.address_lo = 0;
+               msi->msg.address_hi = 0;
+               msi->msg.data = 0;
+               msi->irq = 0;
+       }
 
-void arch_teardown_msi_irqs(struct pci_dev *pdev)
-{
-       pr_info("%s: on pdev: %p\n", __func__, pdev);
-       zpci_teardown_msi(pdev);
+       zpci_aibv[zdev->aisb] = NULL;
+       airq_iv_release(zdev->aibv);
+       airq_iv_free_bit(zpci_aisb_iv, zdev->aisb);
 }
 
 static void zpci_map_resources(struct zpci_dev *zdev)
@@ -589,24 +569,11 @@ struct zpci_dev *zpci_alloc_device(void)
 
        /* Alloc memory for our private pci device data */
        zdev = kzalloc(sizeof(*zdev), GFP_KERNEL);
-       if (!zdev)
-               return ERR_PTR(-ENOMEM);
-
-       /* Alloc aibv & callback space */
-       zdev->irq_map = kmem_cache_zalloc(zdev_irq_cache, GFP_KERNEL);
-       if (!zdev->irq_map)
-               goto error;
-       WARN_ON((u64) zdev->irq_map & 0xff);
-       return zdev;
-
-error:
-       kfree(zdev);
-       return ERR_PTR(-ENOMEM);
+       return zdev ? : ERR_PTR(-ENOMEM);
 }
 
 void zpci_free_device(struct zpci_dev *zdev)
 {
-       kmem_cache_free(zdev_irq_cache, zdev->irq_map);
        kfree(zdev);
 }
 
@@ -641,110 +608,34 @@ int pcibios_add_platform_entries(struct pci_dev *pdev)
        return zpci_sysfs_add_device(&pdev->dev);
 }
 
-int zpci_request_irq(unsigned int irq, irq_handler_t handler, void *data)
-{
-       int msi_nr = irq_to_msi_nr(irq);
-       struct zdev_irq_map *imap;
-       struct msi_desc *msi;
-
-       msi = irq_get_msi_desc(irq);
-       if (!msi)
-               return -EIO;
-
-       imap = get_imap(irq);
-       spin_lock_init(&imap->lock);
-
-       pr_debug("%s: register handler for IRQ:MSI %d:%d\n", __func__, irq >> 6, msi_nr);
-       imap->cb[msi_nr].handler = handler;
-       imap->cb[msi_nr].data = data;
-
-       /*
-        * The generic MSI code returns with the interrupt disabled on the
-        * card, using the MSI mask bits. Firmware doesn't appear to unmask
-        * at that level, so we do it here by hand.
-        */
-       zpci_msi_set_mask_bits(msi, 1, 0);
-       return 0;
-}
-
-void zpci_free_irq(unsigned int irq)
-{
-       struct zdev_irq_map *imap = get_imap(irq);
-       int msi_nr = irq_to_msi_nr(irq);
-       unsigned long flags;
-
-       pr_debug("%s: for irq: %d\n", __func__, irq);
-
-       spin_lock_irqsave(&imap->lock, flags);
-       imap->cb[msi_nr].handler = NULL;
-       imap->cb[msi_nr].data = NULL;
-       spin_unlock_irqrestore(&imap->lock, flags);
-}
-
-int request_irq(unsigned int irq, irq_handler_t handler,
-               unsigned long irqflags, const char *devname, void *dev_id)
-{
-       pr_debug("%s: irq: %d  handler: %p  flags: %lx  dev: %s\n",
-               __func__, irq, handler, irqflags, devname);
-
-       return zpci_request_irq(irq, handler, dev_id);
-}
-EXPORT_SYMBOL_GPL(request_irq);
-
-void free_irq(unsigned int irq, void *dev_id)
-{
-       zpci_free_irq(irq);
-}
-EXPORT_SYMBOL_GPL(free_irq);
-
 static int __init zpci_irq_init(void)
 {
-       int cpu, rc;
-
-       bucket = kzalloc(sizeof(*bucket), GFP_KERNEL);
-       if (!bucket)
-               return -ENOMEM;
-
-       bucket->aisb = (unsigned long *) get_zeroed_page(GFP_KERNEL);
-       if (!bucket->aisb) {
-               rc = -ENOMEM;
-               goto out_aisb;
-       }
-
-       bucket->alloc = (unsigned long *) get_zeroed_page(GFP_KERNEL);
-       if (!bucket->alloc) {
-               rc = -ENOMEM;
-               goto out_alloc;
-       }
+       int rc;
 
        rc = register_adapter_interrupt(&zpci_airq);
        if (rc)
-               goto out_ai;
+               goto out;
        /* Set summary to 1 to be called every time for the ISC. */
        *zpci_airq.lsi_ptr = 1;
 
-       for_each_online_cpu(cpu)
-               per_cpu(next_sbit, cpu) = 0;
+       rc = -ENOMEM;
+       zpci_aisb_iv = airq_iv_create(ZPCI_NR_DEVICES, AIRQ_IV_ALLOC);
+       if (!zpci_aisb_iv)
+               goto out_airq;
 
-       spin_lock_init(&bucket->lock);
-       set_irq_ctrl(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC);
+       zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC);
        return 0;
 
-out_ai:
-       free_page((unsigned long) bucket->alloc);
-out_alloc:
-       free_page((unsigned long) bucket->aisb);
-out_aisb:
-       kfree(bucket);
+out_airq:
+       unregister_adapter_interrupt(&zpci_airq);
+out:
        return rc;
 }
 
 static void zpci_irq_exit(void)
 {
-       free_page((unsigned long) bucket->alloc);
-       free_page((unsigned long) bucket->aisb);
+       airq_iv_release(zpci_aisb_iv);
        unregister_adapter_interrupt(&zpci_airq);
-       kfree(bucket);
 }
 
 static struct resource *zpci_alloc_bus_resource(unsigned long start, unsigned long size,
@@ -967,15 +858,10 @@ static inline int barsize(u8 size)
 
 static int zpci_mem_init(void)
 {
-       zdev_irq_cache = kmem_cache_create("PCI_IRQ_cache", sizeof(struct zdev_irq_map),
-                               L1_CACHE_BYTES, SLAB_HWCACHE_ALIGN, NULL);
-       if (!zdev_irq_cache)
-               goto error_zdev;
-
        zdev_fmb_cache = kmem_cache_create("PCI_FMB_cache", sizeof(struct zpci_fmb),
                                16, 0, NULL);
        if (!zdev_fmb_cache)
-               goto error_fmb;
+               goto error_zdev;
 
        /* TODO: use realloc */
        zpci_iomap_start = kzalloc(ZPCI_IOMAP_MAX_ENTRIES * sizeof(*zpci_iomap_start),
@@ -986,8 +872,6 @@ static int zpci_mem_init(void)
 
 error_iomap:
        kmem_cache_destroy(zdev_fmb_cache);
-error_fmb:
-       kmem_cache_destroy(zdev_irq_cache);
 error_zdev:
        return -ENOMEM;
 }
@@ -995,7 +879,6 @@ error_zdev:
 static void zpci_mem_exit(void)
 {
        kfree(zpci_iomap_start);
-       kmem_cache_destroy(zdev_irq_cache);
        kmem_cache_destroy(zdev_fmb_cache);
 }
 
@@ -1044,16 +927,12 @@ static int __init pci_base_init(void)
 
        rc = zpci_debug_init();
        if (rc)
-               return rc;
+               goto out;
 
        rc = zpci_mem_init();
        if (rc)
                goto out_mem;
 
-       rc = zpci_msihash_init();
-       if (rc)
-               goto out_hash;
-
        rc = zpci_irq_init();
        if (rc)
                goto out_irq;
@@ -1073,11 +952,10 @@ out_find:
 out_dma:
        zpci_irq_exit();
 out_irq:
-       zpci_msihash_exit();
-out_hash:
        zpci_mem_exit();
 out_mem:
        zpci_debug_exit();
+out:
        return rc;
 }
 subsys_initcall(pci_base_init);
index a2343c1f6e0494e0904871a10a69c312fb89fa47..2125310aa891b7beb4f6c9d15b5fe44a18a58ca0 100644 (file)
@@ -170,8 +170,8 @@ static int dma_update_trans(struct zpci_dev *zdev, unsigned long pa,
                 */
                goto no_refresh;
 
-       rc = s390pci_refresh_trans((u64) zdev->fh << 32, start_dma_addr,
-                                  nr_pages * PAGE_SIZE);
+       rc = zpci_refresh_trans((u64) zdev->fh << 32, start_dma_addr,
+                               nr_pages * PAGE_SIZE);
 
 no_refresh:
        spin_unlock_irqrestore(&zdev->dma_table_lock, irq_flags);
index 22eeb9d7ffebd3147d96b8b899af3fb92156b7b5..85267c058af8067d1b6527f05ec483ab0a15c8b0 100644 (file)
@@ -27,7 +27,7 @@ static inline u8 __mpcifc(u64 req, struct zpci_fib *fib, u8 *status)
        return cc;
 }
 
-int s390pci_mod_fc(u64 req, struct zpci_fib *fib)
+int zpci_mod_fc(u64 req, struct zpci_fib *fib)
 {
        u8 cc, status;
 
@@ -61,7 +61,7 @@ static inline u8 __rpcit(u64 fn, u64 addr, u64 range, u8 *status)
        return cc;
 }
 
-int s390pci_refresh_trans(u64 fn, u64 addr, u64 range)
+int zpci_refresh_trans(u64 fn, u64 addr, u64 range)
 {
        u8 cc, status;
 
@@ -78,7 +78,7 @@ int s390pci_refresh_trans(u64 fn, u64 addr, u64 range)
 }
 
 /* Set Interruption Controls */
-void set_irq_ctrl(u16 ctl, char *unused, u8 isc)
+void zpci_set_irq_ctrl(u16 ctl, char *unused, u8 isc)
 {
        asm volatile (
                "       .insn   rsy,0xeb00000000d1,%[ctl],%[isc],%[u]\n"
@@ -109,7 +109,7 @@ static inline int __pcilg(u64 *data, u64 req, u64 offset, u8 *status)
        return cc;
 }
 
-int s390pci_load(u64 *data, u64 req, u64 offset)
+int zpci_load(u64 *data, u64 req, u64 offset)
 {
        u8 status;
        int cc;
@@ -125,7 +125,7 @@ int s390pci_load(u64 *data, u64 req, u64 offset)
                            __func__, cc, status, req, offset);
        return (cc > 0) ? -EIO : cc;
 }
-EXPORT_SYMBOL_GPL(s390pci_load);
+EXPORT_SYMBOL_GPL(zpci_load);
 
 /* PCI Store */
 static inline int __pcistg(u64 data, u64 req, u64 offset, u8 *status)
@@ -147,7 +147,7 @@ static inline int __pcistg(u64 data, u64 req, u64 offset, u8 *status)
        return cc;
 }
 
-int s390pci_store(u64 data, u64 req, u64 offset)
+int zpci_store(u64 data, u64 req, u64 offset)
 {
        u8 status;
        int cc;
@@ -163,7 +163,7 @@ int s390pci_store(u64 data, u64 req, u64 offset)
                        __func__, cc, status, req, offset);
        return (cc > 0) ? -EIO : cc;
 }
-EXPORT_SYMBOL_GPL(s390pci_store);
+EXPORT_SYMBOL_GPL(zpci_store);
 
 /* PCI Store Block */
 static inline int __pcistb(const u64 *data, u64 req, u64 offset, u8 *status)
@@ -183,7 +183,7 @@ static inline int __pcistb(const u64 *data, u64 req, u64 offset, u8 *status)
        return cc;
 }
 
-int s390pci_store_block(const u64 *data, u64 req, u64 offset)
+int zpci_store_block(const u64 *data, u64 req, u64 offset)
 {
        u8 status;
        int cc;
@@ -199,4 +199,4 @@ int s390pci_store_block(const u64 *data, u64 req, u64 offset)
                            __func__, cc, status, req, offset);
        return (cc > 0) ? -EIO : cc;
 }
-EXPORT_SYMBOL_GPL(s390pci_store_block);
+EXPORT_SYMBOL_GPL(zpci_store_block);
diff --git a/arch/s390/pci/pci_msi.c b/arch/s390/pci/pci_msi.c
deleted file mode 100644 (file)
index b097aed..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright IBM Corp. 2012
- *
- * Author(s):
- *   Jan Glauber <jang@linux.vnet.ibm.com>
- */
-
-#define COMPONENT "zPCI"
-#define pr_fmt(fmt) COMPONENT ": " fmt
-
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/rculist.h>
-#include <linux/hash.h>
-#include <linux/pci.h>
-#include <linux/msi.h>
-#include <asm/hw_irq.h>
-
-/* mapping of irq numbers to msi_desc */
-static struct hlist_head *msi_hash;
-static const unsigned int msi_hash_bits = 8;
-#define MSI_HASH_BUCKETS (1U << msi_hash_bits)
-#define msi_hashfn(nr) hash_long(nr, msi_hash_bits)
-
-static DEFINE_SPINLOCK(msi_map_lock);
-
-struct msi_desc *__irq_get_msi_desc(unsigned int irq)
-{
-       struct msi_map *map;
-
-       hlist_for_each_entry_rcu(map,
-                       &msi_hash[msi_hashfn(irq)], msi_chain)
-               if (map->irq == irq)
-                       return map->msi;
-       return NULL;
-}
-
-int zpci_msi_set_mask_bits(struct msi_desc *msi, u32 mask, u32 flag)
-{
-       if (msi->msi_attrib.is_msix) {
-               int offset = msi->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
-                       PCI_MSIX_ENTRY_VECTOR_CTRL;
-               msi->masked = readl(msi->mask_base + offset);
-               writel(flag, msi->mask_base + offset);
-       } else {
-               if (msi->msi_attrib.maskbit) {
-                       int pos;
-                       u32 mask_bits;
-
-                       pos = (long) msi->mask_base;
-                       pci_read_config_dword(msi->dev, pos, &mask_bits);
-                       mask_bits &= ~(mask);
-                       mask_bits |= flag & mask;
-                       pci_write_config_dword(msi->dev, pos, mask_bits);
-               } else {
-                       return 0;
-               }
-       }
-
-       msi->msi_attrib.maskbit = !!flag;
-       return 1;
-}
-
-int zpci_setup_msi_irq(struct zpci_dev *zdev, struct msi_desc *msi,
-                       unsigned int nr, int offset)
-{
-       struct msi_map *map;
-       struct msi_msg msg;
-       int rc;
-
-       map = kmalloc(sizeof(*map), GFP_KERNEL);
-       if (map == NULL)
-               return -ENOMEM;
-
-       map->irq = nr;
-       map->msi = msi;
-       zdev->msi_map[nr & ZPCI_MSI_MASK] = map;
-       INIT_HLIST_NODE(&map->msi_chain);
-
-       pr_debug("%s hashing irq: %u  to bucket nr: %llu\n",
-               __func__, nr, msi_hashfn(nr));
-       hlist_add_head_rcu(&map->msi_chain, &msi_hash[msi_hashfn(nr)]);
-
-       spin_lock(&msi_map_lock);
-       rc = irq_set_msi_desc(nr, msi);
-       if (rc) {
-               spin_unlock(&msi_map_lock);
-               hlist_del_rcu(&map->msi_chain);
-               kfree(map);
-               zdev->msi_map[nr & ZPCI_MSI_MASK] = NULL;
-               return rc;
-       }
-       spin_unlock(&msi_map_lock);
-
-       msg.data = nr - offset;
-       msg.address_lo = zdev->msi_addr & 0xffffffff;
-       msg.address_hi = zdev->msi_addr >> 32;
-       write_msi_msg(nr, &msg);
-       return 0;
-}
-
-void zpci_teardown_msi_irq(struct zpci_dev *zdev, struct msi_desc *msi)
-{
-       int irq = msi->irq & ZPCI_MSI_MASK;
-       struct msi_map *map;
-
-       msi->msg.address_lo = 0;
-       msi->msg.address_hi = 0;
-       msi->msg.data = 0;
-       msi->irq = 0;
-       zpci_msi_set_mask_bits(msi, 1, 1);
-
-       spin_lock(&msi_map_lock);
-       map = zdev->msi_map[irq];
-       hlist_del_rcu(&map->msi_chain);
-       kfree(map);
-       zdev->msi_map[irq] = NULL;
-       spin_unlock(&msi_map_lock);
-}
-
-/*
- * The msi hash table has 256 entries which is good for 4..20
- * devices (a typical device allocates 10 + CPUs MSI's). Maybe make
- * the hash table size adjustable later.
- */
-int __init zpci_msihash_init(void)
-{
-       unsigned int i;
-
-       msi_hash = kmalloc(MSI_HASH_BUCKETS * sizeof(*msi_hash), GFP_KERNEL);
-       if (!msi_hash)
-               return -ENOMEM;
-
-       for (i = 0; i < MSI_HASH_BUCKETS; i++)
-               INIT_HLIST_HEAD(&msi_hash[i]);
-       return 0;
-}
-
-void __init zpci_msihash_exit(void)
-{
-       kfree(msi_hash);
-}
index 2051821724c6db6d33ac89b333bc5214b61b68ea..0cf4097b71e8d02051a3976d86b63226ab2b8924 100644 (file)
@@ -22,7 +22,7 @@ CONFIG_PREEMPT=y
 CONFIG_CMDLINE_OVERWRITE=y
 CONFIG_CMDLINE="console=ttySC1,115200 mem=64M root=/dev/nfs"
 CONFIG_PCI=y
-CONFIG_HOTPLUG_PCI=m
+CONFIG_HOTPLUG_PCI=y
 CONFIG_BINFMT_MISC=y
 CONFIG_NET=y
 CONFIG_PACKET=y
index ec9ad593c3da743bacbd5875a577709a94e3333b..01a38696137e9952c9e07f91669685b3b349b50d 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <linux/kdebug.h>
 #include <linux/types.h>
+#include <cpu/ubc.h>
 
 struct arch_hw_breakpoint {
        char            *name; /* Contains name of the symbol to set bkpt */
@@ -15,17 +16,6 @@ struct arch_hw_breakpoint {
        u16             type;
 };
 
-enum {
-       SH_BREAKPOINT_READ      = (1 << 1),
-       SH_BREAKPOINT_WRITE     = (1 << 2),
-       SH_BREAKPOINT_RW        = SH_BREAKPOINT_READ | SH_BREAKPOINT_WRITE,
-
-       SH_BREAKPOINT_LEN_1     = (1 << 12),
-       SH_BREAKPOINT_LEN_2     = (1 << 13),
-       SH_BREAKPOINT_LEN_4     = SH_BREAKPOINT_LEN_1 | SH_BREAKPOINT_LEN_2,
-       SH_BREAKPOINT_LEN_8     = (1 << 14),
-};
-
 struct sh_ubc {
        const char      *name;
        unsigned int    num_events;
diff --git a/arch/sh/include/cpu-common/cpu/ubc.h b/arch/sh/include/cpu-common/cpu/ubc.h
new file mode 100644 (file)
index 0000000..b604619
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef __ARCH_SH_CPU_UBC_H__
+#define __ARCH_SH_CPU_UBC_H__
+
+enum {
+       SH_BREAKPOINT_READ      = (1 << 1),
+       SH_BREAKPOINT_WRITE     = (1 << 2),
+       SH_BREAKPOINT_RW        = SH_BREAKPOINT_READ | SH_BREAKPOINT_WRITE,
+
+       SH_BREAKPOINT_LEN_1     = (1 << 12),
+       SH_BREAKPOINT_LEN_2     = (1 << 13),
+       SH_BREAKPOINT_LEN_4     = SH_BREAKPOINT_LEN_1 | SH_BREAKPOINT_LEN_2,
+       SH_BREAKPOINT_LEN_8     = (1 << 14),
+};
+
+#define UBC_64BIT      1
+
+#endif /* __ARCH_SH_CPU_UBC_H__ */
diff --git a/arch/sh/include/cpu-sh2a/cpu/ubc.h b/arch/sh/include/cpu-sh2a/cpu/ubc.h
new file mode 100644 (file)
index 0000000..3371f90
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __ARCH_SH_CPU_UBC_H__
+#define __ARCH_SH_CPU_UBC_H__
+
+enum {
+       SH_BREAKPOINT_READ      = (1 << 2),
+       SH_BREAKPOINT_WRITE     = (1 << 3),
+       SH_BREAKPOINT_RW        = SH_BREAKPOINT_READ | SH_BREAKPOINT_WRITE,
+
+       SH_BREAKPOINT_LEN_1     = (1 << 0),
+       SH_BREAKPOINT_LEN_2     = (1 << 1),
+       SH_BREAKPOINT_LEN_4     = SH_BREAKPOINT_LEN_1 | SH_BREAKPOINT_LEN_2,
+};
+
+#endif /* __ARCH_SH_CPU_UBC_H__ */
index 990195d9845607bfcca4a8b3cfcd05c41df582bc..92f0da4c86a7533e18269e6f5d439130e1a71815 100644 (file)
@@ -22,3 +22,4 @@ pinmux-$(CONFIG_CPU_SUBTYPE_SH7264)   := pinmux-sh7264.o
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7269)    := pinmux-sh7269.o
 
 obj-$(CONFIG_GPIOLIB)                  += $(pinmux-y)
+obj-$(CONFIG_HAVE_HW_BREAKPOINT)       += ubc.o
diff --git a/arch/sh/kernel/cpu/sh2a/ubc.c b/arch/sh/kernel/cpu/sh2a/ubc.c
new file mode 100644 (file)
index 0000000..ef95a9b
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * arch/sh/kernel/cpu/sh2a/ubc.c
+ *
+ * On-chip UBC support for SH-2A CPUs.
+ *
+ * Copyright (C) 2009 - 2010  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <asm/hw_breakpoint.h>
+
+#define UBC_BAR(idx)   (0xfffc0400 + (0x10 * idx))
+#define UBC_BAMR(idx)  (0xfffc0404 + (0x10 * idx))
+#define UBC_BBR(idx)   (0xfffc04A0 + (0x10 * idx))
+#define UBC_BDR(idx)   (0xfffc0408 + (0x10 * idx))
+#define UBC_BDMR(idx)  (0xfffc040C + (0x10 * idx))
+
+#define UBC_BRCR       0xfffc04C0
+
+/* BBR */
+#define UBC_BBR_UBID   (1 << 13)     /* User Break Interrupt Disable */
+#define UBC_BBR_DBE    (1 << 12)     /* Data Break Enable */
+#define UBC_BBR_CD_C   (1 << 6)      /* C Bus Cycle */
+#define UBC_BBR_CD_I   (2 << 6)      /* I Bus Cycle */
+#define UBC_BBR_ID_I   (1 << 4)      /* Break Condition is instruction fetch cycle */
+#define UBC_BBR_ID_D   (2 << 4)      /* Break Condition is data access cycle */
+#define UBC_BBR_ID_ID  (3 << 4)      /* Break Condition is instruction fetch or data access cycle */
+
+#define UBC_CRR_BIE    (1 << 0)
+
+/* CBR */
+#define UBC_CBR_CE     (1 << 0)
+
+static struct sh_ubc sh2a_ubc;
+
+static void sh2a_ubc_enable(struct arch_hw_breakpoint *info, int idx)
+{
+       __raw_writel(UBC_BBR_DBE | UBC_BBR_CD_C | UBC_BBR_ID_ID |
+                    info->len | info->type, UBC_BBR(idx));
+       __raw_writel(info->address, UBC_BAR(idx));
+}
+
+static void sh2a_ubc_disable(struct arch_hw_breakpoint *info, int idx)
+{
+       __raw_writel(UBC_BBR_UBID, UBC_BBR(idx));
+       __raw_writel(0, UBC_BAR(idx));
+}
+
+static void sh2a_ubc_enable_all(unsigned long mask)
+{
+       int i;
+
+       for (i = 0; i < sh2a_ubc.num_events; i++)
+               if (mask & (1 << i))
+                       __raw_writel(__raw_readl(UBC_BBR(i)) & ~UBC_BBR_UBID,
+                                    UBC_BBR(i));
+}
+
+static void sh2a_ubc_disable_all(void)
+{
+       int i;
+       
+       for (i = 0; i < sh2a_ubc.num_events; i++)
+               __raw_writel(__raw_readl(UBC_BBR(i)) | UBC_BBR_UBID,
+                            UBC_BBR(i));
+}
+
+static unsigned long sh2a_ubc_active_mask(void)
+{
+       unsigned long active = 0;
+       int i;
+
+       for (i = 0; i < sh2a_ubc.num_events; i++)
+               if (!(__raw_readl(UBC_BBR(i)) & UBC_BBR_UBID))
+                       active |= (1 << i);
+
+       return active;
+}
+
+static unsigned long sh2a_ubc_triggered_mask(void)
+{
+       unsigned int ret, mask;
+       
+       mask = 0;
+       ret = __raw_readl(UBC_BRCR);
+       if ((ret & (1 << 15)) || (ret & (1 << 13))) {
+               mask |= (1 << 0); /* Match condition for channel 0 */
+       } else 
+               mask &= ~(1 << 0);
+       
+       if ((ret & (1 << 14)) || (ret & (1 << 12))) {
+               mask |= (1 << 1); /* Match condition for channel 1 */
+       } else 
+               mask &= ~(1 << 1);
+
+       return mask;
+}
+
+static void sh2a_ubc_clear_triggered_mask(unsigned long mask)
+{
+       if (mask & (1 << 0)) /* Channel 0 statisfied break condition */
+               __raw_writel(__raw_readl(UBC_BRCR) &
+                            ~((1 << 15) | (1 << 13)), UBC_BRCR);
+       
+       if (mask & (1 << 1)) /* Channel 1 statisfied break condition */
+               __raw_writel(__raw_readl(UBC_BRCR) &
+                            ~((1 << 14) | (1 << 12)), UBC_BRCR);
+}
+
+static struct sh_ubc sh2a_ubc = {
+       .name                   = "SH-2A",
+       .num_events             = 2,
+       .trap_nr                = 0x1e0,
+       .enable                 = sh2a_ubc_enable,
+       .disable                = sh2a_ubc_disable,
+       .enable_all             = sh2a_ubc_enable_all,
+       .disable_all            = sh2a_ubc_disable_all,
+       .active_mask            = sh2a_ubc_active_mask,
+       .triggered_mask         = sh2a_ubc_triggered_mask,
+       .clear_triggered_mask   = sh2a_ubc_clear_triggered_mask,
+};
+
+static int __init sh2a_ubc_init(void)
+{
+       struct clk *ubc_iclk = clk_get(NULL, "ubc0");
+       int i;
+
+       /*
+        * The UBC MSTP bit is optional, as not all platforms will have
+        * it. Just ignore it if we can't find it.
+        */
+       if (IS_ERR(ubc_iclk))
+               ubc_iclk = NULL;
+
+       clk_enable(ubc_iclk);
+
+       for (i = 0; i < sh2a_ubc.num_events; i++) {
+               __raw_writel(0, UBC_BAMR(i));
+               __raw_writel(0, UBC_BBR(i));
+       }
+
+       clk_disable(ubc_iclk);
+
+       sh2a_ubc.clk = ubc_iclk;
+
+       return register_sh_ubc(&sh2a_ubc);
+}
+arch_initcall(sh2a_ubc_init);
index f9173766ec4be2393e4207efe7092741f35fc271..ac4922ad3c148d3fc0883afe9ccb8a50d078fc76 100644 (file)
@@ -113,9 +113,11 @@ static int get_hbp_len(u16 hbp_len)
        case SH_BREAKPOINT_LEN_4:
                len_in_bytes = 4;
                break;
+#ifdef UBC_64BIT
        case SH_BREAKPOINT_LEN_8:
                len_in_bytes = 8;
                break;
+#endif
        }
        return len_in_bytes;
 }
@@ -149,9 +151,11 @@ int arch_bp_generic_fields(int sh_len, int sh_type,
        case SH_BREAKPOINT_LEN_4:
                *gen_len = HW_BREAKPOINT_LEN_4;
                break;
+#ifdef UBC_64BIT
        case SH_BREAKPOINT_LEN_8:
                *gen_len = HW_BREAKPOINT_LEN_8;
                break;
+#endif
        default:
                return -EINVAL;
        }
@@ -190,9 +194,11 @@ static int arch_build_bp_info(struct perf_event *bp)
        case HW_BREAKPOINT_LEN_4:
                info->len = SH_BREAKPOINT_LEN_4;
                break;
+#ifdef UBC_64BIT
        case HW_BREAKPOINT_LEN_8:
                info->len = SH_BREAKPOINT_LEN_8;
                break;
+#endif
        default:
                return -EINVAL;
        }
@@ -240,9 +246,11 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
        case SH_BREAKPOINT_LEN_4:
                align = 3;
                break;
+#ifdef UBC_64BIT
        case SH_BREAKPOINT_LEN_8:
                align = 7;
                break;
+#endif
        default:
                return ret;
        }
index c7de3323819c5389a8c1855f09aa542cd67f4d41..8d284801f2322ec26f35bdd7b4e4953ccf993bc8 100644 (file)
@@ -48,8 +48,8 @@ do {  save_and_clear_fpu();                                           \
        "wrpr   %%g0, 14, %%pil\n\t"                                    \
        "brz,pt %%o7, switch_to_pc\n\t"                                 \
        " mov   %%g7, %0\n\t"                                           \
-       "sethi  %%hi(ret_from_syscall), %%g1\n\t"                       \
-       "jmpl   %%g1 + %%lo(ret_from_syscall), %%g0\n\t"                \
+       "sethi  %%hi(ret_from_fork), %%g1\n\t"                          \
+       "jmpl   %%g1 + %%lo(ret_from_fork), %%g0\n\t"                   \
        " nop\n\t"                                                      \
        ".globl switch_to_pc\n\t"                                       \
        "switch_to_pc:\n\t"                                             \
index e4de74c2c9b0d8082c80f57d757ef7577fbb8b0d..cb5d272d658acce52fc85a77b1e730a40c5d885a 100644 (file)
@@ -327,6 +327,7 @@ static int iterate_cpu(struct cpuinfo_tree *t, unsigned int root_index)
        case SUN4V_CHIP_NIAGARA3:
        case SUN4V_CHIP_NIAGARA4:
        case SUN4V_CHIP_NIAGARA5:
+       case SUN4V_CHIP_SPARC64X:
                rover_inc_table = niagara_iterate_method;
                break;
        default:
index e2a030045089f8c06acc55167e332e4ab13a1da5..33c02b15f47859a8262677d08635fcfdbb8872cb 100644 (file)
@@ -839,7 +839,7 @@ sys_sigreturn:
         nop
 
        call    syscall_trace
-        nop
+        mov    1, %o1
 
 1:
        /* We don't want to muck with user registers like a
index c8759550799f0beb13b9108d60de83b19c2fab04..53c0a82e60308d541271707681b046824ad79456 100644 (file)
@@ -42,7 +42,7 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
 {
        struct thread_info *t = task_thread_info(p);
        extern unsigned int switch_to_pc;
-       extern unsigned int ret_from_syscall;
+       extern unsigned int ret_from_fork;
        struct reg_window *win;
        unsigned long pc, cwp;
        int i;
@@ -66,7 +66,7 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
                gdb_regs[i] = 0;
 
        if (t->new_child)
-               pc = (unsigned long) &ret_from_syscall;
+               pc = (unsigned long) &ret_from_fork;
        else
                pc = (unsigned long) &switch_to_pc;
 
index 7ff45e4ba6815080a29e02a64ad79bfdf9c1ed12..a34833099addecd65609155702538f11bbab981f 100644 (file)
@@ -1087,7 +1087,7 @@ asmlinkage void syscall_trace_leave(struct pt_regs *regs)
        audit_syscall_exit(regs);
 
        if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
-               trace_sys_exit(regs, regs->u_regs[UREG_G1]);
+               trace_sys_exit(regs, regs->u_regs[UREG_I0]);
 
        if (test_thread_flag(TIF_SYSCALL_TRACE))
                tracehook_report_syscall_exit(regs, 0);
index 13785547e435274bb6fa079968a9d516dc25800f..3fdb455e3318fab7626763ba6fb9b907e02203d8 100644 (file)
@@ -499,12 +499,14 @@ static void __init init_sparc64_elf_hwcap(void)
                    sun4v_chip_type == SUN4V_CHIP_NIAGARA2 ||
                    sun4v_chip_type == SUN4V_CHIP_NIAGARA3 ||
                    sun4v_chip_type == SUN4V_CHIP_NIAGARA4 ||
-                   sun4v_chip_type == SUN4V_CHIP_NIAGARA5)
+                   sun4v_chip_type == SUN4V_CHIP_NIAGARA5 ||
+                   sun4v_chip_type == SUN4V_CHIP_SPARC64X)
                        cap |= HWCAP_SPARC_BLKINIT;
                if (sun4v_chip_type == SUN4V_CHIP_NIAGARA2 ||
                    sun4v_chip_type == SUN4V_CHIP_NIAGARA3 ||
                    sun4v_chip_type == SUN4V_CHIP_NIAGARA4 ||
-                   sun4v_chip_type == SUN4V_CHIP_NIAGARA5)
+                   sun4v_chip_type == SUN4V_CHIP_NIAGARA5 ||
+                   sun4v_chip_type == SUN4V_CHIP_SPARC64X)
                        cap |= HWCAP_SPARC_N2;
        }
 
@@ -530,13 +532,15 @@ static void __init init_sparc64_elf_hwcap(void)
                        if (sun4v_chip_type == SUN4V_CHIP_NIAGARA2 ||
                            sun4v_chip_type == SUN4V_CHIP_NIAGARA3 ||
                            sun4v_chip_type == SUN4V_CHIP_NIAGARA4 ||
-                           sun4v_chip_type == SUN4V_CHIP_NIAGARA5)
+                           sun4v_chip_type == SUN4V_CHIP_NIAGARA5 ||
+                           sun4v_chip_type == SUN4V_CHIP_SPARC64X)
                                cap |= (AV_SPARC_VIS | AV_SPARC_VIS2 |
                                        AV_SPARC_ASI_BLK_INIT |
                                        AV_SPARC_POPC);
                        if (sun4v_chip_type == SUN4V_CHIP_NIAGARA3 ||
                            sun4v_chip_type == SUN4V_CHIP_NIAGARA4 ||
-                           sun4v_chip_type == SUN4V_CHIP_NIAGARA5)
+                           sun4v_chip_type == SUN4V_CHIP_NIAGARA5 ||
+                           sun4v_chip_type == SUN4V_CHIP_SPARC64X)
                                cap |= (AV_SPARC_VIS3 | AV_SPARC_HPC |
                                        AV_SPARC_FMAF);
                }
index 22a1098961f54a5f15c9ed87ec7d2c3ff3920e85..d950197a17e16229d0b62147b5956924d656baf4 100644 (file)
@@ -98,8 +98,8 @@ sys_clone:
        ba,pt   %xcc, sparc_do_fork
         add    %sp, PTREGS_OFF, %o2
 
-       .globl  ret_from_syscall
-ret_from_syscall:
+       .globl  ret_from_fork
+ret_from_fork:
        /* Clear current_thread_info()->new_child. */
        stb     %g0, [%g6 + TI_NEW_CHILD]
        call    schedule_tail
@@ -152,7 +152,7 @@ linux_syscall_trace32:
        srl     %i4, 0, %o4
        srl     %i1, 0, %o1
        srl     %i2, 0, %o2
-       ba,pt   %xcc, 2f
+       ba,pt   %xcc, 5f
         srl    %i3, 0, %o3
 
 linux_syscall_trace:
@@ -182,13 +182,13 @@ linux_sparc_syscall32:
        srl     %i1, 0, %o1                             ! IEU0  Group
        ldx     [%g6 + TI_FLAGS], %l0           ! Load
 
-       srl     %i5, 0, %o5                             ! IEU1
+       srl     %i3, 0, %o3                             ! IEU0
        srl     %i2, 0, %o2                             ! IEU0  Group
        andcc   %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT|_TIF_SYSCALL_TRACEPOINT), %g0
        bne,pn  %icc, linux_syscall_trace32             ! CTI
         mov    %i0, %l5                                ! IEU1
-       call    %l7                                     ! CTI   Group brk forced
-        srl    %i3, 0, %o3                             ! IEU0
+5:     call    %l7                                     ! CTI   Group brk forced
+        srl    %i5, 0, %o5                             ! IEU1
        ba,a,pt %xcc, 3f
 
        /* Linux native system calls enter here... */
index 31b87bf8c027e201fbc853e46bd5b99cbac864d6..4f8f3d619c4a652b428029f0bc2c0362775d79dd 100644 (file)
@@ -387,6 +387,27 @@ int gxio_mpipe_link_close_aux(gxio_mpipe_context_t * context, int mac)
 
 EXPORT_SYMBOL(gxio_mpipe_link_close_aux);
 
+struct link_set_attr_aux_param {
+       int mac;
+       uint32_t attr;
+       int64_t val;
+};
+
+int gxio_mpipe_link_set_attr_aux(gxio_mpipe_context_t * context, int mac,
+                                uint32_t attr, int64_t val)
+{
+       struct link_set_attr_aux_param temp;
+       struct link_set_attr_aux_param *params = &temp;
+
+       params->mac = mac;
+       params->attr = attr;
+       params->val = val;
+
+       return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+                            sizeof(*params), GXIO_MPIPE_OP_LINK_SET_ATTR_AUX);
+}
+
+EXPORT_SYMBOL(gxio_mpipe_link_set_attr_aux);
 
 struct get_timestamp_aux_param {
        uint64_t sec;
@@ -454,6 +475,51 @@ int gxio_mpipe_adjust_timestamp_aux(gxio_mpipe_context_t * context,
 
 EXPORT_SYMBOL(gxio_mpipe_adjust_timestamp_aux);
 
+struct adjust_timestamp_freq_param {
+       int32_t ppb;
+};
+
+int gxio_mpipe_adjust_timestamp_freq(gxio_mpipe_context_t * context,
+                                    int32_t ppb)
+{
+       struct adjust_timestamp_freq_param temp;
+       struct adjust_timestamp_freq_param *params = &temp;
+
+       params->ppb = ppb;
+
+       return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+                            sizeof(*params),
+                            GXIO_MPIPE_OP_ADJUST_TIMESTAMP_FREQ);
+}
+
+EXPORT_SYMBOL(gxio_mpipe_adjust_timestamp_freq);
+
+struct config_edma_ring_blks_param {
+       unsigned int ering;
+       unsigned int max_blks;
+       unsigned int min_snf_blks;
+       unsigned int db;
+};
+
+int gxio_mpipe_config_edma_ring_blks(gxio_mpipe_context_t * context,
+                                    unsigned int ering, unsigned int max_blks,
+                                    unsigned int min_snf_blks, unsigned int db)
+{
+       struct config_edma_ring_blks_param temp;
+       struct config_edma_ring_blks_param *params = &temp;
+
+       params->ering = ering;
+       params->max_blks = max_blks;
+       params->min_snf_blks = min_snf_blks;
+       params->db = db;
+
+       return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+                            sizeof(*params),
+                            GXIO_MPIPE_OP_CONFIG_EDMA_RING_BLKS);
+}
+
+EXPORT_SYMBOL(gxio_mpipe_config_edma_ring_blks);
+
 struct arm_pollfd_param {
        union iorpc_pollfd pollfd;
 };
index d0254aa60cbac3966e0f5c6a3ce9d6bb2995c907..64883aabeb9c19d2ce3d5e72f4c4040813c33e83 100644 (file)
 #include "gxio/iorpc_mpipe_info.h"
 
 
+struct instance_aux_param {
+       _gxio_mpipe_link_name_t name;
+};
+
+int gxio_mpipe_info_instance_aux(gxio_mpipe_info_context_t * context,
+                                _gxio_mpipe_link_name_t name)
+{
+       struct instance_aux_param temp;
+       struct instance_aux_param *params = &temp;
+
+       params->name = name;
+
+       return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+                            sizeof(*params), GXIO_MPIPE_INFO_OP_INSTANCE_AUX);
+}
+
+EXPORT_SYMBOL(gxio_mpipe_info_instance_aux);
+
 struct enumerate_aux_param {
        _gxio_mpipe_link_name_t name;
        _gxio_mpipe_link_mac_t mac;
index e71c63390acc03b35ed8678fa70d5c959aefee56..5301a9ffbae10917d1a7bd38ffd0ea136d8def6c 100644 (file)
@@ -36,8 +36,14 @@ int gxio_mpipe_init(gxio_mpipe_context_t *context, unsigned int mpipe_index)
        int fd;
        int i;
 
+       if (mpipe_index >= GXIO_MPIPE_INSTANCE_MAX)
+               return -EINVAL;
+
        snprintf(file, sizeof(file), "mpipe/%d/iorpc", mpipe_index);
        fd = hv_dev_open((HV_VirtAddr) file, 0);
+
+       context->fd = fd;
+
        if (fd < 0) {
                if (fd >= GXIO_ERR_MIN && fd <= GXIO_ERR_MAX)
                        return fd;
@@ -45,8 +51,6 @@ int gxio_mpipe_init(gxio_mpipe_context_t *context, unsigned int mpipe_index)
                        return -ENODEV;
        }
 
-       context->fd = fd;
-
        /* Map in the MMIO space. */
        context->mmio_cfg_base = (void __force *)
                iorpc_ioremap(fd, HV_MPIPE_CONFIG_MMIO_OFFSET,
@@ -64,12 +68,15 @@ int gxio_mpipe_init(gxio_mpipe_context_t *context, unsigned int mpipe_index)
        for (i = 0; i < 8; i++)
                context->__stacks.stacks[i] = 255;
 
+       context->instance = mpipe_index;
+
        return 0;
 
       fast_failed:
        iounmap((void __force __iomem *)(context->mmio_cfg_base));
       cfg_failed:
        hv_dev_close(context->fd);
+       context->fd = -1;
        return -ENODEV;
 }
 
@@ -383,7 +390,7 @@ EXPORT_SYMBOL_GPL(gxio_mpipe_iqueue_init);
 
 int gxio_mpipe_equeue_init(gxio_mpipe_equeue_t *equeue,
                           gxio_mpipe_context_t *context,
-                          unsigned int edma_ring_id,
+                          unsigned int ering,
                           unsigned int channel,
                           void *mem, unsigned int mem_size,
                           unsigned int mem_flags)
@@ -394,7 +401,7 @@ int gxio_mpipe_equeue_init(gxio_mpipe_equeue_t *equeue,
        /* Offset used to read number of completed commands. */
        MPIPE_EDMA_POST_REGION_ADDR_t offset;
 
-       int result = gxio_mpipe_init_edma_ring(context, edma_ring_id, channel,
+       int result = gxio_mpipe_init_edma_ring(context, ering, channel,
                                               mem, mem_size, mem_flags);
        if (result < 0)
                return result;
@@ -405,7 +412,7 @@ int gxio_mpipe_equeue_init(gxio_mpipe_equeue_t *equeue,
        offset.region =
                MPIPE_MMIO_ADDR__REGION_VAL_EDMA -
                MPIPE_MMIO_ADDR__REGION_VAL_IDMA;
-       offset.ring = edma_ring_id;
+       offset.ring = ering;
 
        __gxio_dma_queue_init(&equeue->dma_queue,
                              context->mmio_fast_base + offset.word,
@@ -413,6 +420,9 @@ int gxio_mpipe_equeue_init(gxio_mpipe_equeue_t *equeue,
        equeue->edescs = mem;
        equeue->mask_num_entries = num_entries - 1;
        equeue->log2_num_entries = __builtin_ctz(num_entries);
+       equeue->context = context;
+       equeue->ering = ering;
+       equeue->channel = channel;
 
        return 0;
 }
@@ -493,6 +503,20 @@ static gxio_mpipe_context_t *_gxio_get_link_context(void)
        return contextp;
 }
 
+int gxio_mpipe_link_instance(const char *link_name)
+{
+       _gxio_mpipe_link_name_t name;
+       gxio_mpipe_context_t *context = _gxio_get_link_context();
+
+       if (!context)
+               return GXIO_ERR_NO_DEVICE;
+
+       strncpy(name.name, link_name, sizeof(name.name));
+       name.name[GXIO_MPIPE_LINK_NAME_LEN - 1] = '\0';
+
+       return gxio_mpipe_info_instance_aux(context, name);
+}
+
 int gxio_mpipe_link_enumerate_mac(int idx, char *link_name, uint8_t *link_mac)
 {
        int rv;
@@ -543,3 +567,12 @@ int gxio_mpipe_link_close(gxio_mpipe_link_t *link)
 }
 
 EXPORT_SYMBOL_GPL(gxio_mpipe_link_close);
+
+int gxio_mpipe_link_set_attr(gxio_mpipe_link_t *link, uint32_t attr,
+                            int64_t val)
+{
+       return gxio_mpipe_link_set_attr_aux(link->context, link->mac, attr,
+                                           val);
+}
+
+EXPORT_SYMBOL_GPL(gxio_mpipe_link_set_attr);
index 0fc63c488edf28f923d82fafcbe9bc662b6884f0..92ee4c8a4f7675318c948613429cd51a23ad6da0 100644 (file)
@@ -75,23 +75,6 @@ static inline void copy_to_user_page(struct vm_area_struct *vma,
 #define copy_from_user_page(vma, page, vaddr, dst, src, len) \
        memcpy((dst), (src), (len))
 
-/*
- * Invalidate a VA range; pads to L2 cacheline boundaries.
- *
- * Note that on TILE64, __inv_buffer() actually flushes modified
- * cache lines in addition to invalidating them, i.e., it's the
- * same as __finv_buffer().
- */
-static inline void __inv_buffer(void *buffer, size_t size)
-{
-       char *next = (char *)((long)buffer & -L2_CACHE_BYTES);
-       char *finish = (char *)L2_CACHE_ALIGN((long)buffer + size);
-       while (next < finish) {
-               __insn_inv(next);
-               next += CHIP_INV_STRIDE();
-       }
-}
-
 /* Flush a VA range; pads to L2 cacheline boundaries. */
 static inline void __flush_buffer(void *buffer, size_t size)
 {
@@ -115,13 +98,6 @@ static inline void __finv_buffer(void *buffer, size_t size)
 }
 
 
-/* Invalidate a VA range and wait for it to be complete. */
-static inline void inv_buffer(void *buffer, size_t size)
-{
-       __inv_buffer(buffer, size);
-       mb();
-}
-
 /*
  * Flush a locally-homecached VA range and wait for the evicted
  * cachelines to hit memory.
@@ -142,6 +118,26 @@ static inline void finv_buffer_local(void *buffer, size_t size)
        mb_incoherent();
 }
 
+#ifdef __tilepro__
+/* Invalidate a VA range; pads to L2 cacheline boundaries. */
+static inline void __inv_buffer(void *buffer, size_t size)
+{
+       char *next = (char *)((long)buffer & -L2_CACHE_BYTES);
+       char *finish = (char *)L2_CACHE_ALIGN((long)buffer + size);
+       while (next < finish) {
+               __insn_inv(next);
+               next += CHIP_INV_STRIDE();
+       }
+}
+
+/* Invalidate a VA range and wait for it to be complete. */
+static inline void inv_buffer(void *buffer, size_t size)
+{
+       __inv_buffer(buffer, size);
+       mb();
+}
+#endif
+
 /*
  * Flush and invalidate a VA range that is homed remotely, waiting
  * until the memory controller holds the flushed values.  If "hfh" is
index 276f067e36406e52657f7f0c8f95f9e71cdf28df..1da5bfbd8c61d135edda020c17724de4ab315ebe 100644 (file)
@@ -68,6 +68,12 @@ extern unsigned long __cmpxchg_called_with_bad_pointer(void);
 
 #define tas(ptr) (xchg((ptr), 1))
 
+#define cmpxchg64(ptr, o, n)                                           \
+({                                                                     \
+       BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
+       cmpxchg((ptr), (o), (n));                                       \
+})
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* _ASM_TILE_CMPXCHG_H */
index 7535cf1a30e487a22ee88a4c762d411a507793b6..92b271bd9ebd7cb7527a12385c9f12cf10029d8e 100644 (file)
 #define __HAVE_ARCH_MEMMOVE
 #define __HAVE_ARCH_STRCHR
 #define __HAVE_ARCH_STRLEN
+#define __HAVE_ARCH_STRNLEN
 
 extern __kernel_size_t strlen(const char *);
+extern __kernel_size_t strnlen(const char *, __kernel_size_t);
 extern char *strchr(const char *s, int c);
 extern void *memchr(const void *s, int c, size_t n);
 extern void *memset(void *, int, __kernel_size_t);
index e4d44bd7df271f6b5445f5e7d5e593fe69cc58c7..f68503f8e0aa34b4da170f3b009fffdf5d77e556 100644 (file)
@@ -566,37 +566,6 @@ static inline unsigned long __must_check flush_user(
        return len;
 }
 
-/**
- * inv_user: - Invalidate a block of memory in user space from cache.
- * @mem:   Destination address, in user space.
- * @len:   Number of bytes to invalidate.
- *
- * Returns number of bytes that could not be invalidated.
- * On success, this will be zero.
- *
- * Note that on Tile64, the "inv" operation is in fact a
- * "flush and invalidate", so cache write-backs will occur prior
- * to the cache being marked invalid.
- */
-extern unsigned long inv_user_asm(void __user *mem, unsigned long len);
-static inline unsigned long __must_check __inv_user(
-       void __user *mem, unsigned long len)
-{
-       int retval;
-
-       might_fault();
-       retval = inv_user_asm(mem, len);
-       mb_incoherent();
-       return retval;
-}
-static inline unsigned long __must_check inv_user(
-       void __user *mem, unsigned long len)
-{
-       if (access_ok(VERIFY_WRITE, mem, len))
-               return __inv_user(mem, len);
-       return len;
-}
-
 /**
  * finv_user: - Flush-inval a block of memory in user space from cache.
  * @mem:   Destination address, in user space.
index 9d50fce1b1a7961aa15b6409ecdc587fce0959fa..fdd07f88cfd7124458a4d31fb1a098764e15bb9a 100644 (file)
 #define GXIO_MPIPE_OP_REGISTER_CLIENT_MEMORY IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x1210)
 #define GXIO_MPIPE_OP_LINK_OPEN_AUX    IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1211)
 #define GXIO_MPIPE_OP_LINK_CLOSE_AUX   IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1212)
+#define GXIO_MPIPE_OP_LINK_SET_ATTR_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1213)
 
-#define GXIO_MPIPE_OP_GET_TIMESTAMP_AUX IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x121e)
-#define GXIO_MPIPE_OP_SET_TIMESTAMP_AUX IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x121f)
-#define GXIO_MPIPE_OP_ADJUST_TIMESTAMP_AUX IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x1220)
+#define GXIO_MPIPE_OP_GET_TIMESTAMP_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x121e)
+#define GXIO_MPIPE_OP_SET_TIMESTAMP_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x121f)
+#define GXIO_MPIPE_OP_ADJUST_TIMESTAMP_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1220)
+#define GXIO_MPIPE_OP_CONFIG_EDMA_RING_BLKS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1221)
+#define GXIO_MPIPE_OP_ADJUST_TIMESTAMP_FREQ IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1222)
 #define GXIO_MPIPE_OP_ARM_POLLFD       IORPC_OPCODE(IORPC_FORMAT_KERNEL_POLLFD, 0x9000)
 #define GXIO_MPIPE_OP_CLOSE_POLLFD     IORPC_OPCODE(IORPC_FORMAT_KERNEL_POLLFD, 0x9001)
 #define GXIO_MPIPE_OP_GET_MMIO_BASE    IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8000)
@@ -114,6 +117,8 @@ int gxio_mpipe_link_open_aux(gxio_mpipe_context_t * context,
 
 int gxio_mpipe_link_close_aux(gxio_mpipe_context_t * context, int mac);
 
+int gxio_mpipe_link_set_attr_aux(gxio_mpipe_context_t * context, int mac,
+                                uint32_t attr, int64_t val);
 
 int gxio_mpipe_get_timestamp_aux(gxio_mpipe_context_t * context, uint64_t * sec,
                                 uint64_t * nsec, uint64_t * cycles);
@@ -124,6 +129,9 @@ int gxio_mpipe_set_timestamp_aux(gxio_mpipe_context_t * context, uint64_t sec,
 int gxio_mpipe_adjust_timestamp_aux(gxio_mpipe_context_t * context,
                                    int64_t nsec);
 
+int gxio_mpipe_adjust_timestamp_freq(gxio_mpipe_context_t * context,
+                                    int32_t ppb);
+
 int gxio_mpipe_arm_pollfd(gxio_mpipe_context_t * context, int pollfd_cookie);
 
 int gxio_mpipe_close_pollfd(gxio_mpipe_context_t * context, int pollfd_cookie);
index 0bcf3f71ce8be0150237efde998b1ac8998b9512..476c5e5ca22cfe53714e699b667abf2995a192de 100644 (file)
 #include <asm/pgtable.h>
 
 
+#define GXIO_MPIPE_INFO_OP_INSTANCE_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1250)
 #define GXIO_MPIPE_INFO_OP_ENUMERATE_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1251)
 #define GXIO_MPIPE_INFO_OP_GET_MMIO_BASE IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8000)
 #define GXIO_MPIPE_INFO_OP_CHECK_MMIO_OFFSET IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8001)
 
 
+int gxio_mpipe_info_instance_aux(gxio_mpipe_info_context_t * context,
+                                _gxio_mpipe_link_name_t name);
+
 int gxio_mpipe_info_enumerate_aux(gxio_mpipe_info_context_t * context,
                                  unsigned int idx,
                                  _gxio_mpipe_link_name_t * name,
index b74f470ed11e58c9f8515ee50347db59ff9027e5..e37cf4f0cffd42a14f3d392d9701ef8a4da746f5 100644 (file)
@@ -220,6 +220,13 @@ typedef MPIPE_PDESC_t gxio_mpipe_idesc_t;
  */
 typedef MPIPE_EDMA_DESC_t gxio_mpipe_edesc_t;
 
+/*
+ * Max # of mpipe instances. 2 currently.
+ */
+#define GXIO_MPIPE_INSTANCE_MAX  HV_MPIPE_INSTANCE_MAX
+
+#define NR_MPIPE_MAX   GXIO_MPIPE_INSTANCE_MAX
+
 /* Get the "va" field from an "idesc".
  *
  * This is the address at which the ingress hardware copied the first
@@ -311,6 +318,9 @@ typedef struct {
        /* File descriptor for calling up to Linux (and thus the HV). */
        int fd;
 
+       /* Corresponding mpipe instance #. */
+       int instance;
+
        /* The VA at which configuration registers are mapped. */
        char *mmio_cfg_base;
 
@@ -810,7 +820,7 @@ extern int gxio_mpipe_alloc_edma_rings(gxio_mpipe_context_t *context,
 /* Initialize an eDMA ring, using the given memory and size.
  *
  * @param context An initialized mPIPE context.
- * @param ring The eDMA ring index.
+ * @param ering The eDMA ring index.
  * @param channel The channel to use.  This must be one of the channels
  * associated with the context's set of open links.
  * @param mem A physically contiguous region of memory to be filled
@@ -823,10 +833,37 @@ extern int gxio_mpipe_alloc_edma_rings(gxio_mpipe_context_t *context,
  * ::GXIO_ERR_INVAL_MEMORY_SIZE on failure.
  */
 extern int gxio_mpipe_init_edma_ring(gxio_mpipe_context_t *context,
-                                    unsigned int ring, unsigned int channel,
+                                    unsigned int ering, unsigned int channel,
                                     void *mem, size_t mem_size,
                                     unsigned int mem_flags);
 
+/* Set the "max_blks", "min_snf_blks", and "db" fields of
+ * ::MPIPE_EDMA_RG_INIT_DAT_THRESH_t for a given edma ring.
+ *
+ * The global pool of dynamic blocks will be automatically adjusted.
+ *
+ * This function should not be called after any egress has been done
+ * on the edma ring.
+ *
+ * Most applications should just use gxio_mpipe_equeue_set_snf_size().
+ *
+ * @param context An initialized mPIPE context.
+ * @param ering The eDMA ring index.
+ * @param max_blks The number of blocks to dedicate to the ring
+ * (normally min_snf_blks + 1).  Must be greater than min_snf_blocks.
+ * @param min_snf_blks The number of blocks which must be stored
+ * prior to starting to send the packet (normally 12).
+ * @param db Whether to allow use of dynamic blocks by the ring
+ * (normally 1).
+ *
+ * @return 0 on success, negative on error.
+ */
+extern int gxio_mpipe_config_edma_ring_blks(gxio_mpipe_context_t *context,
+                                           unsigned int ering,
+                                           unsigned int max_blks,
+                                           unsigned int min_snf_blks,
+                                           unsigned int db);
+
 /*****************************************************************
  *                      Classifier Program                        *
  ******************************************************************/
@@ -1288,15 +1325,39 @@ typedef struct {
        /* The log2() of the number of entries. */
        unsigned long log2_num_entries;
 
+       /* The context. */
+       gxio_mpipe_context_t *context;
+
+       /* The ering. */
+       unsigned int ering;
+
+       /* The channel. */
+       unsigned int channel;
+
 } gxio_mpipe_equeue_t;
 
 /* Initialize an "equeue".
  *
- * Takes the equeue plus the same args as gxio_mpipe_init_edma_ring().
+ * This function uses gxio_mpipe_init_edma_ring() to initialize the
+ * underlying edma_ring using the provided arguments.
+ *
+ * @param equeue An egress queue to be initialized.
+ * @param context An initialized mPIPE context.
+ * @param ering The eDMA ring index.
+ * @param channel The channel to use.  This must be one of the channels
+ * associated with the context's set of open links.
+ * @param mem A physically contiguous region of memory to be filled
+ * with a ring of ::gxio_mpipe_edesc_t structures.
+ * @param mem_size Number of bytes in the ring.  Must be 512, 2048,
+ * 8192 or 65536, times 16 (i.e. sizeof(gxio_mpipe_edesc_t)).
+ * @param mem_flags ::gxio_mpipe_mem_flags_e memory flags.
+ *
+ * @return 0 on success, ::GXIO_MPIPE_ERR_BAD_EDMA_RING or
+ * ::GXIO_ERR_INVAL_MEMORY_SIZE on failure.
  */
 extern int gxio_mpipe_equeue_init(gxio_mpipe_equeue_t *equeue,
                                  gxio_mpipe_context_t *context,
-                                 unsigned int edma_ring_id,
+                                 unsigned int ering,
                                  unsigned int channel,
                                  void *mem, unsigned int mem_size,
                                  unsigned int mem_flags);
@@ -1494,6 +1555,37 @@ static inline int gxio_mpipe_equeue_is_complete(gxio_mpipe_equeue_t *equeue,
                                            completion_slot, update);
 }
 
+/* Set the snf (store and forward) size for an equeue.
+ *
+ * The snf size for an equeue defaults to 1536, and encodes the size
+ * of the largest packet for which egress is guaranteed to avoid
+ * transmission underruns and/or corrupt checksums under heavy load.
+ *
+ * The snf size affects a global resource pool which cannot support,
+ * for example, all 24 equeues each requesting an snf size of 8K.
+ *
+ * To ensure that jumbo packets can be egressed properly, the snf size
+ * should be set to the size of the largest possible packet, which
+ * will usually be limited by the size of the app's largest buffer.
+ *
+ * This is a convenience wrapper around
+ * gxio_mpipe_config_edma_ring_blks().
+ *
+ * This function should not be called after any egress has been done
+ * on the equeue.
+ *
+ * @param equeue An egress queue initialized via gxio_mpipe_equeue_init().
+ * @param size The snf size, in bytes.
+ * @return Zero on success, negative error otherwise.
+ */
+static inline int gxio_mpipe_equeue_set_snf_size(gxio_mpipe_equeue_t *equeue,
+                                                size_t size)
+{
+       int blks = (size + 127) / 128;
+       return gxio_mpipe_config_edma_ring_blks(equeue->context, equeue->ering,
+                                               blks + 1, blks, 1);
+}
+
 /*****************************************************************
  *                        Link Management                         *
  ******************************************************************/
@@ -1634,6 +1726,24 @@ typedef struct {
        uint8_t mac;
 } gxio_mpipe_link_t;
 
+/* Translate a link name to the instance number of the mPIPE shim which is
+ *  connected to that link.  This call does not verify whether the link is
+ *  currently available, and does not reserve any link resources;
+ *  gxio_mpipe_link_open() must be called to perform those functions.
+ *
+ *  Typically applications will call this function to translate a link name
+ *  to an mPIPE instance number; call gxio_mpipe_init(), passing it that
+ *  instance number, to initialize the mPIPE shim; and then call
+ *  gxio_mpipe_link_open(), passing it the same link name plus the mPIPE
+ *  context, to configure the link.
+ *
+ * @param link_name Name of the link; see @ref gxio_mpipe_link_names.
+ * @return The mPIPE instance number which is associated with the named
+ *  link, or a negative error code (::GXIO_ERR_NO_DEVICE) if the link does
+ *  not exist.
+ */
+extern int gxio_mpipe_link_instance(const char *link_name);
+
 /* Retrieve one of this system's legal link names, and its MAC address.
  *
  * @param index Link name index.  If a system supports N legal link names,
@@ -1697,6 +1807,17 @@ static inline int gxio_mpipe_link_channel(gxio_mpipe_link_t *link)
        return link->channel;
 }
 
+/* Set a link attribute.
+ *
+ * @param link A properly initialized link state object.
+ * @param attr An attribute from the set of @ref gxio_mpipe_link_attrs.
+ * @param val New value of the attribute.
+ * @return 0 if the attribute was successfully set, or a negative error
+ *  code.
+ */
+extern int gxio_mpipe_link_set_attr(gxio_mpipe_link_t *link, uint32_t attr,
+                                   int64_t val);
+
 ///////////////////////////////////////////////////////////////////
 //                             Timestamp                         //
 ///////////////////////////////////////////////////////////////////
@@ -1733,4 +1854,18 @@ extern int gxio_mpipe_set_timestamp(gxio_mpipe_context_t *context,
 extern int gxio_mpipe_adjust_timestamp(gxio_mpipe_context_t *context,
                                       int64_t delta);
 
+/** Adjust the mPIPE timestamp clock frequency.
+ *
+ * @param context An initialized mPIPE context.
+ * @param ppb A 32-bit signed PPB (Parts Per Billion) value to adjust.
+ * The absolute value of ppb must be less than or equal to 1000000000.
+ * Values less than about 30000 will generally cause a GXIO_ERR_INVAL
+ * return due to the granularity of the hardware that converts reference
+ * clock cycles into seconds and nanoseconds.
+ * @return If the call was successful, zero; otherwise, a negative error
+ *  code.
+ */
+extern int gxio_mpipe_adjust_timestamp_freq(gxio_mpipe_context_t* context,
+                                            int32_t ppb);
+
 #endif /* !_GXIO_MPIPE_H_ */
index 6cdae3bf046efb8e8cfd9e815ef6a2856b848593..c97e416dd963b585c8907097408fa53aebf55bcb 100644 (file)
@@ -23,6 +23,9 @@
 #include <arch/mpipe_constants.h>
 
 
+/** Number of mPIPE instances supported */
+#define HV_MPIPE_INSTANCE_MAX   (2)
+
 /** Number of buffer stacks (32). */
 #define HV_MPIPE_NUM_BUFFER_STACKS \
   (MPIPE_MMIO_INIT_DAT_GX36_1__BUFFER_STACK_MASK_WIDTH)
index af4c9f9154d18d7fee24a78dda9b02d691527846..572ddcad2090643fc68c2eeb13f0e8b1b1504a31 100644 (file)
@@ -29,8 +29,8 @@
  * to honor the arguments at some point.)
  *
  * Flush and invalidation of memory can normally be performed with the
- * __insn_flush(), __insn_inv(), and __insn_finv() instructions from
- * userspace.  The DCACHE option to the system call allows userspace
+ * __insn_flush() and __insn_finv() instructions from userspace.
+ * The DCACHE option to the system call allows userspace
  * to flush the entire L1+L2 data cache from the core.  In this case,
  * the address and length arguments are not used.  The DCACHE flush is
  * restricted to the current core, not all cores in the address space.
index 38ac189d95751a1a7d7a0fe074ad76179037f8a0..7db8893d4fc5319a0870c0bc673c0fa817b68128 100644 (file)
@@ -540,6 +540,14 @@ static struct hardwall_info *hardwall_create(struct hardwall_type *hwt,
                }
        }
 
+       /*
+        * Eliminate cpus that are not part of this Linux client.
+        * Note that this allows for configurations that we might not want to
+        * support, such as one client on every even cpu, another client on
+        * every odd cpu.
+        */
+       cpumask_and(&info->cpumask, &info->cpumask, cpu_online_mask);
+
        /* Confirm it doesn't overlap and add it to the list. */
        spin_lock_irqsave(&hwt->lock, flags);
        list_for_each_entry(iter, &hwt->list, list) {
@@ -612,7 +620,7 @@ static int hardwall_activate(struct hardwall_info *info)
 
 /*
  * Deactivate a task's hardwall.  Must hold lock for hardwall_type.
- * This method may be called from free_task(), so we don't want to
+ * This method may be called from exit_thread(), so we don't want to
  * rely on too many fields of struct task_struct still being valid.
  * We assume the cpus_allowed, pid, and comm fields are still valid.
  */
index ac115307e5e4e3189d7e89b3c644ecd65c10c384..80cd407925cdc1404f335bc2f047915b522ec0b1 100644 (file)
@@ -64,7 +64,7 @@ ENTRY(_start)
          auli r0, r0, ha16(swapper_pg_dir - PAGE_OFFSET)
        }
        {
-         inv r6
+         finv r6
          move r1, zero   /* high 32 bits of CPA is zero */
        }
        {
index 6093964fa5c72a891c16d59e5c8d855cceb2ccb2..e23e5f7b91d9a997c502853d93e7c340fa8fec84 100644 (file)
@@ -77,7 +77,7 @@ ENTRY(_start)
        {
          /* After initializing swapper_pgprot, HV_PTE_GLOBAL is set. */
          bfextu r7, r1, HV_PTE_INDEX_GLOBAL, HV_PTE_INDEX_GLOBAL
-         inv r4
+         finv r4
        }
        bnez r7, .Lno_write
        {
index 8ac304484f988a685118d4d4475b48cee1156060..8d6c51d557625db078e3328c8c2d8e31375932cc 100644 (file)
@@ -74,19 +74,6 @@ void arch_release_thread_info(struct thread_info *info)
 {
        struct single_step_state *step_state = info->step_state;
 
-#ifdef CONFIG_HARDWALL
-       /*
-        * We free a thread_info from the context of the task that has
-        * been scheduled next, so the original task is already dead.
-        * Calling deactivate here just frees up the data structures.
-        * If the task we're freeing held the last reference to a
-        * hardwall fd, it would have been released prior to this point
-        * anyway via exit_files(), and the hardwall_task.info pointers
-        * would be NULL by now.
-        */
-       hardwall_deactivate_all(info->task);
-#endif
-
        if (step_state) {
 
                /*
@@ -564,7 +551,15 @@ void flush_thread(void)
  */
 void exit_thread(void)
 {
-       /* Nothing */
+#ifdef CONFIG_HARDWALL
+       /*
+        * Remove the task from the list of tasks that are associated
+        * with any live hardwalls.  (If the task that is exiting held
+        * the last reference to a hardwall fd, it would already have
+        * been released and deactivated at this point.)
+        */
+       hardwall_deactivate_all(current);
+#endif
 }
 
 void show_regs(struct pt_regs *regs)
index 985f59858234d98cf7a29df45d91edc0e6deb973..5d844374b2b18e6aab7d55ac6738ab08781d1c8c 100644 (file)
@@ -4,7 +4,7 @@
 
 lib-y = cacheflush.o checksum.o cpumask.o delay.o uaccess.o \
        memmove.o memcpy_$(BITS).o memchr_$(BITS).o memset_$(BITS).o \
-       strchr_$(BITS).o strlen_$(BITS).o
+       strchr_$(BITS).o strlen_$(BITS).o strnlen_$(BITS).o
 
 ifeq ($(CONFIG_TILEGX),y)
 CFLAGS_REMOVE_memcpy_user_64.o = -fno-omit-frame-pointer
index 8f8ad814b1398619314b5a26d62695279d4f63f1..2238b40abf3c9c233938270616c2bb953a035ae4 100644 (file)
@@ -147,18 +147,21 @@ void finv_buffer_remote(void *buffer, size_t size, int hfh)
                force_load(p);
 
        /*
-        * Repeat, but with inv's instead of loads, to get rid of the
+        * Repeat, but with finv's instead of loads, to get rid of the
         * data we just loaded into our own cache and the old home L3.
-        * No need to unroll since inv's don't target a register.
+        * No need to unroll since finv's don't target a register.
+        * The finv's are guaranteed not to actually flush the data in
+        * the buffer back to their home, since we just read it, so the
+        * lines are clean in cache; we will only invalidate those lines.
         */
        p = (char *)buffer + size - 1;
-       __insn_inv(p);
+       __insn_finv(p);
        p -= step_size;
        p = (char *)((unsigned long)p | (step_size - 1));
        for (; p >= base; p -= step_size)
-               __insn_inv(p);
+               __insn_finv(p);
 
-       /* Wait for the load+inv's (and thus finvs) to have completed. */
+       /* Wait for these finv's (and thus the first finvs) to be done. */
        __insn_mf();
 
 #ifdef __tilegx__
index a93b02a252227c3b8bd40929e663e79f3f757862..359b1bc52d8423f3352d70d64359b58a1413c4d3 100644 (file)
@@ -22,7 +22,6 @@ EXPORT_SYMBOL(strnlen_user_asm);
 EXPORT_SYMBOL(strncpy_from_user_asm);
 EXPORT_SYMBOL(clear_user_asm);
 EXPORT_SYMBOL(flush_user_asm);
-EXPORT_SYMBOL(inv_user_asm);
 EXPORT_SYMBOL(finv_user_asm);
 
 /* arch/tile/kernel/entry.S */
index 6f867dbf7c56df79a25ebcc091dfb9b5fa5321b7..f8196b3a950ef4f6fc8b97e615b7d4cd1e352e55 100644 (file)
@@ -36,7 +36,7 @@ void *memchr(const void *s, int c, size_t n)
        p = (const uint64_t *)(s_int & -8);
 
        /* Create eight copies of the byte for which we are looking. */
-       goal = 0x0101010101010101ULL * (uint8_t) c;
+       goal = copy_byte(c);
 
        /* Read the first word, but munge it so that bytes before the array
         * will not match goal.
index c79b8e7c6828bd384e0c354dccf72553ef1c9536..46fc1600c17d158263819e612ff0a1ff2ee61741 100644 (file)
 /* EXPORT_SYMBOL() is in arch/tile/lib/exports.c since this should be asm. */
 
 /* Must be 8 bytes in size. */
-#define word_t uint64_t
+#define op_t uint64_t
 
-#if CHIP_L2_LINE_SIZE() != 64 && CHIP_L2_LINE_SIZE() != 128
-#error "Assumes 64 or 128 byte line size"
+/* Threshold value for when to enter the unrolled loops. */
+#define        OP_T_THRES      16
+
+#if CHIP_L2_LINE_SIZE() != 64
+#error "Assumes 64 byte line size"
 #endif
 
 /* How many cache lines ahead should we prefetch? */
-#define PREFETCH_LINES_AHEAD 3
+#define PREFETCH_LINES_AHEAD 4
 
 /*
  * Provide "base versions" of load and store for the normal code path.
@@ -58,8 +61,8 @@ int USERCOPY_FUNC(void *__restrict dstv, const void *__restrict srcv, size_t n)
        const char *__restrict src1 = (const char *)srcv;
        const char *__restrict src1_end;
        const char *__restrict prefetch;
-       word_t *__restrict dst8;    /* 8-byte pointer to destination memory. */
-       word_t final; /* Final bytes to write to trailing word, if any */
+       op_t *__restrict dst8;    /* 8-byte pointer to destination memory. */
+       op_t final; /* Final bytes to write to trailing word, if any */
        long i;
 
        if (n < 16) {
@@ -79,104 +82,228 @@ int USERCOPY_FUNC(void *__restrict dstv, const void *__restrict srcv, size_t n)
        for (i = 0; i < PREFETCH_LINES_AHEAD; i++) {
                __insn_prefetch(prefetch);
                prefetch += CHIP_L2_LINE_SIZE();
-               prefetch = (prefetch > src1_end) ? prefetch : src1;
+               prefetch = (prefetch < src1_end) ? prefetch : src1;
        }
 
        /* Copy bytes until dst is word-aligned. */
-       for (; (uintptr_t)dst1 & (sizeof(word_t) - 1); n--)
+       for (; (uintptr_t)dst1 & (sizeof(op_t) - 1); n--)
                ST1(dst1++, LD1(src1++));
 
        /* 8-byte pointer to destination memory. */
-       dst8 = (word_t *)dst1;
-
-       if (__builtin_expect((uintptr_t)src1 & (sizeof(word_t) - 1), 0)) {
-               /*
-                * Misaligned copy.  Copy 8 bytes at a time, but don't
-                * bother with other fanciness.
-                *
-                * TODO: Consider prefetching and using wh64 as well.
-                */
-
-               /* Create an aligned src8. */
-               const word_t *__restrict src8 =
-                       (const word_t *)((uintptr_t)src1 & -sizeof(word_t));
-               word_t b;
-
-               word_t a = LD8(src8++);
-               for (; n >= sizeof(word_t); n -= sizeof(word_t)) {
-                       b = LD8(src8++);
-                       a = __insn_dblalign(a, b, src1);
-                       ST8(dst8++, a);
-                       a = b;
+       dst8 = (op_t *)dst1;
+
+       if (__builtin_expect((uintptr_t)src1 & (sizeof(op_t) - 1), 0)) {
+               /* Unaligned copy. */
+
+               op_t  tmp0 = 0, tmp1 = 0, tmp2, tmp3;
+               const op_t *src8 = (const op_t *) ((uintptr_t)src1 &
+                                                  -sizeof(op_t));
+               const void *srci = (void *)src1;
+               int m;
+
+               m = (CHIP_L2_LINE_SIZE() << 2) -
+                       (((uintptr_t)dst8) & ((CHIP_L2_LINE_SIZE() << 2) - 1));
+               m = (n < m) ? n : m;
+               m /= sizeof(op_t);
+
+               /* Copy until 'dst' is cache-line-aligned. */
+               n -= (sizeof(op_t) * m);
+
+               switch (m % 4) {
+               case 0:
+                       if (__builtin_expect(!m, 0))
+                               goto _M0;
+                       tmp1 = LD8(src8++);
+                       tmp2 = LD8(src8++);
+                       goto _8B3;
+               case 2:
+                       m += 2;
+                       tmp3 = LD8(src8++);
+                       tmp0 = LD8(src8++);
+                       goto _8B1;
+               case 3:
+                       m += 1;
+                       tmp2 = LD8(src8++);
+                       tmp3 = LD8(src8++);
+                       goto _8B2;
+               case 1:
+                       m--;
+                       tmp0 = LD8(src8++);
+                       tmp1 = LD8(src8++);
+                       if (__builtin_expect(!m, 0))
+                               goto _8B0;
+               }
+
+               do {
+                       tmp2 = LD8(src8++);
+                       tmp0 =  __insn_dblalign(tmp0, tmp1, srci);
+                       ST8(dst8++, tmp0);
+_8B3:
+                       tmp3 = LD8(src8++);
+                       tmp1 = __insn_dblalign(tmp1, tmp2, srci);
+                       ST8(dst8++, tmp1);
+_8B2:
+                       tmp0 = LD8(src8++);
+                       tmp2 = __insn_dblalign(tmp2, tmp3, srci);
+                       ST8(dst8++, tmp2);
+_8B1:
+                       tmp1 = LD8(src8++);
+                       tmp3 = __insn_dblalign(tmp3, tmp0, srci);
+                       ST8(dst8++, tmp3);
+                       m -= 4;
+               } while (m);
+
+_8B0:
+               tmp0 = __insn_dblalign(tmp0, tmp1, srci);
+               ST8(dst8++, tmp0);
+               src8--;
+
+_M0:
+               if (__builtin_expect(n >= CHIP_L2_LINE_SIZE(), 0)) {
+                       op_t tmp4, tmp5, tmp6, tmp7, tmp8;
+
+                       prefetch = ((const char *)src8) +
+                               CHIP_L2_LINE_SIZE() * PREFETCH_LINES_AHEAD;
+
+                       for (tmp0 = LD8(src8++); n >= CHIP_L2_LINE_SIZE();
+                            n -= CHIP_L2_LINE_SIZE()) {
+                               /* Prefetch and advance to next line to
+                                  prefetch, but don't go past the end.  */
+                               __insn_prefetch(prefetch);
+
+                               /* Make sure prefetch got scheduled
+                                  earlier.  */
+                               __asm__ ("" : : : "memory");
+
+                               prefetch += CHIP_L2_LINE_SIZE();
+                               prefetch = (prefetch < src1_end) ? prefetch :
+                                       (const char *) src8;
+
+                               tmp1 = LD8(src8++);
+                               tmp2 = LD8(src8++);
+                               tmp3 = LD8(src8++);
+                               tmp4 = LD8(src8++);
+                               tmp5 = LD8(src8++);
+                               tmp6 = LD8(src8++);
+                               tmp7 = LD8(src8++);
+                               tmp8 = LD8(src8++);
+
+                               tmp0 = __insn_dblalign(tmp0, tmp1, srci);
+                               tmp1 = __insn_dblalign(tmp1, tmp2, srci);
+                               tmp2 = __insn_dblalign(tmp2, tmp3, srci);
+                               tmp3 = __insn_dblalign(tmp3, tmp4, srci);
+                               tmp4 = __insn_dblalign(tmp4, tmp5, srci);
+                               tmp5 = __insn_dblalign(tmp5, tmp6, srci);
+                               tmp6 = __insn_dblalign(tmp6, tmp7, srci);
+                               tmp7 = __insn_dblalign(tmp7, tmp8, srci);
+
+                               __insn_wh64(dst8);
+
+                               ST8(dst8++, tmp0);
+                               ST8(dst8++, tmp1);
+                               ST8(dst8++, tmp2);
+                               ST8(dst8++, tmp3);
+                               ST8(dst8++, tmp4);
+                               ST8(dst8++, tmp5);
+                               ST8(dst8++, tmp6);
+                               ST8(dst8++, tmp7);
+
+                               tmp0 = tmp8;
+                       }
+                       src8--;
+               }
+
+               /* Copy the rest 8-byte chunks. */
+               if (n >= sizeof(op_t)) {
+                       tmp0 = LD8(src8++);
+                       for (; n >= sizeof(op_t); n -= sizeof(op_t)) {
+                               tmp1 = LD8(src8++);
+                               tmp0 = __insn_dblalign(tmp0, tmp1, srci);
+                               ST8(dst8++, tmp0);
+                               tmp0 = tmp1;
+                       }
+                       src8--;
                }
 
                if (n == 0)
                        return RETVAL;
 
-               b = ((const char *)src8 <= src1_end) ? *src8 : 0;
+               tmp0 = LD8(src8++);
+               tmp1 = ((const char *)src8 <= src1_end)
+                       ? LD8((op_t *)src8) : 0;
+               final = __insn_dblalign(tmp0, tmp1, srci);
 
-               /*
-                * Final source bytes to write to trailing partial
-                * word, if any.
-                */
-               final = __insn_dblalign(a, b, src1);
        } else {
                /* Aligned copy. */
 
-               const word_t* __restrict src8 = (const word_t *)src1;
+               const op_t *__restrict src8 = (const op_t *)src1;
 
                /* src8 and dst8 are both word-aligned. */
                if (n >= CHIP_L2_LINE_SIZE()) {
                        /* Copy until 'dst' is cache-line-aligned. */
                        for (; (uintptr_t)dst8 & (CHIP_L2_LINE_SIZE() - 1);
-                            n -= sizeof(word_t))
+                            n -= sizeof(op_t))
                                ST8(dst8++, LD8(src8++));
 
                        for (; n >= CHIP_L2_LINE_SIZE(); ) {
-                               __insn_wh64(dst8);
+                               op_t tmp0, tmp1, tmp2, tmp3;
+                               op_t tmp4, tmp5, tmp6, tmp7;
 
                                /*
                                 * Prefetch and advance to next line
-                                * to prefetch, but don't go past the end
+                                * to prefetch, but don't go past the
+                                * end.
                                 */
                                __insn_prefetch(prefetch);
+
+                               /* Make sure prefetch got scheduled
+                                  earlier.  */
+                               __asm__ ("" : : : "memory");
+
                                prefetch += CHIP_L2_LINE_SIZE();
-                               prefetch = (prefetch > src1_end) ? prefetch :
+                               prefetch = (prefetch < src1_end) ? prefetch :
                                        (const char *)src8;
 
                                /*
-                                * Copy an entire cache line.  Manually
-                                * unrolled to avoid idiosyncracies of
-                                * compiler unrolling.
+                                * Do all the loads before wh64.  This
+                                * is necessary if [src8, src8+7] and
+                                * [dst8, dst8+7] share the same cache
+                                * line and dst8 <= src8, as can be
+                                * the case when called from memmove,
+                                * or with code tested on x86 whose
+                                * memcpy always works with forward
+                                * copies.
                                 */
-#define COPY_WORD(offset) ({ ST8(dst8+offset, LD8(src8+offset)); n -= 8; })
-                               COPY_WORD(0);
-                               COPY_WORD(1);
-                               COPY_WORD(2);
-                               COPY_WORD(3);
-                               COPY_WORD(4);
-                               COPY_WORD(5);
-                               COPY_WORD(6);
-                               COPY_WORD(7);
-#if CHIP_L2_LINE_SIZE() == 128
-                               COPY_WORD(8);
-                               COPY_WORD(9);
-                               COPY_WORD(10);
-                               COPY_WORD(11);
-                               COPY_WORD(12);
-                               COPY_WORD(13);
-                               COPY_WORD(14);
-                               COPY_WORD(15);
-#elif CHIP_L2_LINE_SIZE() != 64
-# error Fix code that assumes particular L2 cache line sizes
-#endif
+                               tmp0 = LD8(src8++);
+                               tmp1 = LD8(src8++);
+                               tmp2 = LD8(src8++);
+                               tmp3 = LD8(src8++);
+                               tmp4 = LD8(src8++);
+                               tmp5 = LD8(src8++);
+                               tmp6 = LD8(src8++);
+                               tmp7 = LD8(src8++);
+
+                               /* wh64 and wait for tmp7 load completion. */
+                               __asm__ ("move %0, %0; wh64 %1\n"
+                                        : : "r"(tmp7), "r"(dst8));
 
-                               dst8 += CHIP_L2_LINE_SIZE() / sizeof(word_t);
-                               src8 += CHIP_L2_LINE_SIZE() / sizeof(word_t);
+                               ST8(dst8++, tmp0);
+                               ST8(dst8++, tmp1);
+                               ST8(dst8++, tmp2);
+                               ST8(dst8++, tmp3);
+                               ST8(dst8++, tmp4);
+                               ST8(dst8++, tmp5);
+                               ST8(dst8++, tmp6);
+                               ST8(dst8++, tmp7);
+
+                               n -= CHIP_L2_LINE_SIZE();
                        }
+#if CHIP_L2_LINE_SIZE() != 64
+# error "Fix code that assumes particular L2 cache line size."
+#endif
                }
 
-               for (; n >= sizeof(word_t); n -= sizeof(word_t))
+               for (; n >= sizeof(op_t); n -= sizeof(op_t))
                        ST8(dst8++, LD8(src8++));
 
                if (__builtin_expect(n == 0, 1))
index 57dbb3a5bff86a59e71054100c4ac1c885402a7b..9a7837d11f7d8fd7a250a79b05e8c9fc379d9098 100644 (file)
  *   more details.
  */
 
-#include <arch/chip.h>
-
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/module.h>
-
-#undef memset
+#include <arch/chip.h>
 
 void *memset(void *s, int c, size_t n)
 {
index 3873085711d58fce89b714ed20dd1a090ceaf486..03ef69cd73decac97b4e6e8c584c800ca0fc58e7 100644 (file)
  *   more details.
  */
 
-#include <arch/chip.h>
-
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/module.h>
-
-#undef memset
+#include <arch/chip.h>
+#include "string-endian.h"
 
 void *memset(void *s, int c, size_t n)
 {
@@ -70,8 +68,7 @@ void *memset(void *s, int c, size_t n)
        n64 = n >> 3;
 
        /* Tile input byte out to 64 bits. */
-       /* KLUDGE */
-       v64 = 0x0101010101010101ULL * (uint8_t)c;
+       v64 = copy_byte(c);
 
        /* This must be at least 8 or the following loop doesn't work. */
 #define CACHE_LINE_SIZE_IN_DOUBLEWORDS (CHIP_L2_LINE_SIZE() / 8)
index c94e6f7ae7b53d2eabe658c3945c9f19bd2e9814..841fe69630190503a3135e65b6e637447242207d 100644 (file)
@@ -16,8 +16,6 @@
 #include <linux/string.h>
 #include <linux/module.h>
 
-#undef strchr
-
 char *strchr(const char *s, int c)
 {
        int z, g;
index f39f9dc422b02e44853ff54e14a0dc3cdd277380..fe6e31c06f8deb1bc2d96ddc8f17bdb070105720 100644 (file)
@@ -26,7 +26,7 @@ char *strchr(const char *s, int c)
        const uint64_t *p = (const uint64_t *)(s_int & -8);
 
        /* Create eight copies of the byte for which we are looking. */
-       const uint64_t goal = 0x0101010101010101ULL * (uint8_t) c;
+       const uint64_t goal = copy_byte(c);
 
        /* Read the first aligned word, but force bytes before the string to
         * match neither zero nor goal (we make sure the high bit of each
index c0eed7ce69c31b03c1574c37ffb60d95ea78f463..2e49cbfe937173637ec713eb1ad60e12f74b3896 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ * Copyright 2013 Tilera Corporation. All Rights Reserved.
  *
  *   This program is free software; you can redistribute it and/or
  *   modify it under the terms of the GNU General Public License
 #define CFZ(x) __insn_clz(x)
 #define REVCZ(x) __insn_ctz(x)
 #endif
+
+/*
+ * Create eight copies of the byte in a uint64_t.  Byte Shuffle uses
+ * the bytes of srcB as the index into the dest vector to select a
+ * byte.  With all indices of zero, the first byte is copied into all
+ * the other bytes.
+ */
+static inline uint64_t copy_byte(uint8_t byte)
+{
+       return __insn_shufflebytes(byte, 0, 0);
+}
index 4974292a553498bc789dae5e4e938e95e311051c..f26f88e11e4a8d9885ba10eec773b4181a5739a8 100644 (file)
@@ -16,8 +16,6 @@
 #include <linux/string.h>
 #include <linux/module.h>
 
-#undef strlen
-
 size_t strlen(const char *s)
 {
        /* Get an aligned pointer. */
diff --git a/arch/tile/lib/strnlen_32.c b/arch/tile/lib/strnlen_32.c
new file mode 100644 (file)
index 0000000..4490cf9
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2013 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   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, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/module.h>
+
+size_t strnlen(const char *s, size_t count)
+{
+       /* Get an aligned pointer. */
+       const uintptr_t s_int = (uintptr_t) s;
+       const uint32_t *p = (const uint32_t *)(s_int & -4);
+       size_t bytes_read = sizeof(*p) - (s_int & (sizeof(*p) - 1));
+       size_t len;
+       uint32_t v, bits;
+
+       /* Avoid page fault risk by not reading any bytes when count is 0. */
+       if (count == 0)
+               return 0;
+
+       /* Read the first word, but force bytes before the string to be nonzero.
+        * This expression works because we know shift counts are taken mod 32.
+        */
+       v = *p | ((1 << (s_int << 3)) - 1);
+
+       while ((bits = __insn_seqb(v, 0)) == 0) {
+               if (bytes_read >= count) {
+                       /* Read COUNT bytes and didn't find the terminator. */
+                       return count;
+               }
+               v = *++p;
+               bytes_read += sizeof(v);
+       }
+
+       len = ((const char *) p) + (__insn_ctz(bits) >> 3) - s;
+       return (len < count ? len : count);
+}
+EXPORT_SYMBOL(strnlen);
diff --git a/arch/tile/lib/strnlen_64.c b/arch/tile/lib/strnlen_64.c
new file mode 100644 (file)
index 0000000..2e8de6a
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2013 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   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, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#include "string-endian.h"
+
+size_t strnlen(const char *s, size_t count)
+{
+       /* Get an aligned pointer. */
+       const uintptr_t s_int = (uintptr_t) s;
+       const uint64_t *p = (const uint64_t *)(s_int & -8);
+       size_t bytes_read = sizeof(*p) - (s_int & (sizeof(*p) - 1));
+       size_t len;
+       uint64_t v, bits;
+
+       /* Avoid page fault risk by not reading any bytes when count is 0. */
+       if (count == 0)
+               return 0;
+
+       /* Read and MASK the first word. */
+       v = *p | MASK(s_int);
+
+       while ((bits = __insn_v1cmpeqi(v, 0)) == 0) {
+               if (bytes_read >= count) {
+                       /* Read COUNT bytes and didn't find the terminator. */
+                       return count;
+               }
+               v = *++p;
+               bytes_read += sizeof(v);
+       }
+
+       len = ((const char *) p) + (CFZ(bits) >> 3) - s;
+       return (len < count ? len : count);
+}
+EXPORT_SYMBOL(strnlen);
index b62d002af0096fe89793f5fb4eba6c357ef55922..21ffa88ffe5fc7ad6b14d73edb8b103d560b8d3d 100644 (file)
@@ -108,25 +108,6 @@ STD_ENTRY(flush_user_asm)
        .word 1b, 2b
        .popsection
 
-/*
- * inv_user_asm takes the user target address in r0 and the
- * number of bytes to invalidate in r1.
- * It returns the number of not inv'able bytes (hopefully zero) in r0.
- */
-STD_ENTRY(inv_user_asm)
-       bz r1, 2f
-       { movei r2, L2_CACHE_BYTES; add r1, r0, r1 }
-       { sub r2, zero, r2; addi r1, r1, L2_CACHE_BYTES-1 }
-       { and r0, r0, r2; and r1, r1, r2 }
-       { sub r1, r1, r0 }
-1:      { inv r0; addi r1, r1, -CHIP_INV_STRIDE() }
-       { addi r0, r0, CHIP_INV_STRIDE(); bnzt r1, 1b }
-2:      { move r0, r1; jrp lr }
-       STD_ENDPROC(inv_user_asm)
-       .pushsection __ex_table,"a"
-       .word 1b, 2b
-       .popsection
-
 /*
  * finv_user_asm takes the user target address in r0 and the
  * number of bytes to flush-invalidate in r1.
index adb2dbbc70cd037d5d30b0d5c448da17470db3ef..f248d3196e5c1ed496838ce48b446777e1c66430 100644 (file)
@@ -108,25 +108,6 @@ STD_ENTRY(flush_user_asm)
        .quad 1b, 2b
        .popsection
 
-/*
- * inv_user_asm takes the user target address in r0 and the
- * number of bytes to invalidate in r1.
- * It returns the number of not inv'able bytes (hopefully zero) in r0.
- */
-STD_ENTRY(inv_user_asm)
-       beqz r1, 2f
-       { movei r2, L2_CACHE_BYTES; add r1, r0, r1 }
-       { sub r2, zero, r2; addi r1, r1, L2_CACHE_BYTES-1 }
-       { and r0, r0, r2; and r1, r1, r2 }
-       { sub r1, r1, r0 }
-1:      { inv r0; addi r1, r1, -CHIP_INV_STRIDE() }
-       { addi r0, r0, CHIP_INV_STRIDE(); bnezt r1, 1b }
-2:      { move r0, r1; jrp lr }
-       STD_ENDPROC(inv_user_asm)
-       .pushsection __ex_table,"a"
-       .quad 1b, 2b
-       .popsection
-
 /*
  * finv_user_asm takes the user target address in r0 and the
  * number of bytes to flush-invalidate in r1.
index bae3aba95b15ab298562afe1b657d63b706578e0..b987cd54fa46a6505f3e44af3f8543870855db0f 100644 (file)
@@ -130,14 +130,6 @@ static void set_brk(unsigned long start, unsigned long end)
 
 #include <linux/coredump.h>
 
-#define DUMP_WRITE(addr, nr)                        \
-       if (!dump_write(file, (void *)(addr), (nr))) \
-               goto end_coredump;
-
-#define DUMP_SEEK(offset)              \
-       if (!dump_seek(file, offset))   \
-               goto end_coredump;
-
 #define START_DATA()   (u.u_tsize << PAGE_SHIFT)
 #define START_STACK(u) (u.start_stack)
 
@@ -190,22 +182,26 @@ static int aout_core_dump(long signr, struct pt_regs *regs, struct file *file,
 
        set_fs(KERNEL_DS);
        /* struct user */
-       DUMP_WRITE(&dump, sizeof(dump));
+       if (!dump_emit(cprm, &dump, sizeof(dump)))
+               goto end_coredump;
        /* Now dump all of the user data.  Include malloced stuff as well */
-       DUMP_SEEK(PAGE_SIZE - sizeof(dump));
+       if (!dump_align(cprm, PAGE_SIZE))
+               goto end_coredump;
        /* now we start writing out the user space info */
        set_fs(USER_DS);
        /* Dump the data area */
        if (dump.u_dsize != 0) {
                dump_start = START_DATA(dump);
                dump_size = dump.u_dsize << PAGE_SHIFT;
-               DUMP_WRITE(dump_start, dump_size);
+               if (!dump_emit(cprm, dump_start, dump_size))
+                       goto end_coredump;
        }
        /* Now prepare to dump the stack area */
        if (dump.u_ssize != 0) {
                dump_start = START_STACK(dump);
                dump_size = dump.u_ssize << PAGE_SHIFT;
-               DUMP_WRITE(dump_start, dump_size);
+               if (!dump_emit(cprm, dump_start, dump_size))
+                       goto end_coredump;
        }
 end_coredump:
        set_fs(fs);
index 24cf5aefb7048b496082fd271755e3b186e23540..4f4a3d98c170477caff77d71693f203ae9a6fb34 100644 (file)
@@ -942,35 +942,6 @@ extern int set_tsc_mode(unsigned int val);
 
 extern u16 amd_get_nb_id(int cpu);
 
-struct aperfmperf {
-       u64 aperf, mperf;
-};
-
-static inline void get_aperfmperf(struct aperfmperf *am)
-{
-       WARN_ON_ONCE(!boot_cpu_has(X86_FEATURE_APERFMPERF));
-
-       rdmsrl(MSR_IA32_APERF, am->aperf);
-       rdmsrl(MSR_IA32_MPERF, am->mperf);
-}
-
-#define APERFMPERF_SHIFT 10
-
-static inline
-unsigned long calc_aperfmperf_ratio(struct aperfmperf *old,
-                                   struct aperfmperf *new)
-{
-       u64 aperf = new->aperf - old->aperf;
-       u64 mperf = new->mperf - old->mperf;
-       unsigned long ratio = aperf;
-
-       mperf >>= APERFMPERF_SHIFT;
-       if (mperf)
-               ratio = div64_u64(aperf, mperf);
-
-       return ratio;
-}
-
 extern unsigned long arch_align_stack(unsigned long sp);
 extern void free_init_pages(char *what, unsigned long begin, unsigned long end);
 
index addf7b58f4e839f171cb8d3b68594e6a36e77344..91a4496db43429de294e481075782295b76ff0e6 100644 (file)
@@ -301,6 +301,15 @@ static int tboot_sleep(u8 sleep_state, u32 pm1a_control, u32 pm1b_control)
        return 0;
 }
 
+static int tboot_extended_sleep(u8 sleep_state, u32 val_a, u32 val_b)
+{
+       if (!tboot_enabled())
+               return 0;
+
+       pr_warning("tboot is not able to suspend on platforms with reduced hardware sleep (ACPIv5)");
+       return -ENODEV;
+}
+
 static atomic_t ap_wfs_count;
 
 static int tboot_wait_for_aps(int num_aps)
@@ -422,6 +431,7 @@ static __init int tboot_late_init(void)
 #endif
 
        acpi_os_set_prepare_sleep(&tboot_sleep);
+       acpi_os_set_prepare_extended_sleep(&tboot_extended_sleep);
        return 0;
 }
 
index 6a22c19da6633601c73c1136964950d61f1c855b..7c1fde50ecb0f4efcc6d512d5074977921384592 100644 (file)
@@ -7,8 +7,7 @@
  * kernel and insert a module (lg.ko) which allows us to run other Linux
  * kernels the same way we'd run processes.  We call the first kernel the Host,
  * and the others the Guests.  The program which sets up and configures Guests
- * (such as the example in Documentation/virtual/lguest/lguest.c) is called the
- * Launcher.
+ * (such as the example in tools/lguest/lguest.c) is called the Launcher.
  *
  * Secondly, we only run specially modified Guests, not normal kernels: setting
  * CONFIG_LGUEST_GUEST to "y" compiles this file into the kernel so it knows
index 94919e307f8e97c52d4cd69cee64cf7b0eb68584..db6b1ab43255f0179ae6d539197828ce6834c96f 100644 (file)
@@ -210,6 +210,8 @@ static void pcibios_allocate_bridge_resources(struct pci_dev *dev)
                r = &dev->resource[idx];
                if (!r->flags)
                        continue;
+               if (r->parent)  /* Already allocated */
+                       continue;
                if (!r->start || pci_claim_resource(dev, idx) < 0) {
                        /*
                         * Something is wrong with the region.
@@ -318,6 +320,8 @@ static void pcibios_allocate_dev_rom_resource(struct pci_dev *dev)
        r = &dev->resource[PCI_ROM_RESOURCE];
        if (!r->flags || !r->start)
                return;
+       if (r->parent) /* Already allocated */
+               return;
 
        if (pci_claim_resource(dev, PCI_ROM_RESOURCE) < 0) {
                r->end -= r->start;
index 082e88129712b4eb9e2027852c890a02ff31a1c7..5596c7bdd327b1af38138a3d32be36be3e21cb17 100644 (file)
@@ -700,7 +700,7 @@ int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
        if (!(pci_probe & PCI_PROBE_MMCONF) || pci_mmcfg_arch_init_failed)
                return -ENODEV;
 
-       if (start > end)
+       if (start > end || !addr)
                return -EINVAL;
 
        mutex_lock(&pci_mmcfg_lock);
@@ -716,11 +716,6 @@ int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
                return -EEXIST;
        }
 
-       if (!addr) {
-               mutex_unlock(&pci_mmcfg_lock);
-               return -EINVAL;
-       }
-
        rc = -EBUSY;
        cfg = pci_mmconfig_alloc(seg, start, end, addr);
        if (cfg == NULL) {
index 6eb18c42a28a3584546e87a57f9cccf5af3473e3..903fded507869b45cc7b304e9b9bb0169db7b00a 100644 (file)
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/dmi.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+#include <linux/smp.h>
 
-#include <asm/acpi.h>
 #include <asm/segment.h>
-#include <asm/io.h>
-#include <asm/smp.h>
 #include <asm/pci_x86.h>
 #include <asm/hw_irq.h>
 #include <asm/io_apic.h>
@@ -43,7 +43,7 @@
 #define PCI_FIXED_BAR_4_SIZE   0x14
 #define PCI_FIXED_BAR_5_SIZE   0x1c
 
-static int pci_soc_mode = 0;
+static int pci_soc_mode;
 
 /**
  * fixed_bar_cap - return the offset of the fixed BAR cap if found
@@ -141,7 +141,8 @@ static int pci_device_update_fixed(struct pci_bus *bus, unsigned int devfn,
  */
 static bool type1_access_ok(unsigned int bus, unsigned int devfn, int reg)
 {
-       /* This is a workaround for A0 LNC bug where PCI status register does
+       /*
+        * This is a workaround for A0 LNC bug where PCI status register does
         * not have new CAP bit set. can not be written by SW either.
         *
         * PCI header type in real LNC indicates a single function device, this
@@ -154,7 +155,7 @@ static bool type1_access_ok(unsigned int bus, unsigned int devfn, int reg)
                                || devfn == PCI_DEVFN(0, 0)
                                || devfn == PCI_DEVFN(3, 0)))
                return 1;
-       return 0; /* langwell on others */
+       return 0; /* Langwell on others */
 }
 
 static int pci_read(struct pci_bus *bus, unsigned int devfn, int where,
@@ -172,7 +173,8 @@ static int pci_write(struct pci_bus *bus, unsigned int devfn, int where,
 {
        int offset;
 
-       /* On MRST, there is no PCI ROM BAR, this will cause a subsequent read
+       /*
+        * On MRST, there is no PCI ROM BAR, this will cause a subsequent read
         * to ROM BAR return 0 then being ignored.
         */
        if (where == PCI_ROM_ADDRESS)
@@ -210,7 +212,8 @@ static int mrst_pci_irq_enable(struct pci_dev *dev)
 
        pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
 
-       /* MRST only have IOAPIC, the PCI irq lines are 1:1 mapped to
+       /*
+        * MRST only have IOAPIC, the PCI irq lines are 1:1 mapped to
         * IOAPIC RTE entries, so we just enable RTE for the device.
         */
        irq_attr.ioapic = mp_find_ioapic(dev->irq);
@@ -235,7 +238,7 @@ struct pci_ops pci_mrst_ops = {
  */
 int __init pci_mrst_init(void)
 {
-       printk(KERN_INFO "Intel MID platform detected, using MID PCI ops\n");
+       pr_info("Intel MID platform detected, using MID PCI ops\n");
        pci_mmcfg_late_init();
        pcibios_enable_irq = mrst_pci_irq_enable;
        pci_root_ops = pci_mrst_ops;
@@ -244,17 +247,21 @@ int __init pci_mrst_init(void)
        return 1;
 }
 
-/* Langwell devices are not true pci devices, they are not subject to 10 ms
- * d3 to d0 delay required by pci spec.
+/*
+ * Langwell devices are not true PCI devices; they are not subject to 10 ms
+ * d3 to d0 delay required by PCI spec.
  */
 static void pci_d3delay_fixup(struct pci_dev *dev)
 {
-       /* PCI fixups are effectively decided compile time. If we have a dual
-          SoC/non-SoC kernel we don't want to mangle d3 on non SoC devices */
-        if (!pci_soc_mode)
-            return;
-       /* true pci devices in lincroft should allow type 1 access, the rest
-        * are langwell fake pci devices.
+       /*
+        * PCI fixups are effectively decided compile time. If we have a dual
+        * SoC/non-SoC kernel we don't want to mangle d3 on non-SoC devices.
+        */
+       if (!pci_soc_mode)
+               return;
+       /*
+        * True PCI devices in Lincroft should allow type 1 access, the rest
+        * are Langwell fake PCI devices.
         */
        if (type1_access_ok(dev->bus->number, dev->devfn, PCI_DEVICE_ID))
                return;
index 643b8b5eee86b3eee7edb2cf99dfa31ad7f9318d..8244f5ec2f4c7520284ff2388c328a17c10e3440 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/kernel.h>
 #include <linux/irq.h>
 #include <linux/module.h>
+#include <linux/reboot.h>
 #include <linux/serial_reg.h>
 #include <linux/serial_8250.h>
 #include <linux/reboot.h>
index 6bb49b687c9791a379317343d6597d996fa72402..a623ee6d9455d4d7c8e9f3b9b57452b39062f86c 100644 (file)
@@ -11,8 +11,7 @@ Elf32_Half elf_core_extra_phdrs(void)
        return vsyscall_ehdr ? (((struct elfhdr *)vsyscall_ehdr)->e_phnum) : 0;
 }
 
-int elf_core_write_extra_phdrs(struct file *file, loff_t offset, size_t *size,
-                              unsigned long limit)
+int elf_core_write_extra_phdrs(struct coredump_params *cprm, loff_t offset)
 {
        if ( vsyscall_ehdr ) {
                const struct elfhdr *const ehdrp =
@@ -32,19 +31,16 @@ int elf_core_write_extra_phdrs(struct file *file, loff_t offset, size_t *size,
                                phdr.p_offset += ofs;
                        }
                        phdr.p_paddr = 0; /* match other core phdrs */
-                       *size += sizeof(phdr);
-                       if (*size > limit
-                           || !dump_write(file, &phdr, sizeof(phdr)))
+                       if (!dump_emit(cprm, &phdr, sizeof(phdr)))
                                return 0;
                }
        }
        return 1;
 }
 
-int elf_core_write_extra_data(struct file *file, size_t *size,
-                             unsigned long limit)
+int elf_core_write_extra_data(struct coredump_params *cprm)
 {
-       if ( vsyscall_ehdr ) {
+       if (vsyscall_ehdr) {
                const struct elfhdr *const ehdrp =
                        (struct elfhdr *) vsyscall_ehdr;
                const struct elf_phdr *const phdrp =
@@ -56,9 +52,7 @@ int elf_core_write_extra_data(struct file *file, size_t *size,
                                void *addr = (void *) phdrp[i].p_vaddr;
                                size_t filesz = phdrp[i].p_filesz;
 
-                               *size += filesz;
-                               if (*size > limit
-                                   || !dump_write(file, addr, filesz))
+                               if (!dump_emit(cprm, addr, filesz))
                                        return 0;
                        }
                }
index ecddf921a9db401ee30bea1bf24b30f0ee8dd85d..b7bc2e70895a2ba3ca628e5854128092b6b20e38 100644 (file)
@@ -3224,7 +3224,7 @@ int alg_test(const char *driver, const char *alg, u32 type, u32 mask)
        if (i >= 0)
                rc |= alg_test_descs[i].test(alg_test_descs + i, driver,
                                             type, mask);
-       if (j >= 0)
+       if (j >= 0 && j != i)
                rc |= alg_test_descs[j].test(alg_test_descs + j, driver,
                                             type, mask);
 
index d21167bfc86564b480f21c9b690fe263a0609a73..dc34a5b8bceeea2d9dfac6ccccee6bb7ed64c0e2 100644 (file)
@@ -359,6 +359,9 @@ int braille_register_console(struct console *console, int index,
                char *console_options, char *braille_options)
 {
        int ret;
+
+       if (!(console->flags & CON_BRL))
+               return 0;
        if (!console_options)
                /* Only support VisioBraille for now */
                console_options = "57600o8";
@@ -374,15 +377,17 @@ int braille_register_console(struct console *console, int index,
        braille_co = console;
        register_keyboard_notifier(&keyboard_notifier_block);
        register_vt_notifier(&vt_notifier_block);
-       return 0;
+       return 1;
 }
 
 int braille_unregister_console(struct console *console)
 {
        if (braille_co != console)
                return -EINVAL;
+       if (!(console->flags & CON_BRL))
+               return 0;
        unregister_keyboard_notifier(&keyboard_notifier_block);
        unregister_vt_notifier(&vt_notifier_block);
        braille_co = NULL;
-       return 0;
+       return 1;
 }
index 100bd724f64828e3c42f4e664ced388f346f01e4..3278a210c435320df0e98a9dacbab2892b180176 100644 (file)
@@ -91,24 +91,6 @@ config ACPI_EC_DEBUGFS
          Thus this option is a debug option that helps to write ACPI drivers
          and can be used to identify ACPI code or EC firmware bugs.
 
-config ACPI_PROC_EVENT
-       bool "Deprecated /proc/acpi/event support"
-       depends on PROC_FS
-       default y
-       help
-         A user-space daemon, acpid, typically reads /proc/acpi/event
-         and handles all ACPI-generated events.
-
-         These events are now delivered to user-space either
-         via the input layer or as netlink events.
-
-         This build option enables the old code for legacy
-         user-space implementation.  After some time, this will
-         be moved under CONFIG_ACPI_PROCFS, and then deleted.
-
-         Say Y here to retain the old behaviour.  Say N if your
-         user-space is newer than kernel 2.6.23 (September 2007).
-
 config ACPI_AC
        tristate "AC Adapter"
        depends on X86
index 4f4e741d34b2c9616808177c31e7b488ee00ed8e..f37beaa32750106dffdf9fd7aeac764f1f0094f2 100644 (file)
@@ -267,7 +267,6 @@ static void acpi_ac_notify(struct acpi_device *device, u32 event)
                        msleep(ac_sleep_before_get_state_ms);
 
                acpi_ac_get_state(ac);
-               acpi_bus_generate_proc_event(device, event, (u32) ac->state);
                acpi_bus_generate_netlink_event(device->pnp.device_class,
                                                  dev_name(&device->dev), event,
                                                  (u32) ac->state);
index 27bb6a91de5f6cf257fd85562fb12bcc033baecc..6230637054c6ccd10c7fd95b999684c6b9752616 100644 (file)
@@ -452,7 +452,6 @@ static void acpi_pad_notify(acpi_handle handle, u32 event,
        switch (event) {
        case ACPI_PROCESSOR_AGGREGATOR_NOTIFY:
                acpi_pad_handle_notify(handle);
-               acpi_bus_generate_proc_event(device, event, 0);
                acpi_bus_generate_netlink_event(device->pnp.device_class,
                        dev_name(&device->dev), event, 0);
                break;
index fafec5ddf17f17c326181988cf3f7d3d625c442f..32136b85196d438e665b27bb7e5686e3e1fa243f 100644 (file)
@@ -52,7 +52,7 @@ int acpi_create_platform_device(struct acpi_device *adev,
        struct platform_device_info pdevinfo;
        struct resource_list_entry *rentry;
        struct list_head resource_list;
-       struct resource *resources;
+       struct resource *resources = NULL;
        int count;
 
        /* If the ACPI node already has a physical device attached, skip it. */
@@ -61,9 +61,12 @@ int acpi_create_platform_device(struct acpi_device *adev,
 
        INIT_LIST_HEAD(&resource_list);
        count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
-       if (count <= 0)
+       if (count < 0)
                return 0;
 
+       if (!count)
+               goto create_dev;
+
        resources = kmalloc(count * sizeof(struct resource), GFP_KERNEL);
        if (!resources) {
                dev_err(&adev->dev, "No memory for resources\n");
@@ -76,6 +79,7 @@ int acpi_create_platform_device(struct acpi_device *adev,
 
        acpi_dev_free_resource_list(&resource_list);
 
+create_dev:
        memset(&pdevinfo, 0, sizeof(pdevinfo));
        /*
         * If the ACPI node has a parent and that parent has a physical device
index d4a4901637cd01f06e2646a145abdeaff16773ec..b0e3d15cfe96c289901c5ba597b96061df078099 100644 (file)
@@ -942,6 +942,9 @@ struct acpi_interface_info {
 
 #define ACPI_OSI_INVALID                0x01
 #define ACPI_OSI_DYNAMIC                0x02
+#define ACPI_OSI_FEATURE                0x04
+#define ACPI_OSI_DEFAULT_INVALID        0x08
+#define ACPI_OSI_OPTIONAL_FEATURE       (ACPI_OSI_FEATURE | ACPI_OSI_DEFAULT_INVALID | ACPI_OSI_INVALID)
 
 struct acpi_port_info {
        char *name;
index 7755e915a007a9aec4ecefce08f2bfdceb7b2a7f..917315ec21dda3f272e88ca61fcb5b845aa31457 100644 (file)
 
 acpi_status acpi_allocate_root_table(u32 initial_table_count);
 
+/*
+ * tbxfroot - Root pointer utilities
+ */
+u8 *acpi_tb_scan_memory_for_rsdp(u8 *start_address, u32 length);
+
 /*
  * tbfadt - FADT parse/convert/validate
  */
index 3c76edea6803faf0cf8c7db1b76431b5abafbf04..d5a62a6182bb96826e5ee7144d8e7be228cd91ea 100644 (file)
@@ -470,6 +470,8 @@ acpi_status acpi_ut_install_interface(acpi_string interface_name);
 
 acpi_status acpi_ut_remove_interface(acpi_string interface_name);
 
+acpi_status acpi_ut_update_interfaces(u8 action);
+
 struct acpi_interface_info *acpi_ut_get_interface(acpi_string interface_name);
 
 acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state);
@@ -616,7 +618,7 @@ int acpi_ut_stricmp(char *string1, char *string2);
 
 acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer);
 
-void acpi_ut_print_string(char *string, u8 max_length);
+void acpi_ut_print_string(char *string, u16 max_length);
 
 void ut_convert_backslashes(char *pathname);
 
index 9037f17c9608f70a6bc2df68eca5b55043ad9723..7842700346a48b0cfa542d46def472ba92643212 100644 (file)
@@ -125,7 +125,6 @@ acpi_status acpi_ev_gpe_initialize(void)
                /* GPE block 0 exists (has both length and address > 0) */
 
                register_count0 = (u16)(acpi_gbl_FADT.gpe0_block_length / 2);
-
                gpe_number_max =
                    (register_count0 * ACPI_GPE_REGISTER_WIDTH) - 1;
 
@@ -204,16 +203,6 @@ acpi_status acpi_ev_gpe_initialize(void)
                goto cleanup;
        }
 
-       /* Check for Max GPE number out-of-range */
-
-       if (gpe_number_max > ACPI_GPE_MAX) {
-               ACPI_ERROR((AE_INFO,
-                           "Maximum GPE number from FADT is too large: 0x%X",
-                           gpe_number_max));
-               status = AE_BAD_VALUE;
-               goto cleanup;
-       }
-
       cleanup:
        (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
        return_ACPI_STATUS(AE_OK);
index c740f24e3101069af922a5e5842a77fb60d34710..4d046faac48cbb09b2c0aa6c4a0c5e8550333ec5 100644 (file)
@@ -338,6 +338,7 @@ acpi_ex_dump_object(union acpi_operand_object *obj_desc,
 {
        u8 *target;
        char *name;
+       const char *reference_name;
        u8 count;
 
        if (!info) {
@@ -426,10 +427,9 @@ acpi_ex_dump_object(union acpi_operand_object *obj_desc,
 
                case ACPI_EXD_REFERENCE:
 
+                       reference_name = acpi_ut_get_reference_name(obj_desc);
                        acpi_ex_out_string("Class Name",
-                                          ACPI_CAST_PTR(char,
-                                                        acpi_ut_get_reference_name
-                                                        (obj_desc)));
+                                          ACPI_CAST_PTR(char, reference_name));
                        acpi_ex_dump_reference_obj(obj_desc);
                        break;
 
index 5e5f76230f5eb673057f86c7d61c24539471a1eb..414076818d40ee234d05970e5675023d1bff5b20 100644 (file)
@@ -43,6 +43,7 @@
  */
 
 #include <acpi/acpi.h>
+#include <linux/acpi.h>
 #include "accommon.h"
 
 #define _COMPONENT          ACPI_HARDWARE
@@ -128,6 +129,14 @@ acpi_status acpi_hw_extended_sleep(u8 sleep_state)
 
        ACPI_FLUSH_CPU_CACHE();
 
+       status = acpi_os_prepare_extended_sleep(sleep_state,
+                                               acpi_gbl_sleep_type_a,
+                                               acpi_gbl_sleep_type_b);
+       if (ACPI_SKIP(status))
+               return_ACPI_STATUS(AE_OK);
+       if (ACPI_FAILURE(status))
+               return_ACPI_STATUS(status);
+
        /*
         * Set the SLP_TYP and SLP_EN bits.
         *
index f3a4d95899f71ea8578362fa35b5867423028dd2..83c164434580d3bd12229be0278d6e7e70e0e6b8 100644 (file)
@@ -158,6 +158,7 @@ acpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer * buffer)
 {
        acpi_status status;
        struct acpi_namespace_node *node;
+       char *node_name;
 
        /* Parameter validation */
 
@@ -202,7 +203,8 @@ acpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer * buffer)
 
        /* Just copy the ACPI name from the Node and zero terminate it */
 
-       ACPI_MOVE_NAME(buffer->pointer, acpi_ut_get_node_name(node));
+       node_name = acpi_ut_get_node_name(node);
+       ACPI_MOVE_NAME(buffer->pointer, node_name);
        ((char *)buffer->pointer)[ACPI_NAME_SIZE] = 0;
        status = AE_OK;
 
@@ -379,9 +381,14 @@ acpi_get_object_info(acpi_handle handle,
                 * Get extra info for ACPI Device/Processor objects only:
                 * Run the _STA, _ADR and, sx_w, and _sx_d methods.
                 *
-                * Note: none of these methods are required, so they may or may
+                * Notes: none of these methods are required, so they may or may
                 * not be present for this device. The Info->Valid bitfield is used
                 * to indicate which methods were found and run successfully.
+                *
+                * For _STA, if the method does not exist, then (as per the ACPI
+                * specification), the returned current_status flags will indicate
+                * that the device is present/functional/enabled. Otherwise, the
+                * current_status flags reflect the value returned from _STA.
                 */
 
                /* Execute the Device._STA method */
index 7c2ecfb7c2c37dbb448e7703d2689d994fe8931f..e76ed0f078265becd5942fc70ac2e21b85d013fa 100644 (file)
@@ -49,8 +49,6 @@
 ACPI_MODULE_NAME("tbxfroot")
 
 /* Local prototypes */
-static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length);
-
 static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp);
 
 /*******************************************************************************
@@ -231,7 +229,7 @@ acpi_status acpi_find_root_pointer(acpi_size *table_address)
  * DESCRIPTION: Search a block of memory for the RSDP signature
  *
  ******************************************************************************/
-static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length)
+u8 *acpi_tb_scan_memory_for_rsdp(u8 *start_address, u32 length)
 {
        acpi_status status;
        u8 *mem_rover;
index ee83adb97b1e73827a6a7740de03edb3680e2a28..4fd68971019bdd69bcdf5ede57e26abaea3bf09f 100644 (file)
@@ -239,7 +239,8 @@ acpi_ut_evaluate_numeric_object(char *object_name,
  * RETURN:      Status
  *
  * DESCRIPTION: Executes _STA for selected device and stores results in
- *              *Flags.
+ *              *Flags. If _STA does not exist, then the device is assumed
+ *              to be present/functional/enabled (as per the ACPI spec).
  *
  *              NOTE: Internal function, no parameter validation
  *
@@ -257,6 +258,11 @@ acpi_ut_execute_STA(struct acpi_namespace_node *device_node, u32 * flags)
                                         ACPI_BTYPE_INTEGER, &obj_desc);
        if (ACPI_FAILURE(status)) {
                if (AE_NOT_FOUND == status) {
+                       /*
+                        * if _STA does not exist, then (as per the ACPI specification),
+                        * the returned flags will indicate that the device is present,
+                        * functional, and enabled.
+                        */
                        ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
                                          "_STA on %4.4s was not found, assuming device is present\n",
                                          acpi_ut_get_node_name(device_node)));
index 7e807725c636896aeeb83c3b35022eb2ad88848f..8856bd37bc763f2a94c157acb513aefa82342875 100644 (file)
@@ -77,21 +77,20 @@ static struct acpi_interface_info acpi_default_supported_interfaces[] = {
 
        /* Feature Group Strings */
 
-       {"Extended Address Space Descriptor", NULL, 0, 0}
+       {"Extended Address Space Descriptor", NULL, ACPI_OSI_FEATURE, 0},
 
        /*
         * All "optional" feature group strings (features that are implemented
-        * by the host) should be dynamically added by the host via
-        * acpi_install_interface and should not be manually added here.
-        *
-        * Examples of optional feature group strings:
-        *
-        * "Module Device"
-        * "Processor Device"
-        * "3.0 Thermal Model"
-        * "3.0 _SCP Extensions"
-        * "Processor Aggregator Device"
+        * by the host) should be dynamically modified to VALID by the host via
+        * acpi_install_interface or acpi_update_interfaces. Such optional feature
+        * group strings are set as INVALID by default here.
         */
+
+       {"Module Device", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0},
+       {"Processor Device", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0},
+       {"3.0 Thermal Model", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0},
+       {"3.0 _SCP Extensions", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0},
+       {"Processor Aggregator Device", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0}
 };
 
 /*******************************************************************************
@@ -158,11 +157,20 @@ acpi_status acpi_ut_interface_terminate(void)
        while (next_interface) {
                acpi_gbl_supported_interfaces = next_interface->next;
 
-               /* Only interfaces added at runtime can be freed */
-
                if (next_interface->flags & ACPI_OSI_DYNAMIC) {
+
+                       /* Only interfaces added at runtime can be freed */
+
                        ACPI_FREE(next_interface->name);
                        ACPI_FREE(next_interface);
+               } else {
+                       /* Interface is in static list. Reset it to invalid or valid. */
+
+                       if (next_interface->flags & ACPI_OSI_DEFAULT_INVALID) {
+                               next_interface->flags |= ACPI_OSI_INVALID;
+                       } else {
+                               next_interface->flags &= ~ACPI_OSI_INVALID;
+                       }
                }
 
                next_interface = acpi_gbl_supported_interfaces;
@@ -276,6 +284,49 @@ acpi_status acpi_ut_remove_interface(acpi_string interface_name)
        return (AE_NOT_EXIST);
 }
 
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_update_interfaces
+ *
+ * PARAMETERS:  action              - Actions to be performed during the
+ *                                    update
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Update _OSI interface strings, disabling or enabling OS vendor
+ *              strings or/and feature group strings.
+ *              Caller MUST hold acpi_gbl_osi_mutex
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ut_update_interfaces(u8 action)
+{
+       struct acpi_interface_info *next_interface;
+
+       next_interface = acpi_gbl_supported_interfaces;
+       while (next_interface) {
+               if (((next_interface->flags & ACPI_OSI_FEATURE) &&
+                    (action & ACPI_FEATURE_STRINGS)) ||
+                   (!(next_interface->flags & ACPI_OSI_FEATURE) &&
+                    (action & ACPI_VENDOR_STRINGS))) {
+                       if (action & ACPI_DISABLE_INTERFACES) {
+
+                               /* Mark the interfaces as invalid */
+
+                               next_interface->flags |= ACPI_OSI_INVALID;
+                       } else {
+                               /* Mark the interfaces as valid */
+
+                               next_interface->flags &= ~ACPI_OSI_INVALID;
+                       }
+               }
+
+               next_interface = next_interface->next;
+       }
+
+       return (AE_OK);
+}
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ut_get_interface
index c53759b76a3f97d0fe5558f36ad9b656fbc905fa..cb1e9cc32d5f8d89e7d8ba954d5c0928a0ff5f66 100644 (file)
@@ -333,7 +333,8 @@ acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer)
  * FUNCTION:    acpi_ut_print_string
  *
  * PARAMETERS:  string          - Null terminated ASCII string
- *              max_length      - Maximum output length
+ *              max_length      - Maximum output length. Used to constrain the
+ *                                length of strings during debug output only.
  *
  * RETURN:      None
  *
@@ -342,7 +343,7 @@ acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer)
  *
  ******************************************************************************/
 
-void acpi_ut_print_string(char *string, u8 max_length)
+void acpi_ut_print_string(char *string, u16 max_length)
 {
        u32 i;
 
index 6505774f223e372239a0ee5fadfc00e4aaaf0446..03a211e6e26ab0a3789b7192fc6386ecd456bb1c 100644 (file)
@@ -387,6 +387,34 @@ acpi_status acpi_install_interface_handler(acpi_interface_handler handler)
 
 ACPI_EXPORT_SYMBOL(acpi_install_interface_handler)
 
+/*****************************************************************************
+ *
+ * FUNCTION:    acpi_update_interfaces
+ *
+ * PARAMETERS:  action              - Actions to be performed during the
+ *                                    update
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Update _OSI interface strings, disabling or enabling OS vendor
+ *              string or/and feature group strings.
+ *
+ ****************************************************************************/
+acpi_status acpi_update_interfaces(u8 action)
+{
+       acpi_status status;
+
+       status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
+       if (ACPI_FAILURE(status)) {
+               return (status);
+       }
+
+       status = acpi_ut_update_interfaces(action);
+
+       acpi_os_release_mutex(acpi_gbl_osi_mutex);
+       return (status);
+}
+
 /*****************************************************************************
  *
  * FUNCTION:    acpi_check_address_range
@@ -402,6 +430,7 @@ ACPI_EXPORT_SYMBOL(acpi_install_interface_handler)
  *              ASL operation region address ranges.
  *
  ****************************************************************************/
+
 u32
 acpi_check_address_range(acpi_adr_space_type space_id,
                         acpi_physical_address address,
index 082b4dd252a82ab17f7fe7249913e1f7030d35fd..2c9958cd7a4350ae675b76ad338904999ae149c1 100644 (file)
@@ -117,6 +117,7 @@ struct acpi_battery {
        struct acpi_device *device;
        struct notifier_block pm_nb;
        unsigned long update_time;
+       int revision;
        int rate_now;
        int capacity_now;
        int voltage_now;
@@ -359,6 +360,7 @@ static struct acpi_offsets info_offsets[] = {
 };
 
 static struct acpi_offsets extended_info_offsets[] = {
+       {offsetof(struct acpi_battery, revision), 0},
        {offsetof(struct acpi_battery, power_unit), 0},
        {offsetof(struct acpi_battery, design_capacity), 0},
        {offsetof(struct acpi_battery, full_charge_capacity), 0},
@@ -525,18 +527,14 @@ static int acpi_battery_get_state(struct acpi_battery *battery)
 static int acpi_battery_set_alarm(struct acpi_battery *battery)
 {
        acpi_status status = 0;
-       union acpi_object arg0 = { .type = ACPI_TYPE_INTEGER };
-       struct acpi_object_list arg_list = { 1, &arg0 };
 
        if (!acpi_battery_present(battery) ||
            !test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags))
                return -ENODEV;
 
-       arg0.integer.value = battery->alarm;
-
        mutex_lock(&battery->lock);
-       status = acpi_evaluate_object(battery->device->handle, "_BTP",
-                                &arg_list, NULL);
+       status = acpi_execute_simple_method(battery->device->handle, "_BTP",
+                                           battery->alarm);
        mutex_unlock(&battery->lock);
 
        if (ACPI_FAILURE(status))
@@ -548,12 +546,8 @@ static int acpi_battery_set_alarm(struct acpi_battery *battery)
 
 static int acpi_battery_init_alarm(struct acpi_battery *battery)
 {
-       acpi_status status = AE_OK;
-       acpi_handle handle = NULL;
-
        /* See if alarms are supported, and if so, set default */
-       status = acpi_get_handle(battery->device->handle, "_BTP", &handle);
-       if (ACPI_FAILURE(status)) {
+       if (!acpi_has_method(battery->device->handle, "_BTP")) {
                clear_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags);
                return 0;
        }
@@ -1034,8 +1028,6 @@ static void acpi_battery_notify(struct acpi_device *device, u32 event)
        if (event == ACPI_BATTERY_NOTIFY_INFO)
                acpi_battery_refresh(battery);
        acpi_battery_update(battery);
-       acpi_bus_generate_proc_event(device, event,
-                                    acpi_battery_present(battery));
        acpi_bus_generate_netlink_event(device->pnp.device_class,
                                        dev_name(&device->dev), event,
                                        acpi_battery_present(battery));
@@ -1066,7 +1058,7 @@ static int acpi_battery_add(struct acpi_device *device)
 {
        int result = 0;
        struct acpi_battery *battery = NULL;
-       acpi_handle handle;
+
        if (!device)
                return -EINVAL;
        battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL);
@@ -1078,8 +1070,7 @@ static int acpi_battery_add(struct acpi_device *device)
        device->driver_data = battery;
        mutex_init(&battery->lock);
        mutex_init(&battery->sysfs_lock);
-       if (ACPI_SUCCESS(acpi_get_handle(battery->device->handle,
-                       "_BIX", &handle)))
+       if (acpi_has_method(battery->device->handle, "_BIX"))
                set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags);
        result = acpi_battery_update(battery);
        if (result)
index cb9629638def78fdd1432dc06102c2a5f5097a24..a404127768045f5b2fb1fe7a6035cf5ec2a0f93a 100644 (file)
@@ -192,6 +192,12 @@ static int __init dmi_disable_osi_win7(const struct dmi_system_id *d)
        acpi_osi_setup("!Windows 2009");
        return 0;
 }
+static int __init dmi_disable_osi_win8(const struct dmi_system_id *d)
+{
+       printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident);
+       acpi_osi_setup("!Windows 2012");
+       return 0;
+}
 
 static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
        {
@@ -267,6 +273,14 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
                     DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P305D"),
                },
        },
+       {
+       .callback = dmi_disable_osi_win8,
+       .ident = "ASUS Zenbook Prime UX31A",
+       .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                    DMI_MATCH(DMI_PRODUCT_NAME, "UX31A"),
+               },
+       },
 
        /*
         * BIOS invocation of _OSI(Linux) is almost always a BIOS bug.
index a5bb33bab4485307f7969b19ff9d9ea9cb3f67e2..b587ec8257b2190758eca2b8b3306a933d4ae16d 100644 (file)
@@ -89,27 +89,6 @@ static struct dmi_system_id dsdt_dmi_table[] __initdata = {
                                 Device Management
    -------------------------------------------------------------------------- */
 
-int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
-{
-       acpi_status status;
-
-       if (!device)
-               return -EINVAL;
-
-       /* TBD: Support fixed-feature devices */
-
-       status = acpi_get_data(handle, acpi_bus_data_handler, (void **)device);
-       if (ACPI_FAILURE(status) || !*device) {
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n",
-                                 handle));
-               return -ENODEV;
-       }
-
-       return 0;
-}
-
-EXPORT_SYMBOL(acpi_bus_get_device);
-
 acpi_status acpi_bus_get_status_handle(acpi_handle handle,
                                       unsigned long long *sta)
 {
@@ -345,104 +324,6 @@ static void acpi_bus_osc_support(void)
        /* do we need to check other returned cap? Sounds no */
 }
 
-/* --------------------------------------------------------------------------
-                                Event Management
-   -------------------------------------------------------------------------- */
-
-#ifdef CONFIG_ACPI_PROC_EVENT
-static DEFINE_SPINLOCK(acpi_bus_event_lock);
-
-LIST_HEAD(acpi_bus_event_list);
-DECLARE_WAIT_QUEUE_HEAD(acpi_bus_event_queue);
-
-extern int event_is_open;
-
-int acpi_bus_generate_proc_event4(const char *device_class, const char *bus_id, u8 type, int data)
-{
-       struct acpi_bus_event *event;
-       unsigned long flags;
-
-       /* drop event on the floor if no one's listening */
-       if (!event_is_open)
-               return 0;
-
-       event = kzalloc(sizeof(struct acpi_bus_event), GFP_ATOMIC);
-       if (!event)
-               return -ENOMEM;
-
-       strcpy(event->device_class, device_class);
-       strcpy(event->bus_id, bus_id);
-       event->type = type;
-       event->data = data;
-
-       spin_lock_irqsave(&acpi_bus_event_lock, flags);
-       list_add_tail(&event->node, &acpi_bus_event_list);
-       spin_unlock_irqrestore(&acpi_bus_event_lock, flags);
-
-       wake_up_interruptible(&acpi_bus_event_queue);
-
-       return 0;
-
-}
-
-EXPORT_SYMBOL_GPL(acpi_bus_generate_proc_event4);
-
-int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data)
-{
-       if (!device)
-               return -EINVAL;
-       return acpi_bus_generate_proc_event4(device->pnp.device_class,
-                                            device->pnp.bus_id, type, data);
-}
-
-EXPORT_SYMBOL(acpi_bus_generate_proc_event);
-
-int acpi_bus_receive_event(struct acpi_bus_event *event)
-{
-       unsigned long flags;
-       struct acpi_bus_event *entry = NULL;
-
-       DECLARE_WAITQUEUE(wait, current);
-
-
-       if (!event)
-               return -EINVAL;
-
-       if (list_empty(&acpi_bus_event_list)) {
-
-               set_current_state(TASK_INTERRUPTIBLE);
-               add_wait_queue(&acpi_bus_event_queue, &wait);
-
-               if (list_empty(&acpi_bus_event_list))
-                       schedule();
-
-               remove_wait_queue(&acpi_bus_event_queue, &wait);
-               set_current_state(TASK_RUNNING);
-
-               if (signal_pending(current))
-                       return -ERESTARTSYS;
-       }
-
-       spin_lock_irqsave(&acpi_bus_event_lock, flags);
-       if (!list_empty(&acpi_bus_event_list)) {
-               entry = list_entry(acpi_bus_event_list.next,
-                                  struct acpi_bus_event, node);
-               list_del(&entry->node);
-       }
-       spin_unlock_irqrestore(&acpi_bus_event_lock, flags);
-
-       if (!entry)
-               return -ENODEV;
-
-       memcpy(event, entry, sizeof(struct acpi_bus_event));
-
-       kfree(entry);
-
-       return 0;
-}
-
-#endif /* CONFIG_ACPI_PROC_EVENT */
-
 /* --------------------------------------------------------------------------
                              Notification Handling
    -------------------------------------------------------------------------- */
@@ -499,19 +380,6 @@ static void acpi_bus_check_scope(acpi_handle handle)
         */
 }
 
-static BLOCKING_NOTIFIER_HEAD(acpi_bus_notify_list);
-int register_acpi_bus_notifier(struct notifier_block *nb)
-{
-       return blocking_notifier_chain_register(&acpi_bus_notify_list, nb);
-}
-EXPORT_SYMBOL_GPL(register_acpi_bus_notifier);
-
-void unregister_acpi_bus_notifier(struct notifier_block *nb)
-{
-       blocking_notifier_chain_unregister(&acpi_bus_notify_list, nb);
-}
-EXPORT_SYMBOL_GPL(unregister_acpi_bus_notifier);
-
 /**
  * acpi_bus_notify
  * ---------------
@@ -525,9 +393,6 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
        ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notification %#02x to handle %p\n",
                          type, handle));
 
-       blocking_notifier_call_chain(&acpi_bus_notify_list,
-               type, (void *)handle);
-
        switch (type) {
 
        case ACPI_NOTIFY_BUS_CHECK:
@@ -593,8 +458,6 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
 static int __init acpi_bus_init_irq(void)
 {
        acpi_status status;
-       union acpi_object arg = { ACPI_TYPE_INTEGER };
-       struct acpi_object_list arg_list = { 1, &arg };
        char *message = NULL;
 
 
@@ -623,9 +486,7 @@ static int __init acpi_bus_init_irq(void)
 
        printk(KERN_INFO PREFIX "Using %s for interrupt routing\n", message);
 
-       arg.integer.value = acpi_irq_model;
-
-       status = acpi_evaluate_object(NULL, "\\_PIC", &arg_list, NULL);
+       status = acpi_execute_simple_method(NULL, "\\_PIC", acpi_irq_model);
        if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
                ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PIC"));
                return -ENODEV;
@@ -715,7 +576,6 @@ static int __init acpi_bus_init(void)
 {
        int result;
        acpi_status status;
-       extern acpi_status acpi_os_initialize1(void);
 
        acpi_os_initialize1();
 
index d2e617b5b3f661c8d0effd34628eb4225875d0f4..a55773801c5f1fb739df9597dbbde86d272b092c 100644 (file)
@@ -303,8 +303,6 @@ static void acpi_button_notify(struct acpi_device *device, u32 event)
 
                        pm_wakeup_event(&device->dev, 0);
                }
-
-               acpi_bus_generate_proc_event(device, event, ++button->pushed);
                break;
        default:
                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
index 4ab807dc851812a8c4d64265298f38c610bf22ba..beb9625e8458d089faff6420cbbb209be753fcb2 100644 (file)
@@ -159,26 +159,27 @@ int acpi_device_set_power(struct acpi_device *device, int state)
        int result = 0;
        bool cut_power = false;
 
-       if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
+       if (!device || !device->flags.power_manageable
+           || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
                return -EINVAL;
 
        /* Make sure this is a valid target state */
 
        if (state == device->power.state) {
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at %s\n",
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] already in %s\n",
+                                 device->pnp.bus_id,
                                  acpi_power_state_string(state)));
                return 0;
        }
 
        if (!device->power.states[state].flags.valid) {
-               printk(KERN_WARNING PREFIX "Device does not support %s\n",
-                      acpi_power_state_string(state));
+               dev_warn(&device->dev, "Power state %s not supported\n",
+                        acpi_power_state_string(state));
                return -ENODEV;
        }
        if (device->parent && (state < device->parent->power.state)) {
-               printk(KERN_WARNING PREFIX
-                             "Cannot set device to a higher-powered"
-                             " state than parent\n");
+               dev_warn(&device->dev,
+                        "Cannot transition to a higher-powered state than parent\n");
                return -ENODEV;
        }
 
@@ -191,8 +192,8 @@ int acpi_device_set_power(struct acpi_device *device, int state)
 
        if (state < device->power.state && state != ACPI_STATE_D0
            && device->power.state >= ACPI_STATE_D3_HOT) {
-               printk(KERN_WARNING PREFIX
-                       "Cannot transition to non-D0 state from D3\n");
+               dev_warn(&device->dev,
+                        "Cannot transition to non-D0 state from D3\n");
                return -ENODEV;
        }
 
@@ -219,10 +220,8 @@ int acpi_device_set_power(struct acpi_device *device, int state)
 
  end:
        if (result) {
-               printk(KERN_WARNING PREFIX
-                             "Device [%s] failed to transition to %s\n",
-                             device->pnp.bus_id,
-                             acpi_power_state_string(state));
+               dev_warn(&device->dev, "Failed to change power state to %s\n",
+                        acpi_power_state_string(state));
        } else {
                device->power.state = state;
                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -244,13 +243,6 @@ int acpi_bus_set_power(acpi_handle handle, int state)
        if (result)
                return result;
 
-       if (!device->flags.power_manageable) {
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                               "Device [%s] is not power manageable\n",
-                               dev_name(&device->dev)));
-               return -ENODEV;
-       }
-
        return acpi_device_set_power(device, state);
 }
 EXPORT_SYMBOL(acpi_bus_set_power);
index 826560753389ca3f1d2dd1bc2670f15f059970ae..b527c1bd8bb2aaf2b27c73b4a24e86d9d3a8202f 100644 (file)
@@ -51,8 +51,6 @@ MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to "
        " the driver to wait for userspace to write the undock sysfs file "
        " before undocking");
 
-static struct atomic_notifier_head dock_notifier_list;
-
 static const struct acpi_device_id dock_device_ids[] = {
        {"LNXDOCK", 0},
        {"", 0},
@@ -63,8 +61,6 @@ struct dock_station {
        acpi_handle handle;
        unsigned long last_dock_time;
        u32 flags;
-       spinlock_t dd_lock;
-       struct mutex hp_lock;
        struct list_head dependent_devices;
 
        struct list_head sibling;
@@ -91,6 +87,12 @@ struct dock_dependent_device {
 #define DOCK_EVENT     3
 #define UNDOCK_EVENT   2
 
+enum dock_callback_type {
+       DOCK_CALL_HANDLER,
+       DOCK_CALL_FIXUP,
+       DOCK_CALL_UEVENT,
+};
+
 /*****************************************************************************
  *                         Dock Dependent device functions                   *
  *****************************************************************************/
@@ -101,7 +103,7 @@ struct dock_dependent_device {
  *
  * Add the dependent device to the dock's dependent device list.
  */
-static int
+static int __init
 add_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
 {
        struct dock_dependent_device *dd;
@@ -112,14 +114,21 @@ add_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
 
        dd->handle = handle;
        INIT_LIST_HEAD(&dd->list);
-
-       spin_lock(&ds->dd_lock);
        list_add_tail(&dd->list, &ds->dependent_devices);
-       spin_unlock(&ds->dd_lock);
 
        return 0;
 }
 
+static void remove_dock_dependent_devices(struct dock_station *ds)
+{
+       struct dock_dependent_device *dd, *aux;
+
+       list_for_each_entry_safe(dd, aux, &ds->dependent_devices, list) {
+               list_del(&dd->list);
+               kfree(dd);
+       }
+}
+
 /**
  * dock_init_hotplug - Initialize a hotplug device on a docking station.
  * @dd: Dock-dependent device.
@@ -135,19 +144,16 @@ static int dock_init_hotplug(struct dock_dependent_device *dd,
        int ret = 0;
 
        mutex_lock(&hotplug_lock);
-
-       if (dd->hp_context) {
+       if (WARN_ON(dd->hp_context)) {
                ret = -EEXIST;
        } else {
                dd->hp_refcount = 1;
                dd->hp_ops = ops;
                dd->hp_context = context;
                dd->hp_release = release;
+               if (init)
+                       init(context);
        }
-
-       if (!WARN_ON(ret) && init)
-               init(context);
-
        mutex_unlock(&hotplug_lock);
        return ret;
 }
@@ -162,27 +168,22 @@ static int dock_init_hotplug(struct dock_dependent_device *dd,
  */
 static void dock_release_hotplug(struct dock_dependent_device *dd)
 {
-       void (*release)(void *) = NULL;
-       void *context = NULL;
-
        mutex_lock(&hotplug_lock);
-
        if (dd->hp_context && !--dd->hp_refcount) {
+               void (*release)(void *) = dd->hp_release;
+               void *context = dd->hp_context;
+
                dd->hp_ops = NULL;
-               context = dd->hp_context;
                dd->hp_context = NULL;
-               release = dd->hp_release;
                dd->hp_release = NULL;
+               if (release)
+                       release(context);
        }
-
-       if (release && context)
-               release(context);
-
        mutex_unlock(&hotplug_lock);
 }
 
 static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event,
-                              bool uevent)
+                              enum dock_callback_type cb_type)
 {
        acpi_notify_handler cb = NULL;
        bool run = false;
@@ -192,8 +193,18 @@ static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event,
        if (dd->hp_context) {
                run = true;
                dd->hp_refcount++;
-               if (dd->hp_ops)
-                       cb = uevent ? dd->hp_ops->uevent : dd->hp_ops->handler;
+               if (dd->hp_ops) {
+                       switch (cb_type) {
+                       case DOCK_CALL_FIXUP:
+                               cb = dd->hp_ops->fixup;
+                               break;
+                       case DOCK_CALL_UEVENT:
+                               cb = dd->hp_ops->uevent;
+                               break;
+                       default:
+                               cb = dd->hp_ops->handler;
+                       }
+               }
        }
 
        mutex_unlock(&hotplug_lock);
@@ -220,63 +231,17 @@ find_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
 {
        struct dock_dependent_device *dd;
 
-       spin_lock(&ds->dd_lock);
-       list_for_each_entry(dd, &ds->dependent_devices, list) {
-               if (handle == dd->handle) {
-                       spin_unlock(&ds->dd_lock);
+       list_for_each_entry(dd, &ds->dependent_devices, list)
+               if (handle == dd->handle)
                        return dd;
-               }
-       }
-       spin_unlock(&ds->dd_lock);
+
        return NULL;
 }
 
 /*****************************************************************************
  *                         Dock functions                                    *
  *****************************************************************************/
-/**
- * is_dock - see if a device is a dock station
- * @handle: acpi handle of the device
- *
- * If an acpi object has a _DCK method, then it is by definition a dock
- * station, so return true.
- */
-static int is_dock(acpi_handle handle)
-{
-       acpi_status status;
-       acpi_handle tmp;
-
-       status = acpi_get_handle(handle, "_DCK", &tmp);
-       if (ACPI_FAILURE(status))
-               return 0;
-       return 1;
-}
-
-static int is_ejectable(acpi_handle handle)
-{
-       acpi_status status;
-       acpi_handle tmp;
-
-       status = acpi_get_handle(handle, "_EJ0", &tmp);
-       if (ACPI_FAILURE(status))
-               return 0;
-       return 1;
-}
-
-static int is_ata(acpi_handle handle)
-{
-       acpi_handle tmp;
-
-       if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) ||
-          (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) ||
-          (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) ||
-          (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp))))
-               return 1;
-
-       return 0;
-}
-
-static int is_battery(acpi_handle handle)
+static int __init is_battery(acpi_handle handle)
 {
        struct acpi_device_info *info;
        int ret = 1;
@@ -292,17 +257,13 @@ static int is_battery(acpi_handle handle)
        return ret;
 }
 
-static int is_ejectable_bay(acpi_handle handle)
+/* Check whether ACPI object is an ejectable battery or disk bay */
+static bool __init is_ejectable_bay(acpi_handle handle)
 {
-       acpi_handle phandle;
+       if (acpi_has_method(handle, "_EJ0") && is_battery(handle))
+               return true;
 
-       if (!is_ejectable(handle))
-               return 0;
-       if (is_battery(handle) || is_ata(handle))
-               return 1;
-       if (!acpi_get_parent(handle, &phandle) && is_ata(phandle))
-               return 1;
-       return 0;
+       return acpi_bay_match(handle);
 }
 
 /**
@@ -320,7 +281,7 @@ int is_dock_device(acpi_handle handle)
        if (!dock_station_count)
                return 0;
 
-       if (is_dock(handle))
+       if (acpi_dock_match(handle))
                return 1;
 
        list_for_each_entry(dock_station, &dock_stations, sibling)
@@ -359,10 +320,8 @@ static int dock_present(struct dock_station *ds)
  *  handle if one does not exist already.  This should cause
  *  acpi to scan for drivers for the given devices, and call
  *  matching driver's add routine.
- *
- *  Returns a pointer to the acpi_device corresponding to the handle.
  */
-static struct acpi_device * dock_create_acpi_device(acpi_handle handle)
+static void dock_create_acpi_device(acpi_handle handle)
 {
        struct acpi_device *device;
        int ret;
@@ -375,10 +334,7 @@ static struct acpi_device * dock_create_acpi_device(acpi_handle handle)
                ret = acpi_bus_scan(handle);
                if (ret)
                        pr_debug("error adding bus, %x\n", -ret);
-
-               acpi_bus_get_device(handle, &device);
        }
-       return device;
 }
 
 /**
@@ -397,9 +353,29 @@ static void dock_remove_acpi_device(acpi_handle handle)
 }
 
 /**
- * hotplug_dock_devices - insert or remove devices on the dock station
+ * hot_remove_dock_devices - Remove dock station devices.
+ * @ds: Dock station.
+ */
+static void hot_remove_dock_devices(struct dock_station *ds)
+{
+       struct dock_dependent_device *dd;
+
+       /*
+        * Walk the list in reverse order so that devices that have been added
+        * last are removed first (in case there are some indirect dependencies
+        * between them).
+        */
+       list_for_each_entry_reverse(dd, &ds->dependent_devices, list)
+               dock_hotplug_event(dd, ACPI_NOTIFY_EJECT_REQUEST, false);
+
+       list_for_each_entry_reverse(dd, &ds->dependent_devices, list)
+               dock_remove_acpi_device(dd->handle);
+}
+
+/**
+ * hotplug_dock_devices - Insert devices on a dock station.
  * @ds: the dock station
- * @event: either bus check or eject request
+ * @event: either bus check or device check request
  *
  * Some devices on the dock station need to have drivers called
  * to perform hotplug operations after a dock event has occurred.
@@ -410,27 +386,21 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event)
 {
        struct dock_dependent_device *dd;
 
-       mutex_lock(&ds->hp_lock);
+       /* Call driver specific post-dock fixups. */
+       list_for_each_entry(dd, &ds->dependent_devices, list)
+               dock_hotplug_event(dd, event, DOCK_CALL_FIXUP);
 
-       /*
-        * First call driver specific hotplug functions
-        */
+       /* Call driver specific hotplug functions. */
        list_for_each_entry(dd, &ds->dependent_devices, list)
-               dock_hotplug_event(dd, event, false);
+               dock_hotplug_event(dd, event, DOCK_CALL_HANDLER);
 
        /*
-        * Now make sure that an acpi_device is created for each
-        * dependent device, or removed if this is an eject request.
-        * This will cause acpi_drivers to be stopped/started if they
-        * exist
+        * Now make sure that an acpi_device is created for each dependent
+        * device.  That will cause scan handlers to be attached to device
+        * objects or acpi_drivers to be stopped/started if they are present.
         */
-       list_for_each_entry(dd, &ds->dependent_devices, list) {
-               if (event == ACPI_NOTIFY_EJECT_REQUEST)
-                       dock_remove_acpi_device(dd->handle);
-               else
-                       dock_create_acpi_device(dd->handle);
-       }
-       mutex_unlock(&ds->hp_lock);
+       list_for_each_entry(dd, &ds->dependent_devices, list)
+               dock_create_acpi_device(dd->handle);
 }
 
 static void dock_event(struct dock_station *ds, u32 event, int num)
@@ -453,43 +423,12 @@ static void dock_event(struct dock_station *ds, u32 event, int num)
                kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
 
        list_for_each_entry(dd, &ds->dependent_devices, list)
-               dock_hotplug_event(dd, event, true);
+               dock_hotplug_event(dd, event, DOCK_CALL_UEVENT);
 
        if (num != DOCK_EVENT)
                kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
 }
 
-/**
- * eject_dock - respond to a dock eject request
- * @ds: the dock station
- *
- * This is called after _DCK is called, to execute the dock station's
- * _EJ0 method.
- */
-static void eject_dock(struct dock_station *ds)
-{
-       struct acpi_object_list arg_list;
-       union acpi_object arg;
-       acpi_status status;
-       acpi_handle tmp;
-
-       /* all dock devices should have _EJ0, but check anyway */
-       status = acpi_get_handle(ds->handle, "_EJ0", &tmp);
-       if (ACPI_FAILURE(status)) {
-               pr_debug("No _EJ0 support for dock device\n");
-               return;
-       }
-
-       arg_list.count = 1;
-       arg_list.pointer = &arg;
-       arg.type = ACPI_TYPE_INTEGER;
-       arg.integer.value = 1;
-
-       status = acpi_evaluate_object(ds->handle, "_EJ0", &arg_list, NULL);
-       if (ACPI_FAILURE(status))
-               pr_debug("Failed to evaluate _EJ0!\n");
-}
-
 /**
  * handle_dock - handle a dock event
  * @ds: the dock station
@@ -550,27 +489,6 @@ static inline void complete_undock(struct dock_station *ds)
        ds->flags &= ~(DOCK_UNDOCKING);
 }
 
-static void dock_lock(struct dock_station *ds, int lock)
-{
-       struct acpi_object_list arg_list;
-       union acpi_object arg;
-       acpi_status status;
-
-       arg_list.count = 1;
-       arg_list.pointer = &arg;
-       arg.type = ACPI_TYPE_INTEGER;
-       arg.integer.value = !!lock;
-       status = acpi_evaluate_object(ds->handle, "_LCK", &arg_list, NULL);
-       if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
-               if (lock)
-                       acpi_handle_warn(ds->handle,
-                               "Locking device failed (0x%x)\n", status);
-               else
-                       acpi_handle_warn(ds->handle,
-                               "Unlocking device failed (0x%x)\n", status);
-       }
-}
-
 /**
  * dock_in_progress - see if we are in the middle of handling a dock event
  * @ds: the dock station
@@ -587,37 +505,6 @@ static int dock_in_progress(struct dock_station *ds)
        return 0;
 }
 
-/**
- * register_dock_notifier - add yourself to the dock notifier list
- * @nb: the callers notifier block
- *
- * If a driver wishes to be notified about dock events, they can
- * use this function to put a notifier block on the dock notifier list.
- * this notifier call chain will be called after a dock event, but
- * before hotplugging any new devices.
- */
-int register_dock_notifier(struct notifier_block *nb)
-{
-       if (!dock_station_count)
-               return -ENODEV;
-
-       return atomic_notifier_chain_register(&dock_notifier_list, nb);
-}
-EXPORT_SYMBOL_GPL(register_dock_notifier);
-
-/**
- * unregister_dock_notifier - remove yourself from the dock notifier list
- * @nb: the callers notifier block
- */
-void unregister_dock_notifier(struct notifier_block *nb)
-{
-       if (!dock_station_count)
-               return;
-
-       atomic_notifier_chain_unregister(&dock_notifier_list, nb);
-}
-EXPORT_SYMBOL_GPL(unregister_dock_notifier);
-
 /**
  * register_hotplug_dock_device - register a hotplug function
  * @handle: the handle of the device
@@ -703,10 +590,10 @@ static int handle_eject_request(struct dock_station *ds, u32 event)
         */
        dock_event(ds, event, UNDOCK_EVENT);
 
-       hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST);
+       hot_remove_dock_devices(ds);
        undock(ds);
-       dock_lock(ds, 0);
-       eject_dock(ds);
+       acpi_evaluate_lck(ds->handle, 0);
+       acpi_evaluate_ej0(ds->handle);
        if (dock_present(ds)) {
                acpi_handle_err(ds->handle, "Unable to undock!\n");
                return -EBUSY;
@@ -717,18 +604,17 @@ static int handle_eject_request(struct dock_station *ds, u32 event)
 
 /**
  * dock_notify - act upon an acpi dock notification
- * @handle: the dock station handle
+ * @ds: dock station
  * @event: the acpi event
- * @data: our driver data struct
  *
  * If we are notified to dock, then check to see if the dock is
  * present and then dock.  Notify all drivers of the dock event,
  * and then hotplug and devices that may need hotplugging.
  */
-static void dock_notify(acpi_handle handle, u32 event, void *data)
+static void dock_notify(struct dock_station *ds, u32 event)
 {
-       struct dock_station *ds = data;
-       struct acpi_device *tmp;
+       acpi_handle handle = ds->handle;
+       struct acpi_device *ad;
        int surprise_removal = 0;
 
        /*
@@ -751,8 +637,7 @@ static void dock_notify(acpi_handle handle, u32 event, void *data)
        switch (event) {
        case ACPI_NOTIFY_BUS_CHECK:
        case ACPI_NOTIFY_DEVICE_CHECK:
-               if (!dock_in_progress(ds) && acpi_bus_get_device(ds->handle,
-                  &tmp)) {
+               if (!dock_in_progress(ds) && acpi_bus_get_device(handle, &ad)) {
                        begin_dock(ds);
                        dock(ds);
                        if (!dock_present(ds)) {
@@ -760,12 +645,10 @@ static void dock_notify(acpi_handle handle, u32 event, void *data)
                                complete_dock(ds);
                                break;
                        }
-                       atomic_notifier_call_chain(&dock_notifier_list,
-                                                  event, NULL);
                        hotplug_dock_devices(ds, event);
                        complete_dock(ds);
                        dock_event(ds, event, DOCK_EVENT);
-                       dock_lock(ds, 1);
+                       acpi_evaluate_lck(ds->handle, 1);
                        acpi_update_all_gpes();
                        break;
                }
@@ -789,9 +672,8 @@ static void dock_notify(acpi_handle handle, u32 event, void *data)
 }
 
 struct dock_data {
-       acpi_handle handle;
-       unsigned long event;
        struct dock_station *ds;
+       u32 event;
 };
 
 static void acpi_dock_deferred_cb(void *context)
@@ -799,52 +681,31 @@ static void acpi_dock_deferred_cb(void *context)
        struct dock_data *data = context;
 
        acpi_scan_lock_acquire();
-       dock_notify(data->handle, data->event, data->ds);
+       dock_notify(data->ds, data->event);
        acpi_scan_lock_release();
        kfree(data);
 }
 
-static int acpi_dock_notifier_call(struct notifier_block *this,
-       unsigned long event, void *data)
+static void dock_notify_handler(acpi_handle handle, u32 event, void *data)
 {
-       struct dock_station *dock_station;
-       acpi_handle handle = data;
+       struct dock_data *dd;
 
        if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK
           && event != ACPI_NOTIFY_EJECT_REQUEST)
-               return 0;
-
-       acpi_scan_lock_acquire();
-
-       list_for_each_entry(dock_station, &dock_stations, sibling) {
-               if (dock_station->handle == handle) {
-                       struct dock_data *dd;
-                       acpi_status status;
-
-                       dd = kmalloc(sizeof(*dd), GFP_KERNEL);
-                       if (!dd)
-                               break;
+               return;
 
-                       dd->handle = handle;
-                       dd->event = event;
-                       dd->ds = dock_station;
-                       status = acpi_os_hotplug_execute(acpi_dock_deferred_cb,
-                                                        dd);
-                       if (ACPI_FAILURE(status))
-                               kfree(dd);
+       dd = kmalloc(sizeof(*dd), GFP_KERNEL);
+       if (dd) {
+               acpi_status status;
 
-                       break;
-               }
+               dd->ds = data;
+               dd->event = event;
+               status = acpi_os_hotplug_execute(acpi_dock_deferred_cb, dd);
+               if (ACPI_FAILURE(status))
+                       kfree(dd);
        }
-
-       acpi_scan_lock_release();
-       return 0;
 }
 
-static struct notifier_block dock_acpi_notifier = {
-       .notifier_call = acpi_dock_notifier_call,
-};
-
 /**
  * find_dock_devices - find devices on the dock station
  * @handle: the handle of the device we are examining
@@ -856,29 +717,16 @@ static struct notifier_block dock_acpi_notifier = {
  * check to see if an object has an _EJD method.  If it does, then it
  * will see if it is dependent on the dock station.
  */
-static acpi_status
-find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv)
+static acpi_status __init find_dock_devices(acpi_handle handle, u32 lvl,
+                                           void *context, void **rv)
 {
-       acpi_status status;
-       acpi_handle tmp, parent;
        struct dock_station *ds = context;
+       acpi_handle ejd = NULL;
 
-       status = acpi_bus_get_ejd(handle, &tmp);
-       if (ACPI_FAILURE(status)) {
-               /* try the parent device as well */
-               status = acpi_get_parent(handle, &parent);
-               if (ACPI_FAILURE(status))
-                       goto fdd_out;
-               /* see if parent is dependent on dock */
-               status = acpi_bus_get_ejd(parent, &tmp);
-               if (ACPI_FAILURE(status))
-                       goto fdd_out;
-       }
-
-       if (tmp == ds->handle)
+       acpi_bus_get_ejd(handle, &ejd);
+       if (ejd == ds->handle)
                add_dock_dependent_device(ds, handle);
 
-fdd_out:
        return AE_OK;
 }
 
@@ -988,13 +836,13 @@ static struct attribute_group dock_attribute_group = {
  */
 static int __init dock_add(acpi_handle handle)
 {
-       int ret, id;
-       struct dock_station ds, *dock_station;
+       struct dock_station *dock_station, ds = { NULL, };
        struct platform_device *dd;
+       acpi_status status;
+       int ret;
 
-       id = dock_station_count;
-       memset(&ds, 0, sizeof(ds));
-       dd = platform_device_register_data(NULL, "dock", id, &ds, sizeof(ds));
+       dd = platform_device_register_data(NULL, "dock", dock_station_count,
+                                          &ds, sizeof(ds));
        if (IS_ERR(dd))
                return PTR_ERR(dd);
 
@@ -1004,18 +852,15 @@ static int __init dock_add(acpi_handle handle)
        dock_station->dock_device = dd;
        dock_station->last_dock_time = jiffies - HZ;
 
-       mutex_init(&dock_station->hp_lock);
-       spin_lock_init(&dock_station->dd_lock);
        INIT_LIST_HEAD(&dock_station->sibling);
-       ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
        INIT_LIST_HEAD(&dock_station->dependent_devices);
 
        /* we want the dock device to send uevents */
        dev_set_uevent_suppress(&dd->dev, 0);
 
-       if (is_dock(handle))
+       if (acpi_dock_match(handle))
                dock_station->flags |= DOCK_IS_DOCK;
-       if (is_ata(handle))
+       if (acpi_ata_match(handle))
                dock_station->flags |= DOCK_IS_ATA;
        if (is_battery(handle))
                dock_station->flags |= DOCK_IS_BAT;
@@ -1034,11 +879,19 @@ static int __init dock_add(acpi_handle handle)
        if (ret)
                goto err_rmgroup;
 
+       status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+                                            dock_notify_handler, dock_station);
+       if (ACPI_FAILURE(status)) {
+               ret = -ENODEV;
+               goto err_rmgroup;
+       }
+
        dock_station_count++;
        list_add(&dock_station->sibling, &dock_stations);
        return 0;
 
 err_rmgroup:
+       remove_dock_dependent_devices(dock_station);
        sysfs_remove_group(&dd->dev.kobj, &dock_attribute_group);
 err_unregister:
        platform_device_unregister(dd);
@@ -1058,7 +911,7 @@ err_unregister:
 static __init acpi_status
 find_dock_and_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
 {
-       if (is_dock(handle) || is_ejectable_bay(handle))
+       if (acpi_dock_match(handle) || is_ejectable_bay(handle))
                dock_add(handle);
 
        return AE_OK;
@@ -1078,7 +931,6 @@ void __init acpi_dock_init(void)
                return;
        }
 
-       register_acpi_bus_notifier(&dock_acpi_notifier);
        pr_info(PREFIX "%s: %d docks/bays found\n",
                ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count);
 }
index 80403c1a89f8969919c868e0fb3238e056adb581..84bf06cec1f203698f1ec042bc9aaad24c83e058 100644 (file)
@@ -1049,10 +1049,8 @@ int __init acpi_ec_ecdt_probe(void)
                * which needs it, has fake EC._INI method, so use it as flag.
                * Keep boot_ec struct as it will be needed soon.
                */
-               acpi_handle dummy;
                if (!dmi_name_in_vendors("ASUS") ||
-                   ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI",
-                                                       &dummy)))
+                   !acpi_has_method(boot_ec->handle, "_INI"))
                        return -ENODEV;
        }
 install:
index 1442737cedec784874fed04a74f251d543b1a61e..8247fcdde0795b37377bdec44d6271ca16ad225d 100644 (file)
 #define _COMPONENT             ACPI_SYSTEM_COMPONENT
 ACPI_MODULE_NAME("event");
 
-#ifdef CONFIG_ACPI_PROC_EVENT
-/* Global vars for handling event proc entry */
-static DEFINE_SPINLOCK(acpi_system_event_lock);
-int event_is_open = 0;
-extern struct list_head acpi_bus_event_list;
-extern wait_queue_head_t acpi_bus_event_queue;
-
-static int acpi_system_open_event(struct inode *inode, struct file *file)
-{
-       spin_lock_irq(&acpi_system_event_lock);
-
-       if (event_is_open)
-               goto out_busy;
-
-       event_is_open = 1;
-
-       spin_unlock_irq(&acpi_system_event_lock);
-       return 0;
-
-      out_busy:
-       spin_unlock_irq(&acpi_system_event_lock);
-       return -EBUSY;
-}
-
-static ssize_t
-acpi_system_read_event(struct file *file, char __user * buffer, size_t count,
-                      loff_t * ppos)
-{
-       int result = 0;
-       struct acpi_bus_event event;
-       static char str[ACPI_MAX_STRING];
-       static int chars_remaining = 0;
-       static char *ptr;
-
-       if (!chars_remaining) {
-               memset(&event, 0, sizeof(struct acpi_bus_event));
-
-               if ((file->f_flags & O_NONBLOCK)
-                   && (list_empty(&acpi_bus_event_list)))
-                       return -EAGAIN;
-
-               result = acpi_bus_receive_event(&event);
-               if (result)
-                       return result;
-
-               chars_remaining = sprintf(str, "%s %s %08x %08x\n",
-                                         event.device_class ? event.
-                                         device_class : "<unknown>",
-                                         event.bus_id ? event.
-                                         bus_id : "<unknown>", event.type,
-                                         event.data);
-               ptr = str;
-       }
-
-       if (chars_remaining < count) {
-               count = chars_remaining;
-       }
-
-       if (copy_to_user(buffer, ptr, count))
-               return -EFAULT;
-
-       *ppos += count;
-       chars_remaining -= count;
-       ptr += count;
-
-       return count;
-}
-
-static int acpi_system_close_event(struct inode *inode, struct file *file)
-{
-       spin_lock_irq(&acpi_system_event_lock);
-       event_is_open = 0;
-       spin_unlock_irq(&acpi_system_event_lock);
-       return 0;
-}
-
-static unsigned int acpi_system_poll_event(struct file *file, poll_table * wait)
-{
-       poll_wait(file, &acpi_bus_event_queue, wait);
-       if (!list_empty(&acpi_bus_event_list))
-               return POLLIN | POLLRDNORM;
-       return 0;
-}
-
-static const struct file_operations acpi_system_event_ops = {
-       .owner = THIS_MODULE,
-       .open = acpi_system_open_event,
-       .read = acpi_system_read_event,
-       .release = acpi_system_close_event,
-       .poll = acpi_system_poll_event,
-       .llseek = default_llseek,
-};
-#endif /* CONFIG_ACPI_PROC_EVENT */
-
 /* ACPI notifier chain */
 static BLOCKING_NOTIFIER_HEAD(acpi_chain_head);
 
@@ -280,9 +186,6 @@ static int acpi_event_genetlink_init(void)
 
 static int __init acpi_event_init(void)
 {
-#ifdef CONFIG_ACPI_PROC_EVENT
-       struct proc_dir_entry *entry;
-#endif
        int error = 0;
 
        if (acpi_disabled)
@@ -293,15 +196,6 @@ static int __init acpi_event_init(void)
        if (error)
                printk(KERN_WARNING PREFIX
                       "Failed to create genetlink family for ACPI event\n");
-
-#ifdef CONFIG_ACPI_PROC_EVENT
-       /* 'event' [R] */
-       entry = proc_create("event", S_IRUSR, acpi_root_dir,
-                           &acpi_system_event_ops);
-       if (!entry)
-               return -ENODEV;
-#endif
-
        return 0;
 }
 
index 5b02a0aa540cfa122ecfd8481d38162076cefbde..41ade6570bc07c22c3c40445d696aea26e4e4c41 100644 (file)
@@ -93,7 +93,7 @@ static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
        if (result)
                return result;
 
-       *state = (acpi_state == ACPI_STATE_D3 ? 0 :
+       *state = (acpi_state == ACPI_STATE_D3_COLD ? 0 :
                 (acpi_state == ACPI_STATE_D0 ? 1 : -1));
        return 0;
 }
@@ -108,7 +108,7 @@ fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
                return -EINVAL;
 
        result = acpi_bus_set_power(device->handle,
-                               state ? ACPI_STATE_D0 : ACPI_STATE_D3);
+                               state ? ACPI_STATE_D0 : ACPI_STATE_D3_COLD);
 
        return result;
 }
index 5da44e81dd4d70f7ed42ae1f1587734c0b6a5a55..20f423337e1fb73c66379a3771954741860c6d7d 100644 (file)
@@ -23,6 +23,7 @@
 
 #define PREFIX "ACPI: "
 
+acpi_status acpi_os_initialize1(void);
 int init_acpi_device_notify(void);
 int acpi_scan_init(void);
 #ifdef CONFIG_ACPI_PCI_SLOT
index 6ab2c350552061893ded7355d376406de5d98ed8..d6bc619512dc8dcb6f19b9fefb52d54b7cbaa848 100644 (file)
@@ -52,6 +52,7 @@
 #include <acpi/acpi.h>
 #include <acpi/acpi_bus.h>
 #include <acpi/processor.h>
+#include "internal.h"
 
 #define _COMPONENT             ACPI_OS_SERVICES
 ACPI_MODULE_NAME("osl");
@@ -79,6 +80,8 @@ extern char line_buf[80];
 
 static int (*__acpi_os_prepare_sleep)(u8 sleep_state, u32 pm1a_ctrl,
                                      u32 pm1b_ctrl);
+static int (*__acpi_os_prepare_extended_sleep)(u8 sleep_state, u32 val_a,
+                                     u32 val_b);
 
 static acpi_osd_handler acpi_irq_handler;
 static void *acpi_irq_context;
@@ -140,7 +143,8 @@ static struct osi_linux {
        unsigned int    enable:1;
        unsigned int    dmi:1;
        unsigned int    cmdline:1;
-} osi_linux = {0, 0, 0};
+       unsigned int    default_disabling:1;
+} osi_linux = {0, 0, 0, 0};
 
 static u32 acpi_osi_handler(acpi_string interface, u32 supported)
 {
@@ -1376,6 +1380,17 @@ void __init acpi_osi_setup(char *str)
 
        if (*str == '!') {
                str++;
+               if (*str == '\0') {
+                       osi_linux.default_disabling = 1;
+                       return;
+               } else if (*str == '*') {
+                       acpi_update_interfaces(ACPI_DISABLE_ALL_STRINGS);
+                       for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) {
+                               osi = &osi_setup_entries[i];
+                               osi->enable = false;
+                       }
+                       return;
+               }
                enable = false;
        }
 
@@ -1441,6 +1456,13 @@ static void __init acpi_osi_setup_late(void)
        int i;
        acpi_status status;
 
+       if (osi_linux.default_disabling) {
+               status = acpi_update_interfaces(ACPI_DISABLE_ALL_VENDOR_STRINGS);
+
+               if (ACPI_SUCCESS(status))
+                       printk(KERN_INFO PREFIX "Disabled all _OSI OS vendors\n");
+       }
+
        for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) {
                osi = &osi_setup_entries[i];
                str = osi->string;
@@ -1779,6 +1801,28 @@ void acpi_os_set_prepare_sleep(int (*func)(u8 sleep_state,
        __acpi_os_prepare_sleep = func;
 }
 
+acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state, u32 val_a,
+                                 u32 val_b)
+{
+       int rc = 0;
+       if (__acpi_os_prepare_extended_sleep)
+               rc = __acpi_os_prepare_extended_sleep(sleep_state,
+                                            val_a, val_b);
+       if (rc < 0)
+               return AE_ERROR;
+       else if (rc > 0)
+               return AE_CTRL_SKIP;
+
+       return AE_OK;
+}
+
+void acpi_os_set_prepare_extended_sleep(int (*func)(u8 sleep_state,
+                              u32 val_a, u32 val_b))
+{
+       __acpi_os_prepare_extended_sleep = func;
+}
+
+
 void alloc_acpi_hp_work(acpi_handle handle, u32 type, void *context,
                        void (*func)(struct work_struct *work))
 {
index 41c5e1b799ef938ff1eed92e4cf48a7c7677f8bd..9681847aa1d7c73c6de19e97f4b6140d95763ba9 100644 (file)
@@ -430,6 +430,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
                } else {
                        dev_warn(&dev->dev, "PCI INT %c: no GSI\n",
                                 pin_name(pin));
+                       return -ENOENT;
                }
 
                return 0;
index 033d1179bdb56bb0937e067cb907b9f4272f282d..d678a180ca2aa20cfac20d32460400dc0f05951f 100644 (file)
@@ -159,12 +159,16 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
        return AE_OK;
 }
 
-void acpi_pci_slot_enumerate(struct pci_bus *bus, acpi_handle handle)
+void acpi_pci_slot_enumerate(struct pci_bus *bus)
 {
-       mutex_lock(&slot_list_lock);
-       acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
-                           register_slot, NULL, bus, NULL);
-       mutex_unlock(&slot_list_lock);
+       acpi_handle handle = ACPI_HANDLE(bus->bridge);
+
+       if (handle) {
+               mutex_lock(&slot_list_lock);
+               acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
+                                   register_slot, NULL, bus, NULL);
+               mutex_unlock(&slot_list_lock);
+       }
 }
 
 void acpi_pci_slot_remove(struct pci_bus *bus)
index 5c28c894c0fc204925f489fdf988a01abb74bc88..0dbe5cdf3396e5f53b23c84bb30041329544774d 100644 (file)
@@ -637,9 +637,7 @@ int acpi_device_sleep_wake(struct acpi_device *dev,
        }
 
        /* Execute _PSW */
-       arg_list.count = 1;
-       in_arg[0].integer.value = enable;
-       status = acpi_evaluate_object(dev->handle, "_PSW", &arg_list, NULL);
+       status = acpi_execute_simple_method(dev->handle, "_PSW", enable);
        if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
                printk(KERN_ERR PREFIX "_PSW execution failed\n");
                dev->wakeup.flags.valid = 0;
@@ -786,7 +784,7 @@ int acpi_power_get_inferred_state(struct acpi_device *device, int *state)
                }
        }
 
-       *state = ACPI_STATE_D3;
+       *state = ACPI_STATE_D3_COLD;
        return 0;
 }
 
index 870eaf5fa547b935bdde1fe31a7bf31d2ab3d222..bd11ef93b0ceb943b821528b943579884b410c15 100644 (file)
@@ -91,21 +91,17 @@ static void acpi_processor_notify(acpi_handle handle, u32 event, void *data)
                acpi_processor_ppc_has_changed(pr, 1);
                if (saved == pr->performance_platform_limit)
                        break;
-               acpi_bus_generate_proc_event(device, event,
-                                       pr->performance_platform_limit);
                acpi_bus_generate_netlink_event(device->pnp.device_class,
                                                  dev_name(&device->dev), event,
                                                  pr->performance_platform_limit);
                break;
        case ACPI_PROCESSOR_NOTIFY_POWER:
                acpi_processor_cst_has_changed(pr);
-               acpi_bus_generate_proc_event(device, event, 0);
                acpi_bus_generate_netlink_event(device->pnp.device_class,
                                                  dev_name(&device->dev), event, 0);
                break;
        case ACPI_PROCESSOR_NOTIFY_THROTTLING:
                acpi_processor_tstate_has_changed(pr);
-               acpi_bus_generate_proc_event(device, event, 0);
                acpi_bus_generate_netlink_event(device->pnp.device_class,
                                                  dev_name(&device->dev), event, 0);
                break;
index 1e9732d809bf67ad19eee32f83617428291025b7..51d7948611da0ece22a9aedb6ecd598ba4e4526e 100644 (file)
@@ -164,17 +164,12 @@ static void acpi_processor_ppc_ost(acpi_handle handle, int status)
                {.type = ACPI_TYPE_INTEGER,},
        };
        struct acpi_object_list arg_list = {2, params};
-       acpi_handle temp;
 
-       params[0].integer.value = ACPI_PROCESSOR_NOTIFY_PERFORMANCE;
-       params[1].integer.value =  status;
-
-       /* when there is no _OST , skip it */
-       if (ACPI_FAILURE(acpi_get_handle(handle, "_OST", &temp)))
-               return;
-
-       acpi_evaluate_object(handle, "_OST", &arg_list, NULL);
-       return;
+       if (acpi_has_method(handle, "_OST")) {
+               params[0].integer.value = ACPI_PROCESSOR_NOTIFY_PERFORMANCE;
+               params[1].integer.value =  status;
+               acpi_evaluate_object(handle, "_OST", &arg_list, NULL);
+       }
 }
 
 int acpi_processor_ppc_has_changed(struct acpi_processor *pr, int event_flag)
@@ -468,14 +463,11 @@ static int acpi_processor_get_performance_states(struct acpi_processor *pr)
 int acpi_processor_get_performance_info(struct acpi_processor *pr)
 {
        int result = 0;
-       acpi_status status = AE_OK;
-       acpi_handle handle = NULL;
 
        if (!pr || !pr->performance || !pr->handle)
                return -EINVAL;
 
-       status = acpi_get_handle(pr->handle, "_PCT", &handle);
-       if (ACPI_FAILURE(status)) {
+       if (!acpi_has_method(pr->handle, "_PCT")) {
                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
                                  "ACPI-based processor performance control unavailable\n"));
                return -ENODEV;
@@ -501,7 +493,7 @@ int acpi_processor_get_performance_info(struct acpi_processor *pr)
         */
  update_bios:
 #ifdef CONFIG_X86
-       if (ACPI_SUCCESS(acpi_get_handle(pr->handle, "_PPC", &handle))){
+       if (acpi_has_method(pr->handle, "_PPC")) {
                if(boot_cpu_has(X86_FEATURE_EST))
                        printk(KERN_WARNING FW_BUG "BIOS needs update for CPU "
                               "frequency support\n");
index 3322b47ab7cae22dc08520b6cec9a3b1df981b84..b7201fc6f1e19c06c798889900c1e9c689494c8d 100644 (file)
@@ -505,14 +505,12 @@ int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list,
                           void *preproc_data)
 {
        struct res_proc_context c;
-       acpi_handle not_used;
        acpi_status status;
 
        if (!adev || !adev->handle || !list_empty(list))
                return -EINVAL;
 
-       status = acpi_get_handle(adev->handle, METHOD_NAME__CRS, &not_used);
-       if (ACPI_FAILURE(status))
+       if (!acpi_has_method(adev->handle, METHOD_NAME__CRS))
                return 0;
 
        c.list = list;
index b6241eeb1132a0b3afed934ba96f52545a4a1d13..aef7e1cd1e5d62f95512484935e4fea9b11af961 100644 (file)
@@ -873,14 +873,9 @@ static void acpi_sbs_callback(void *context)
        u8 saved_charger_state = sbs->charger_present;
        u8 saved_battery_state;
        acpi_ac_get_present(sbs);
-       if (sbs->charger_present != saved_charger_state) {
-#ifdef CONFIG_ACPI_PROC_EVENT
-               acpi_bus_generate_proc_event4(ACPI_AC_CLASS, ACPI_AC_DIR_NAME,
-                                             ACPI_SBS_NOTIFY_STATUS,
-                                             sbs->charger_present);
-#endif
+       if (sbs->charger_present != saved_charger_state)
                kobject_uevent(&sbs->charger.dev->kobj, KOBJ_CHANGE);
-       }
+
        if (sbs->manager_present) {
                for (id = 0; id < MAX_SBS_BAT; ++id) {
                        if (!(sbs->batteries_supported & (1 << id)))
@@ -890,12 +885,6 @@ static void acpi_sbs_callback(void *context)
                        acpi_battery_read(bat);
                        if (saved_battery_state == bat->present)
                                continue;
-#ifdef CONFIG_ACPI_PROC_EVENT
-                       acpi_bus_generate_proc_event4(ACPI_BATTERY_CLASS,
-                                                     bat->name,
-                                                     ACPI_SBS_NOTIFY_STATUS,
-                                                     bat->present);
-#endif
                        kobject_uevent(&bat->bat.dev->kobj, KOBJ_CHANGE);
                }
        }
index 8a46c924effd4e5bef09cb645429170e70ed380a..e76365136ba3500998ba9f7cd3a980fc78c92429 100644 (file)
@@ -193,9 +193,6 @@ static acpi_status acpi_bus_online_companions(acpi_handle handle, u32 lvl,
 static int acpi_scan_hot_remove(struct acpi_device *device)
 {
        acpi_handle handle = device->handle;
-       acpi_handle not_used;
-       struct acpi_object_list arg_list;
-       union acpi_object arg;
        struct device *errdev;
        acpi_status status;
        unsigned long long sta;
@@ -258,32 +255,15 @@ static int acpi_scan_hot_remove(struct acpi_device *device)
        put_device(&device->dev);
        device = NULL;
 
-       if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &not_used))) {
-               arg_list.count = 1;
-               arg_list.pointer = &arg;
-               arg.type = ACPI_TYPE_INTEGER;
-               arg.integer.value = 0;
-               acpi_evaluate_object(handle, "_LCK", &arg_list, NULL);
-       }
-
-       arg_list.count = 1;
-       arg_list.pointer = &arg;
-       arg.type = ACPI_TYPE_INTEGER;
-       arg.integer.value = 1;
-
+       acpi_evaluate_lck(handle, 0);
        /*
         * TBD: _EJD support.
         */
-       status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
-       if (ACPI_FAILURE(status)) {
-               if (status == AE_NOT_FOUND) {
-                       return -ENODEV;
-               } else {
-                       acpi_handle_warn(handle, "Eject failed (0x%x)\n",
-                                                               status);
-                       return -EIO;
-               }
-       }
+       status = acpi_evaluate_ej0(handle);
+       if (status == AE_NOT_FOUND)
+               return -ENODEV;
+       else if (ACPI_FAILURE(status))
+               return -EIO;
 
        /*
         * Verify if eject was indeed successful.  If not, log an error
@@ -654,7 +634,6 @@ static int acpi_device_setup_files(struct acpi_device *dev)
 {
        struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
        acpi_status status;
-       acpi_handle temp;
        unsigned long long sun;
        int result = 0;
 
@@ -680,8 +659,7 @@ static int acpi_device_setup_files(struct acpi_device *dev)
        /*
         * If device has _STR, 'description' file is created
         */
-       status = acpi_get_handle(dev->handle, "_STR", &temp);
-       if (ACPI_SUCCESS(status)) {
+       if (acpi_has_method(dev->handle, "_STR")) {
                status = acpi_evaluate_object(dev->handle, "_STR",
                                        NULL, &buffer);
                if (ACPI_FAILURE(status))
@@ -711,8 +689,7 @@ static int acpi_device_setup_files(struct acpi_device *dev)
          * If device has _EJ0, 'eject' file is created that is used to trigger
          * hot-removal function from userland.
          */
-       status = acpi_get_handle(dev->handle, "_EJ0", &temp);
-       if (ACPI_SUCCESS(status)) {
+       if (acpi_has_method(dev->handle, "_EJ0")) {
                result = device_create_file(&dev->dev, &dev_attr_eject);
                if (result)
                        return result;
@@ -734,9 +711,6 @@ end:
 
 static void acpi_device_remove_files(struct acpi_device *dev)
 {
-       acpi_status status;
-       acpi_handle temp;
-
        if (dev->flags.power_manageable) {
                device_remove_file(&dev->dev, &dev_attr_power_state);
                if (dev->power.flags.power_resources)
@@ -747,20 +721,17 @@ static void acpi_device_remove_files(struct acpi_device *dev)
        /*
         * If device has _STR, remove 'description' file
         */
-       status = acpi_get_handle(dev->handle, "_STR", &temp);
-       if (ACPI_SUCCESS(status)) {
+       if (acpi_has_method(dev->handle, "_STR")) {
                kfree(dev->pnp.str_obj);
                device_remove_file(&dev->dev, &dev_attr_description);
        }
        /*
         * If device has _EJ0, remove 'eject' file.
         */
-       status = acpi_get_handle(dev->handle, "_EJ0", &temp);
-       if (ACPI_SUCCESS(status))
+       if (acpi_has_method(dev->handle, "_EJ0"))
                device_remove_file(&dev->dev, &dev_attr_eject);
 
-       status = acpi_get_handle(dev->handle, "_SUN", &temp);
-       if (ACPI_SUCCESS(status))
+       if (acpi_has_method(dev->handle, "_SUN"))
                device_remove_file(&dev->dev, &dev_attr_sun);
 
        if (dev->pnp.unique_id)
@@ -999,6 +970,28 @@ struct bus_type acpi_bus_type = {
        .uevent         = acpi_device_uevent,
 };
 
+static void acpi_bus_data_handler(acpi_handle handle, void *context)
+{
+       /* Intentionally empty. */
+}
+
+int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
+{
+       acpi_status status;
+
+       if (!device)
+               return -EINVAL;
+
+       status = acpi_get_data(handle, acpi_bus_data_handler, (void **)device);
+       if (ACPI_FAILURE(status) || !*device) {
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n",
+                                 handle));
+               return -ENODEV;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(acpi_bus_get_device);
+
 int acpi_device_add(struct acpi_device *device,
                    void (*release)(struct device *))
 {
@@ -1210,14 +1203,6 @@ acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd)
 }
 EXPORT_SYMBOL_GPL(acpi_bus_get_ejd);
 
-void acpi_bus_data_handler(acpi_handle handle, void *context)
-{
-
-       /* TBD */
-
-       return;
-}
-
 static int acpi_bus_extract_wakeup_device_power_package(acpi_handle handle,
                                        struct acpi_device_wakeup *wakeup)
 {
@@ -1336,13 +1321,10 @@ static void acpi_bus_set_run_wake_flags(struct acpi_device *device)
 
 static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
 {
-       acpi_handle temp;
-       acpi_status status = 0;
        int err;
 
        /* Presence of _PRW indicates wake capable */
-       status = acpi_get_handle(device->handle, "_PRW", &temp);
-       if (ACPI_FAILURE(status))
+       if (!acpi_has_method(device->handle, "_PRW"))
                return;
 
        err = acpi_bus_extract_wakeup_device_power_package(device->handle,
@@ -1372,7 +1354,6 @@ static void acpi_bus_init_power_state(struct acpi_device *device, int state)
        struct acpi_device_power_state *ps = &device->power.states[state];
        char pathname[5] = { '_', 'P', 'R', '0' + state, '\0' };
        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-       acpi_handle handle;
        acpi_status status;
 
        INIT_LIST_HEAD(&ps->resources);
@@ -1395,8 +1376,7 @@ static void acpi_bus_init_power_state(struct acpi_device *device, int state)
 
        /* Evaluate "_PSx" to see if we can do explicit sets */
        pathname[2] = 'S';
-       status = acpi_get_handle(device->handle, pathname, &handle);
-       if (ACPI_SUCCESS(status))
+       if (acpi_has_method(device->handle, pathname))
                ps->flags.explicit_set = 1;
 
        /*
@@ -1415,28 +1395,21 @@ static void acpi_bus_init_power_state(struct acpi_device *device, int state)
 
 static void acpi_bus_get_power_flags(struct acpi_device *device)
 {
-       acpi_status status;
-       acpi_handle handle;
        u32 i;
 
        /* Presence of _PS0|_PR0 indicates 'power manageable' */
-       status = acpi_get_handle(device->handle, "_PS0", &handle);
-       if (ACPI_FAILURE(status)) {
-               status = acpi_get_handle(device->handle, "_PR0", &handle);
-               if (ACPI_FAILURE(status))
-                       return;
-       }
+       if (!acpi_has_method(device->handle, "_PS0") &&
+           !acpi_has_method(device->handle, "_PR0"))
+               return;
 
        device->flags.power_manageable = 1;
 
        /*
         * Power Management Flags
         */
-       status = acpi_get_handle(device->handle, "_PSC", &handle);
-       if (ACPI_SUCCESS(status))
+       if (acpi_has_method(device->handle, "_PSC"))
                device->power.flags.explicit_get = 1;
-       status = acpi_get_handle(device->handle, "_IRC", &handle);
-       if (ACPI_SUCCESS(status))
+       if (acpi_has_method(device->handle, "_IRC"))
                device->power.flags.inrush_current = 1;
 
        /*
@@ -1450,8 +1423,8 @@ static void acpi_bus_get_power_flags(struct acpi_device *device)
        /* Set defaults for D0 and D3 states (always valid) */
        device->power.states[ACPI_STATE_D0].flags.valid = 1;
        device->power.states[ACPI_STATE_D0].power = 100;
-       device->power.states[ACPI_STATE_D3].flags.valid = 1;
-       device->power.states[ACPI_STATE_D3].power = 0;
+       device->power.states[ACPI_STATE_D3_COLD].flags.valid = 1;
+       device->power.states[ACPI_STATE_D3_COLD].power = 0;
 
        /* Set D3cold's explicit_set flag if _PS3 exists. */
        if (device->power.states[ACPI_STATE_D3_HOT].flags.explicit_set)
@@ -1470,28 +1443,18 @@ static void acpi_bus_get_power_flags(struct acpi_device *device)
 
 static void acpi_bus_get_flags(struct acpi_device *device)
 {
-       acpi_status status = AE_OK;
-       acpi_handle temp = NULL;
-
        /* Presence of _STA indicates 'dynamic_status' */
-       status = acpi_get_handle(device->handle, "_STA", &temp);
-       if (ACPI_SUCCESS(status))
+       if (acpi_has_method(device->handle, "_STA"))
                device->flags.dynamic_status = 1;
 
        /* Presence of _RMV indicates 'removable' */
-       status = acpi_get_handle(device->handle, "_RMV", &temp);
-       if (ACPI_SUCCESS(status))
+       if (acpi_has_method(device->handle, "_RMV"))
                device->flags.removable = 1;
 
        /* Presence of _EJD|_EJ0 indicates 'ejectable' */
-       status = acpi_get_handle(device->handle, "_EJD", &temp);
-       if (ACPI_SUCCESS(status))
+       if (acpi_has_method(device->handle, "_EJD") ||
+           acpi_has_method(device->handle, "_EJ0"))
                device->flags.ejectable = 1;
-       else {
-               status = acpi_get_handle(device->handle, "_EJ0", &temp);
-               if (ACPI_SUCCESS(status))
-                       device->flags.ejectable = 1;
-       }
 }
 
 static void acpi_device_get_busid(struct acpi_device *device)
@@ -1532,47 +1495,46 @@ static void acpi_device_get_busid(struct acpi_device *device)
        }
 }
 
+/*
+ * acpi_ata_match - see if an acpi object is an ATA device
+ *
+ * If an acpi object has one of the ACPI ATA methods defined,
+ * then we can safely call it an ATA device.
+ */
+bool acpi_ata_match(acpi_handle handle)
+{
+       return acpi_has_method(handle, "_GTF") ||
+              acpi_has_method(handle, "_GTM") ||
+              acpi_has_method(handle, "_STM") ||
+              acpi_has_method(handle, "_SDD");
+}
+
 /*
  * acpi_bay_match - see if an acpi object is an ejectable driver bay
  *
  * If an acpi object is ejectable and has one of the ACPI ATA methods defined,
  * then we can safely call it an ejectable drive bay
  */
-static int acpi_bay_match(acpi_handle handle)
+bool acpi_bay_match(acpi_handle handle)
 {
-       acpi_status status;
-       acpi_handle tmp;
        acpi_handle phandle;
 
-       status = acpi_get_handle(handle, "_EJ0", &tmp);
-       if (ACPI_FAILURE(status))
-               return -ENODEV;
-
-       if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) ||
-               (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) ||
-               (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) ||
-               (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp))))
-               return 0;
+       if (!acpi_has_method(handle, "_EJ0"))
+               return false;
+       if (acpi_ata_match(handle))
+               return true;
+       if (ACPI_FAILURE(acpi_get_parent(handle, &phandle)))
+               return false;
 
-       if (acpi_get_parent(handle, &phandle))
-               return -ENODEV;
-
-        if ((ACPI_SUCCESS(acpi_get_handle(phandle, "_GTF", &tmp))) ||
-                (ACPI_SUCCESS(acpi_get_handle(phandle, "_GTM", &tmp))) ||
-                (ACPI_SUCCESS(acpi_get_handle(phandle, "_STM", &tmp))) ||
-                (ACPI_SUCCESS(acpi_get_handle(phandle, "_SDD", &tmp))))
-                return 0;
-
-       return -ENODEV;
+       return acpi_ata_match(phandle);
 }
 
 /*
  * acpi_dock_match - see if an acpi object has a _DCK method
  */
-static int acpi_dock_match(acpi_handle handle)
+bool acpi_dock_match(acpi_handle handle)
 {
-       acpi_handle tmp;
-       return acpi_get_handle(handle, "_DCK", &tmp);
+       return acpi_has_method(handle, "_DCK");
 }
 
 const char *acpi_device_hid(struct acpi_device *device)
@@ -1610,34 +1572,26 @@ static void acpi_add_id(struct acpi_device_pnp *pnp, const char *dev_id)
  * lacks the SMBUS01 HID and the methods do not have the necessary "_"
  * prefix.  Work around this.
  */
-static int acpi_ibm_smbus_match(acpi_handle handle)
+static bool acpi_ibm_smbus_match(acpi_handle handle)
 {
-       acpi_handle h_dummy;
-       struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL};
-       int result;
+       char node_name[ACPI_PATH_SEGMENT_LENGTH];
+       struct acpi_buffer path = { sizeof(node_name), node_name };
 
        if (!dmi_name_in_vendors("IBM"))
-               return -ENODEV;
+               return false;
 
        /* Look for SMBS object */
-       result = acpi_get_name(handle, ACPI_SINGLE_NAME, &path);
-       if (result)
-               return result;
-
-       if (strcmp("SMBS", path.pointer)) {
-               result = -ENODEV;
-               goto out;
-       }
+       if (ACPI_FAILURE(acpi_get_name(handle, ACPI_SINGLE_NAME, &path)) ||
+           strcmp("SMBS", path.pointer))
+               return false;
 
        /* Does it have the necessary (but misnamed) methods? */
-       result = -ENODEV;
-       if (ACPI_SUCCESS(acpi_get_handle(handle, "SBI", &h_dummy)) &&
-           ACPI_SUCCESS(acpi_get_handle(handle, "SBR", &h_dummy)) &&
-           ACPI_SUCCESS(acpi_get_handle(handle, "SBW", &h_dummy)))
-               result = 0;
-out:
-       kfree(path.pointer);
-       return result;
+       if (acpi_has_method(handle, "SBI") &&
+           acpi_has_method(handle, "SBR") &&
+           acpi_has_method(handle, "SBW"))
+               return true;
+
+       return false;
 }
 
 static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
@@ -1685,11 +1639,11 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
                 */
                if (acpi_is_video_device(handle))
                        acpi_add_id(pnp, ACPI_VIDEO_HID);
-               else if (ACPI_SUCCESS(acpi_bay_match(handle)))
+               else if (acpi_bay_match(handle))
                        acpi_add_id(pnp, ACPI_BAY_HID);
-               else if (ACPI_SUCCESS(acpi_dock_match(handle)))
+               else if (acpi_dock_match(handle))
                        acpi_add_id(pnp, ACPI_DOCK_HID);
-               else if (!acpi_ibm_smbus_match(handle))
+               else if (acpi_ibm_smbus_match(handle))
                        acpi_add_id(pnp, ACPI_SMBUS_IBM_HID);
                else if (list_empty(&pnp->ids) && handle == ACPI_ROOT_OBJECT) {
                        acpi_add_id(pnp, ACPI_BUS_HID); /* \_SB, LNXSYBUS */
@@ -1900,7 +1854,6 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
        struct acpi_device *device = NULL;
        int type;
        unsigned long long sta;
-       acpi_status status;
        int result;
 
        acpi_bus_get_device(handle, &device);
@@ -1921,10 +1874,8 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
        if (!(sta & ACPI_STA_DEVICE_PRESENT) &&
            !(sta & ACPI_STA_DEVICE_FUNCTIONING)) {
                struct acpi_device_wakeup wakeup;
-               acpi_handle temp;
 
-               status = acpi_get_handle(handle, "_PRW", &temp);
-               if (ACPI_SUCCESS(status)) {
+               if (acpi_has_method(handle, "_PRW")) {
                        acpi_bus_extract_wakeup_device_power_package(handle,
                                                                     &wakeup);
                        acpi_power_resources_list_free(&wakeup.resources);
index 187ab61889e6da5fab9312e987a620a4cb212280..81b0f03d97db75a66fa649ec6ce505f5c0a6afb8 100644 (file)
@@ -31,12 +31,9 @@ static u8 sleep_states[ACPI_S_STATE_COUNT];
 
 static void acpi_sleep_tts_switch(u32 acpi_state)
 {
-       union acpi_object in_arg = { ACPI_TYPE_INTEGER };
-       struct acpi_object_list arg_list = { 1, &in_arg };
-       acpi_status status = AE_OK;
+       acpi_status status;
 
-       in_arg.integer.value = acpi_state;
-       status = acpi_evaluate_object(NULL, "\\_TTS", &arg_list, NULL);
+       status = acpi_execute_simple_method(NULL, "\\_TTS", acpi_state);
        if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
                /*
                 * OS can't evaluate the _TTS object correctly. Some warning
index a33821ca3895e672a32d1d145aca7108751667e5..a3e38a0a056bff8b1987ff8ca2b9f40d83b93d77 100644 (file)
@@ -239,26 +239,16 @@ static int acpi_thermal_get_polling_frequency(struct acpi_thermal *tz)
 
 static int acpi_thermal_set_cooling_mode(struct acpi_thermal *tz, int mode)
 {
-       acpi_status status = AE_OK;
-       union acpi_object arg0 = { ACPI_TYPE_INTEGER };
-       struct acpi_object_list arg_list = { 1, &arg0 };
-       acpi_handle handle = NULL;
-
-
        if (!tz)
                return -EINVAL;
 
-       status = acpi_get_handle(tz->device->handle, "_SCP", &handle);
-       if (ACPI_FAILURE(status)) {
+       if (!acpi_has_method(tz->device->handle, "_SCP")) {
                ACPI_DEBUG_PRINT((ACPI_DB_INFO, "_SCP not present\n"));
                return -ENODEV;
-       }
-
-       arg0.integer.value = mode;
-
-       status = acpi_evaluate_object(handle, NULL, &arg_list, NULL);
-       if (ACPI_FAILURE(status))
+       } else if (ACPI_FAILURE(acpi_execute_simple_method(tz->device->handle,
+                                                          "_SCP", mode))) {
                return -ENODEV;
+       }
 
        return 0;
 }
@@ -769,7 +759,6 @@ static int thermal_notify(struct thermal_zone_device *thermal, int trip,
        else
                return 0;
 
-       acpi_bus_generate_proc_event(tz->device, type, 1);
        acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
                                        dev_name(&tz->device->dev), type, 1);
 
@@ -980,14 +969,12 @@ static void acpi_thermal_notify(struct acpi_device *device, u32 event)
        case ACPI_THERMAL_NOTIFY_THRESHOLDS:
                acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_THRESHOLDS);
                acpi_thermal_check(tz);
-               acpi_bus_generate_proc_event(device, event, 0);
                acpi_bus_generate_netlink_event(device->pnp.device_class,
                                                  dev_name(&device->dev), event, 0);
                break;
        case ACPI_THERMAL_NOTIFY_DEVICES:
                acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_DEVICES);
                acpi_thermal_check(tz);
-               acpi_bus_generate_proc_event(device, event, 0);
                acpi_bus_generate_netlink_event(device->pnp.device_class,
                                                  dev_name(&device->dev), event, 0);
                break;
index 74437130431359005374a44529bab0c801918f3a..552248b0005b01a241ab511e52eef08a1c15d244 100644 (file)
@@ -495,3 +495,73 @@ acpi_handle_printk(const char *level, acpi_handle handle, const char *fmt, ...)
        kfree(buffer.pointer);
 }
 EXPORT_SYMBOL(acpi_handle_printk);
+
+/**
+ * acpi_has_method: Check whether @handle has a method named @name
+ * @handle: ACPI device handle
+ * @name: name of object or method
+ *
+ * Check whether @handle has a method named @name.
+ */
+bool acpi_has_method(acpi_handle handle, char *name)
+{
+       acpi_handle tmp;
+
+       return ACPI_SUCCESS(acpi_get_handle(handle, name, &tmp));
+}
+EXPORT_SYMBOL(acpi_has_method);
+
+acpi_status acpi_execute_simple_method(acpi_handle handle, char *method,
+                                      u64 arg)
+{
+       union acpi_object obj = { .type = ACPI_TYPE_INTEGER };
+       struct acpi_object_list arg_list = { .count = 1, .pointer = &obj, };
+
+       obj.integer.value = arg;
+
+       return acpi_evaluate_object(handle, method, &arg_list, NULL);
+}
+EXPORT_SYMBOL(acpi_execute_simple_method);
+
+/**
+ * acpi_evaluate_ej0: Evaluate _EJ0 method for hotplug operations
+ * @handle: ACPI device handle
+ *
+ * Evaluate device's _EJ0 method for hotplug operations.
+ */
+acpi_status acpi_evaluate_ej0(acpi_handle handle)
+{
+       acpi_status status;
+
+       status = acpi_execute_simple_method(handle, "_EJ0", 1);
+       if (status == AE_NOT_FOUND)
+               acpi_handle_warn(handle, "No _EJ0 support for device\n");
+       else if (ACPI_FAILURE(status))
+               acpi_handle_warn(handle, "Eject failed (0x%x)\n", status);
+
+       return status;
+}
+
+/**
+ * acpi_evaluate_lck: Evaluate _LCK method to lock/unlock device
+ * @handle: ACPI device handle
+ * @lock: lock device if non-zero, otherwise unlock device
+ *
+ * Evaluate device's _LCK method if present to lock/unlock device
+ */
+acpi_status acpi_evaluate_lck(acpi_handle handle, int lock)
+{
+       acpi_status status;
+
+       status = acpi_execute_simple_method(handle, "_LCK", !!lock);
+       if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+               if (lock)
+                       acpi_handle_warn(handle,
+                               "Locking device failed (0x%x)\n", status);
+               else
+                       acpi_handle_warn(handle,
+                               "Unlocking device failed (0x%x)\n", status);
+       }
+
+       return status;
+}
index 0ec434d2586da29d65003aed0b7d9c7dd244944e..dd4e5afdc96466b1cb1ec43664fac9bc8f3230d0 100644 (file)
@@ -355,14 +355,10 @@ static int
 acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level)
 {
        int status;
-       union acpi_object arg0 = { ACPI_TYPE_INTEGER };
-       struct acpi_object_list args = { 1, &arg0 };
        int state;
 
-       arg0.integer.value = level;
-
-       status = acpi_evaluate_object(device->dev->handle, "_BCM",
-                                     &args, NULL);
+       status = acpi_execute_simple_method(device->dev->handle,
+                                           "_BCM", level);
        if (ACPI_FAILURE(status)) {
                ACPI_ERROR((AE_INFO, "Evaluating _BCM failed"));
                return -EIO;
@@ -638,18 +634,15 @@ static int
 acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag)
 {
        acpi_status status;
-       union acpi_object arg0 = { ACPI_TYPE_INTEGER };
-       struct acpi_object_list args = { 1, &arg0 };
 
        if (!video->cap._DOS)
                return 0;
 
        if (bios_flag < 0 || bios_flag > 3 || lcd_flag < 0 || lcd_flag > 1)
                return -EINVAL;
-       arg0.integer.value = (lcd_flag << 2) | bios_flag;
-       video->dos_setting = arg0.integer.value;
-       status = acpi_evaluate_object(video->device->handle, "_DOS",
-               &args, NULL);
+       video->dos_setting = (lcd_flag << 2) | bios_flag;
+       status = acpi_execute_simple_method(video->device->handle, "_DOS",
+                                           (lcd_flag << 2) | bios_flag);
        if (ACPI_FAILURE(status))
                return -EIO;
 
@@ -885,28 +878,21 @@ out:
 
 static void acpi_video_device_find_cap(struct acpi_video_device *device)
 {
-       acpi_handle h_dummy1;
-
-       if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_ADR", &h_dummy1))) {
+       if (acpi_has_method(device->dev->handle, "_ADR"))
                device->cap._ADR = 1;
-       }
-       if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCL", &h_dummy1))) {
+       if (acpi_has_method(device->dev->handle, "_BCL"))
                device->cap._BCL = 1;
-       }
-       if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCM", &h_dummy1))) {
+       if (acpi_has_method(device->dev->handle, "_BCM"))
                device->cap._BCM = 1;
-       }
-       if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle,"_BQC",&h_dummy1)))
+       if (acpi_has_method(device->dev->handle, "_BQC")) {
                device->cap._BQC = 1;
-       else if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCQ",
-                               &h_dummy1))) {
+       } else if (acpi_has_method(device->dev->handle, "_BCQ")) {
                printk(KERN_WARNING FW_BUG "_BCQ is used instead of _BQC\n");
                device->cap._BCQ = 1;
        }
 
-       if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DDC", &h_dummy1))) {
+       if (acpi_has_method(device->dev->handle, "_DDC"))
                device->cap._DDC = 1;
-       }
 
        if (acpi_video_init_brightness(device))
                return;
@@ -999,26 +985,18 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
 
 static void acpi_video_bus_find_cap(struct acpi_video_bus *video)
 {
-       acpi_handle h_dummy1;
-
-       if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_DOS", &h_dummy1))) {
+       if (acpi_has_method(video->device->handle, "_DOS"))
                video->cap._DOS = 1;
-       }
-       if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_DOD", &h_dummy1))) {
+       if (acpi_has_method(video->device->handle, "_DOD"))
                video->cap._DOD = 1;
-       }
-       if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_ROM", &h_dummy1))) {
+       if (acpi_has_method(video->device->handle, "_ROM"))
                video->cap._ROM = 1;
-       }
-       if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_GPD", &h_dummy1))) {
+       if (acpi_has_method(video->device->handle, "_GPD"))
                video->cap._GPD = 1;
-       }
-       if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_SPD", &h_dummy1))) {
+       if (acpi_has_method(video->device->handle, "_SPD"))
                video->cap._SPD = 1;
-       }
-       if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_VPO", &h_dummy1))) {
+       if (acpi_has_method(video->device->handle, "_VPO"))
                video->cap._VPO = 1;
-       }
 }
 
 /*
@@ -1577,7 +1555,6 @@ static void acpi_video_bus_notify(struct acpi_device *device, u32 event)
        switch (event) {
        case ACPI_VIDEO_NOTIFY_SWITCH:  /* User requested a switch,
                                         * most likely via hotkey. */
-               acpi_bus_generate_proc_event(device, event, 0);
                keycode = KEY_SWITCHVIDEOMODE;
                break;
 
@@ -1585,20 +1562,16 @@ static void acpi_video_bus_notify(struct acpi_device *device, u32 event)
                                         * connector. */
                acpi_video_device_enumerate(video);
                acpi_video_device_rebind(video);
-               acpi_bus_generate_proc_event(device, event, 0);
                keycode = KEY_SWITCHVIDEOMODE;
                break;
 
        case ACPI_VIDEO_NOTIFY_CYCLE:   /* Cycle Display output hotkey pressed. */
-               acpi_bus_generate_proc_event(device, event, 0);
                keycode = KEY_SWITCHVIDEOMODE;
                break;
        case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT:     /* Next Display output hotkey pressed. */
-               acpi_bus_generate_proc_event(device, event, 0);
                keycode = KEY_VIDEO_NEXT;
                break;
        case ACPI_VIDEO_NOTIFY_PREV_OUTPUT:     /* previous Display output hotkey pressed. */
-               acpi_bus_generate_proc_event(device, event, 0);
                keycode = KEY_VIDEO_PREV;
                break;
 
@@ -1641,31 +1614,26 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
        case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS:        /* Cycle brightness */
                if (brightness_switch_enabled)
                        acpi_video_switch_brightness(video_device, event);
-               acpi_bus_generate_proc_event(device, event, 0);
                keycode = KEY_BRIGHTNESS_CYCLE;
                break;
        case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS:  /* Increase brightness */
                if (brightness_switch_enabled)
                        acpi_video_switch_brightness(video_device, event);
-               acpi_bus_generate_proc_event(device, event, 0);
                keycode = KEY_BRIGHTNESSUP;
                break;
        case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS:  /* Decrease brightness */
                if (brightness_switch_enabled)
                        acpi_video_switch_brightness(video_device, event);
-               acpi_bus_generate_proc_event(device, event, 0);
                keycode = KEY_BRIGHTNESSDOWN;
                break;
        case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: /* zero brightness */
                if (brightness_switch_enabled)
                        acpi_video_switch_brightness(video_device, event);
-               acpi_bus_generate_proc_event(device, event, 0);
                keycode = KEY_BRIGHTNESS_ZERO;
                break;
        case ACPI_VIDEO_NOTIFY_DISPLAY_OFF:     /* display device off */
                if (brightness_switch_enabled)
                        acpi_video_switch_brightness(video_device, event);
-               acpi_bus_generate_proc_event(device, event, 0);
                keycode = KEY_DISPLAY_OFF;
                break;
        default:
index c3397748ba466ca13f41c664b4c374c7dea5d028..940edbf2fe8f4460b27fceb1e7fe5fdb7cbacfc3 100644 (file)
@@ -53,14 +53,13 @@ acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context,
                          void **retyurn_value)
 {
        long *cap = context;
-       acpi_handle h_dummy;
 
-       if (ACPI_SUCCESS(acpi_get_handle(handle, "_BCM", &h_dummy)) &&
-           ACPI_SUCCESS(acpi_get_handle(handle, "_BCL", &h_dummy))) {
+       if (acpi_has_method(handle, "_BCM") &&
+           acpi_has_method(handle, "_BCL")) {
                ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found generic backlight "
                                  "support\n"));
                *cap |= ACPI_VIDEO_BACKLIGHT;
-               if (ACPI_FAILURE(acpi_get_handle(handle, "_BQC", &h_dummy)))
+               if (!acpi_has_method(handle, "_BQC"))
                        printk(KERN_WARNING FW_BUG PREFIX "No _BQC method, "
                                "cannot determine initial brightness\n");
                /* We have backlight support, no need to scan further */
@@ -79,22 +78,20 @@ acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context,
  */
 long acpi_is_video_device(acpi_handle handle)
 {
-       acpi_handle h_dummy;
        long video_caps = 0;
 
        /* Is this device able to support video switching ? */
-       if (ACPI_SUCCESS(acpi_get_handle(handle, "_DOD", &h_dummy)) ||
-           ACPI_SUCCESS(acpi_get_handle(handle, "_DOS", &h_dummy)))
+       if (acpi_has_method(handle, "_DOD") || acpi_has_method(handle, "_DOS"))
                video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING;
 
        /* Is this device able to retrieve a video ROM ? */
-       if (ACPI_SUCCESS(acpi_get_handle(handle, "_ROM", &h_dummy)))
+       if (acpi_has_method(handle, "_ROM"))
                video_caps |= ACPI_VIDEO_ROM_AVAILABLE;
 
        /* Is this device able to configure which video head to be POSTed ? */
-       if (ACPI_SUCCESS(acpi_get_handle(handle, "_VPO", &h_dummy)) &&
-           ACPI_SUCCESS(acpi_get_handle(handle, "_GPD", &h_dummy)) &&
-           ACPI_SUCCESS(acpi_get_handle(handle, "_SPD", &h_dummy)))
+       if (acpi_has_method(handle, "_VPO") &&
+           acpi_has_method(handle, "_GPD") &&
+           acpi_has_method(handle, "_SPD"))
                video_caps |= ACPI_VIDEO_DEVICE_POSTING;
 
        /* Only check for backlight functionality if one of the above hit. */
index cf4e7020adacde5e69881a21adb0c578d31d7a3e..da8170dfc90f142d8924de9c10be76444acbb250 100644 (file)
@@ -947,11 +947,11 @@ static void pata_acpi_set_state(struct ata_port *ap, pm_message_t state)
                        continue;
 
                acpi_bus_set_power(dev_handle, state.event & PM_EVENT_RESUME ?
-                                               ACPI_STATE_D0 : ACPI_STATE_D3);
+                                       ACPI_STATE_D0 : ACPI_STATE_D3_COLD);
        }
 
        if (!(state.event & PM_EVENT_RESUME))
-               acpi_bus_set_power(port_handle, ACPI_STATE_D3);
+               acpi_bus_set_power(port_handle, ACPI_STATE_D3_COLD);
 }
 
 /**
index 577d902bc4deaa12d69d1acdc8aa304732163227..cc8a6e879dfb7eeac203b294a38c97163ff90d23 100644 (file)
@@ -120,8 +120,6 @@ extern void ata_acpi_on_disable(struct ata_device *dev);
 extern void ata_acpi_set_state(struct ata_port *ap, pm_message_t state);
 extern int ata_acpi_register(void);
 extern void ata_acpi_unregister(void);
-extern void ata_acpi_bind(struct ata_device *dev);
-extern void ata_acpi_unbind(struct ata_device *dev);
 extern void ata_acpi_hotplug_init(struct ata_host *host);
 #else
 static inline void ata_acpi_dissociate(struct ata_host *host) { }
@@ -133,8 +131,6 @@ static inline void ata_acpi_set_state(struct ata_port *ap,
                                      pm_message_t state) { }
 static inline int ata_acpi_register(void) { return 0; }
 static inline void ata_acpi_unregister(void) { }
-static inline void ata_acpi_bind(struct ata_device *dev) { }
-static inline void ata_acpi_unbind(struct ata_device *dev) { }
 static inline void ata_acpi_hotplug_init(struct ata_host *host) {}
 #endif
 
index 8d493b4a0961985347feb48f990075233578c893..d59d5239405f934c5bf9f8186719819f55c9dfc6 100644 (file)
@@ -271,7 +271,7 @@ static int __init pata_at32_probe(struct platform_device *pdev)
 
        struct device            *dev = &pdev->dev;
        struct at32_ide_info     *info;
-       struct ide_platform_data *board = pdev->dev.platform_data;
+       struct ide_platform_data *board = dev_get_platdata(&pdev->dev);
        struct resource          *res;
 
        int irq;
index 5364f97b42c6b9d6fcac4e130d3172913aa7c80a..d63ee8f41a4f29e9c0bc9209236c97ca47259ab5 100644 (file)
@@ -315,7 +315,7 @@ static struct ata_port_operations pata_at91_port_ops = {
 
 static int pata_at91_probe(struct platform_device *pdev)
 {
-       struct at91_cf_data *board = pdev->dev.platform_data;
+       struct at91_cf_data *board = dev_get_platdata(&pdev->dev);
        struct device *dev = &pdev->dev;
        struct at91_ide_info *info;
        struct resource *mem_res;
index 4ec7c04b3f8279dff1f2e39f356106e92815e39f..26386f0b89a8f4583c397ca9da154a9c499c6d2f 100644 (file)
@@ -237,6 +237,7 @@ static const struct of_device_id imx_pata_dt_ids[] = {
                /* sentinel */
        }
 };
+MODULE_DEVICE_TABLE(of, imx_pata_dt_ids);
 
 static struct platform_driver pata_imx_driver = {
        .probe          = pata_imx_probe,
index dcc6b243e525572ba4ac92576c3cb5e7d28863b9..1ec53f8ca96fa682fc1492e61816c6b043876f7d 100644 (file)
@@ -48,7 +48,7 @@ static unsigned int ixp4xx_mmio_data_xfer(struct ata_device *dev,
        u16 *buf16 = (u16 *) buf;
        struct ata_port *ap = dev->link->ap;
        void __iomem *mmio = ap->ioaddr.data_addr;
-       struct ixp4xx_pata_data *data = ap->host->dev->platform_data;
+       struct ixp4xx_pata_data *data = dev_get_platdata(ap->host->dev);
 
        /* set the expansion bus in 16bit mode and restore
         * 8 bit mode after the transaction.
@@ -143,7 +143,7 @@ static int ixp4xx_pata_probe(struct platform_device *pdev)
        struct resource *cs0, *cs1;
        struct ata_host *host;
        struct ata_port *ap;
-       struct ixp4xx_pata_data *data = pdev->dev.platform_data;
+       struct ixp4xx_pata_data *data = dev_get_platdata(&pdev->dev);
 
        cs0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        cs1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
index e73bef3093d2be6c859c462b4f8fa50758e21b80..c51bbb9ea8e8a826e3d2fa68e693d1cf6a3a2a94 100644 (file)
@@ -1037,7 +1037,7 @@ static void octeon_cf_shutdown(struct device *dev)
        union cvmx_mio_boot_dma_cfgx dma_cfg;
        union cvmx_mio_boot_dma_intx dma_int;
 
-       struct octeon_cf_port *cf_port = dev->platform_data;
+       struct octeon_cf_port *cf_port = dev_get_platdata(dev);
 
        if (cf_port->dma_base) {
                /* Stop and clear the dma engine.  */
index 71e093767f4e400e66ea8defe5b7d0ff0c2d0ff7..02794885de10be8329003300d19c2f8084ff9032 100644 (file)
@@ -180,7 +180,7 @@ static int pata_platform_probe(struct platform_device *pdev)
        struct resource *io_res;
        struct resource *ctl_res;
        struct resource *irq_res;
-       struct pata_platform_info *pp_info = pdev->dev.platform_data;
+       struct pata_platform_info *pp_info = dev_get_platdata(&pdev->dev);
 
        /*
         * Simple resource validation ..
index 942ef94b29e6658a115935c64cc3e81bdf8c1e6b..a6f05acad61ed01d68b0ec201698a8abc406cf44 100644 (file)
@@ -238,7 +238,7 @@ static int pxa_ata_probe(struct platform_device *pdev)
        struct resource *ctl_res;
        struct resource *dma_res;
        struct resource *irq_res;
-       struct pata_pxa_pdata *pdata = pdev->dev.platform_data;
+       struct pata_pxa_pdata *pdata = dev_get_platdata(&pdev->dev);
        int ret = 0;
 
        /*
index 6ef27e98c50894190e74f396e19e13a44713157c..951aa951ffdb1dcdaedea3c36707f4d1513711db 100644 (file)
@@ -475,7 +475,7 @@ static void pata_s3c_hwinit(struct s3c_ide_info *info,
 
 static int __init pata_s3c_probe(struct platform_device *pdev)
 {
-       struct s3c_ide_platdata *pdata = pdev->dev.platform_data;
+       struct s3c_ide_platdata *pdata = dev_get_platdata(&pdev->dev);
        struct device *dev = &pdev->dev;
        struct s3c_ide_info *info;
        struct resource *res;
@@ -617,7 +617,7 @@ static int pata_s3c_resume(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct ata_host *host = platform_get_drvdata(pdev);
-       struct s3c_ide_platdata *pdata = pdev->dev.platform_data;
+       struct s3c_ide_platdata *pdata = dev_get_platdata(&pdev->dev);
        struct s3c_ide_info *info = host->private_data;
 
        pata_s3c_hwinit(info, pdata);
index 35c6b6d09c277526d93461388b6971069c644341..56be318198971f40ea9a57703530260ad51e4067 100644 (file)
@@ -553,10 +553,15 @@ struct mv_host_priv {
        u32                     irq_mask_offset;
        u32                     unmask_all_irqs;
 
-#if defined(CONFIG_HAVE_CLK)
+       /*
+        * Needed on some devices that require their clocks to be enabled.
+        * These are optional: if the platform device does not have any
+        * clocks, they won't be used.  Also, if the underlying hardware
+        * does not support the common clock framework (CONFIG_HAVE_CLK=n),
+        * all the clock operations become no-ops (see clk.h).
+        */
        struct clk              *clk;
        struct clk              **port_clks;
-#endif
        /*
         * These consistent DMA memory pools give us guaranteed
         * alignment for hardware-accessed data structures,
@@ -4032,9 +4037,7 @@ static int mv_platform_probe(struct platform_device *pdev)
        struct resource *res;
        int n_ports = 0, irq = 0;
        int rc;
-#if defined(CONFIG_HAVE_CLK)
        int port;
-#endif
 
        ata_print_version_once(&pdev->dev, DRV_VERSION);
 
@@ -4058,7 +4061,7 @@ static int mv_platform_probe(struct platform_device *pdev)
                of_property_read_u32(pdev->dev.of_node, "nr-ports", &n_ports);
                irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
        } else {
-               mv_platform_data = pdev->dev.platform_data;
+               mv_platform_data = dev_get_platdata(&pdev->dev);
                n_ports = mv_platform_data->n_ports;
                irq = platform_get_irq(pdev, 0);
        }
@@ -4068,13 +4071,11 @@ static int mv_platform_probe(struct platform_device *pdev)
 
        if (!host || !hpriv)
                return -ENOMEM;
-#if defined(CONFIG_HAVE_CLK)
        hpriv->port_clks = devm_kzalloc(&pdev->dev,
                                        sizeof(struct clk *) * n_ports,
                                        GFP_KERNEL);
        if (!hpriv->port_clks)
                return -ENOMEM;
-#endif
        host->private_data = hpriv;
        hpriv->n_ports = n_ports;
        hpriv->board_idx = chip_soc;
@@ -4084,7 +4085,6 @@ static int mv_platform_probe(struct platform_device *pdev)
                                   resource_size(res));
        hpriv->base -= SATAHC0_REG_BASE;
 
-#if defined(CONFIG_HAVE_CLK)
        hpriv->clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(hpriv->clk))
                dev_notice(&pdev->dev, "cannot get optional clkdev\n");
@@ -4098,7 +4098,6 @@ static int mv_platform_probe(struct platform_device *pdev)
                if (!IS_ERR(hpriv->port_clks[port]))
                        clk_prepare_enable(hpriv->port_clks[port]);
        }
-#endif
 
        /*
         * (Re-)program MBUS remapping windows if we are asked to.
@@ -4124,7 +4123,6 @@ static int mv_platform_probe(struct platform_device *pdev)
                return 0;
 
 err:
-#if defined(CONFIG_HAVE_CLK)
        if (!IS_ERR(hpriv->clk)) {
                clk_disable_unprepare(hpriv->clk);
                clk_put(hpriv->clk);
@@ -4135,7 +4133,6 @@ err:
                        clk_put(hpriv->port_clks[port]);
                }
        }
-#endif
 
        return rc;
 }
@@ -4151,13 +4148,10 @@ err:
 static int mv_platform_remove(struct platform_device *pdev)
 {
        struct ata_host *host = platform_get_drvdata(pdev);
-#if defined(CONFIG_HAVE_CLK)
        struct mv_host_priv *hpriv = host->private_data;
        int port;
-#endif
        ata_host_detach(host);
 
-#if defined(CONFIG_HAVE_CLK)
        if (!IS_ERR(hpriv->clk)) {
                clk_disable_unprepare(hpriv->clk);
                clk_put(hpriv->clk);
@@ -4168,7 +4162,6 @@ static int mv_platform_remove(struct platform_device *pdev)
                        clk_put(hpriv->port_clks[port]);
                }
        }
-#endif
        return 0;
 }
 
@@ -4428,9 +4421,6 @@ static int mv_pci_device_resume(struct pci_dev *pdev)
 #endif
 #endif
 
-static int mv_platform_probe(struct platform_device *pdev);
-static int mv_platform_remove(struct platform_device *pdev);
-
 static int __init mv_init(void)
 {
        int rc = -ENODEV;
index 5a9b6569dd74f8cc97ba15fde613f208bd752c46..9f098a82cf04b061edb203fff718ef0ca70e6328 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/sched.h>
 #include <linux/async.h>
 #include <linux/suspend.h>
+#include <trace/events/power.h>
 #include <linux/cpuidle.h>
 #include "../base.h"
 #include "power.h"
@@ -56,6 +57,30 @@ static pm_message_t pm_transition;
 
 static int async_error;
 
+static char *pm_verb(int event)
+{
+       switch (event) {
+       case PM_EVENT_SUSPEND:
+               return "suspend";
+       case PM_EVENT_RESUME:
+               return "resume";
+       case PM_EVENT_FREEZE:
+               return "freeze";
+       case PM_EVENT_QUIESCE:
+               return "quiesce";
+       case PM_EVENT_HIBERNATE:
+               return "hibernate";
+       case PM_EVENT_THAW:
+               return "thaw";
+       case PM_EVENT_RESTORE:
+               return "restore";
+       case PM_EVENT_RECOVER:
+               return "recover";
+       default:
+               return "(unknown PM event)";
+       }
+}
+
 /**
  * device_pm_sleep_init - Initialize system suspend-related device fields.
  * @dev: Device object being initialized.
@@ -172,16 +197,21 @@ static ktime_t initcall_debug_start(struct device *dev)
 }
 
 static void initcall_debug_report(struct device *dev, ktime_t calltime,
-                                 int error)
+                                 int error, pm_message_t state, char *info)
 {
-       ktime_t delta, rettime;
+       ktime_t rettime;
+       s64 nsecs;
+
+       rettime = ktime_get();
+       nsecs = (s64) ktime_to_ns(ktime_sub(rettime, calltime));
 
        if (pm_print_times_enabled) {
-               rettime = ktime_get();
-               delta = ktime_sub(rettime, calltime);
                pr_info("call %s+ returned %d after %Ld usecs\n", dev_name(dev),
-                       error, (unsigned long long)ktime_to_ns(delta) >> 10);
+                       error, (unsigned long long)nsecs >> 10);
        }
+
+       trace_device_pm_report_time(dev, info, nsecs, pm_verb(state.event),
+                                   error);
 }
 
 /**
@@ -309,30 +339,6 @@ static pm_callback_t pm_noirq_op(const struct dev_pm_ops *ops, pm_message_t stat
        return NULL;
 }
 
-static char *pm_verb(int event)
-{
-       switch (event) {
-       case PM_EVENT_SUSPEND:
-               return "suspend";
-       case PM_EVENT_RESUME:
-               return "resume";
-       case PM_EVENT_FREEZE:
-               return "freeze";
-       case PM_EVENT_QUIESCE:
-               return "quiesce";
-       case PM_EVENT_HIBERNATE:
-               return "hibernate";
-       case PM_EVENT_THAW:
-               return "thaw";
-       case PM_EVENT_RESTORE:
-               return "restore";
-       case PM_EVENT_RECOVER:
-               return "recover";
-       default:
-               return "(unknown PM event)";
-       }
-}
-
 static void pm_dev_dbg(struct device *dev, pm_message_t state, char *info)
 {
        dev_dbg(dev, "%s%s%s\n", info, pm_verb(state.event),
@@ -379,7 +385,7 @@ static int dpm_run_callback(pm_callback_t cb, struct device *dev,
        error = cb(dev);
        suspend_report_result(cb, error);
 
-       initcall_debug_report(dev, calltime, error);
+       initcall_debug_report(dev, calltime, error, state, info);
 
        return error;
 }
@@ -1027,7 +1033,8 @@ EXPORT_SYMBOL_GPL(dpm_suspend_end);
  * @cb: Suspend callback to execute.
  */
 static int legacy_suspend(struct device *dev, pm_message_t state,
-                         int (*cb)(struct device *dev, pm_message_t state))
+                         int (*cb)(struct device *dev, pm_message_t state),
+                         char *info)
 {
        int error;
        ktime_t calltime;
@@ -1037,7 +1044,7 @@ static int legacy_suspend(struct device *dev, pm_message_t state,
        error = cb(dev, state);
        suspend_report_result(cb, error);
 
-       initcall_debug_report(dev, calltime, error);
+       initcall_debug_report(dev, calltime, error, state, info);
 
        return error;
 }
@@ -1097,7 +1104,8 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
                        goto Run;
                } else if (dev->class->suspend) {
                        pm_dev_dbg(dev, state, "legacy class ");
-                       error = legacy_suspend(dev, state, dev->class->suspend);
+                       error = legacy_suspend(dev, state, dev->class->suspend,
+                                               "legacy class ");
                        goto End;
                }
        }
@@ -1108,7 +1116,8 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
                        callback = pm_op(dev->bus->pm, state);
                } else if (dev->bus->suspend) {
                        pm_dev_dbg(dev, state, "legacy bus ");
-                       error = legacy_suspend(dev, state, dev->bus->suspend);
+                       error = legacy_suspend(dev, state, dev->bus->suspend,
+                                               "legacy bus ");
                        goto End;
                }
        }
index 380a2003231e4c56984207dd7f2658bd9bcc3166..7c081b38ef3e840ed37248e2110e012e7ebb2191 100644 (file)
@@ -35,8 +35,14 @@ config BCMA_DRIVER_PCI_HOSTMODE
          PCI core hostmode operation (external PCI bus).
 
 config BCMA_HOST_SOC
-       bool
-       depends on BCMA_DRIVER_MIPS
+       bool "Support for BCMA in a SoC"
+       depends on BCMA
+       help
+         Host interface for a Broadcom AIX bus directly mapped into
+         the memory. This only works with the Broadcom SoCs from the
+         BCM47XX line.
+
+         If unsure, say N
 
 config BCMA_DRIVER_MIPS
        bool "BCMA Broadcom MIPS core driver"
index 0067422ec17dacb681fd3d6cd4afd0c64894ae1c..90ee350442a99d243606c97b716af75d909308c9 100644 (file)
@@ -237,7 +237,7 @@ int bcma_bus_register(struct bcma_bus *bus)
        err = bcma_bus_scan(bus);
        if (err) {
                bcma_err(bus, "Failed to scan: %d\n", err);
-               return -1;
+               return err;
        }
 
        /* Early init CC core */
index 8bffa5c9818c8e598a7f1408bd56a511f5773f29..cd6b20fce680591a5253f15546cae34d21a4bb68 100644 (file)
@@ -32,6 +32,18 @@ static const struct bcma_device_id_name bcma_bcm_device_names[] = {
        { BCMA_CORE_4706_CHIPCOMMON, "BCM4706 ChipCommon" },
        { BCMA_CORE_4706_SOC_RAM, "BCM4706 SOC RAM" },
        { BCMA_CORE_4706_MAC_GBIT, "BCM4706 GBit MAC" },
+       { BCMA_CORE_PCIEG2, "PCIe Gen 2" },
+       { BCMA_CORE_DMA, "DMA" },
+       { BCMA_CORE_SDIO3, "SDIO3" },
+       { BCMA_CORE_USB20, "USB 2.0" },
+       { BCMA_CORE_USB30, "USB 3.0" },
+       { BCMA_CORE_A9JTAG, "ARM Cortex A9 JTAG" },
+       { BCMA_CORE_DDR23, "Denali DDR2/DDR3 memory controller" },
+       { BCMA_CORE_ROM, "ROM" },
+       { BCMA_CORE_NAND, "NAND flash controller" },
+       { BCMA_CORE_QSPI, "SPI flash controller" },
+       { BCMA_CORE_CHIPCOMMON_B, "Chipcommon B" },
+       { BCMA_CORE_ARMCA9, "ARM Cortex A9 core (ihost)" },
        { BCMA_CORE_AMEMC, "AMEMC (DDR)" },
        { BCMA_CORE_ALTA, "ALTA (I2S)" },
        { BCMA_CORE_INVALID, "Invalid" },
@@ -201,7 +213,7 @@ static s32 bcma_erom_get_mst_port(struct bcma_bus *bus, u32 __iomem **eromptr)
        return ent;
 }
 
-static s32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 __iomem **eromptr,
+static u32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 __iomem **eromptr,
                                  u32 type, u8 port)
 {
        u32 addrl, addrh, sizel, sizeh = 0;
@@ -213,7 +225,7 @@ static s32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 __iomem **eromptr,
            ((ent & SCAN_ADDR_TYPE) != type) ||
            (((ent & SCAN_ADDR_PORT) >> SCAN_ADDR_PORT_SHIFT) != port)) {
                bcma_erom_push_ent(eromptr);
-               return -EINVAL;
+               return (u32)-EINVAL;
        }
 
        addrl = ent & SCAN_ADDR_ADDR;
@@ -261,7 +273,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
                              struct bcma_device_id *match, int core_num,
                              struct bcma_device *core)
 {
-       s32 tmp;
+       u32 tmp;
        u8 i, j;
        s32 cia, cib;
        u8 ports[2], wrappers[2];
@@ -339,11 +351,11 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
         * the main register space for the core
         */
        tmp = bcma_erom_get_addr_desc(bus, eromptr, SCAN_ADDR_TYPE_SLAVE, 0);
-       if (tmp <= 0) {
+       if (tmp == 0 || IS_ERR_VALUE(tmp)) {
                /* Try again to see if it is a bridge */
                tmp = bcma_erom_get_addr_desc(bus, eromptr,
                                              SCAN_ADDR_TYPE_BRIDGE, 0);
-               if (tmp <= 0) {
+               if (tmp == 0 || IS_ERR_VALUE(tmp)) {
                        return -EILSEQ;
                } else {
                        bcma_info(bus, "Bridge found\n");
@@ -357,7 +369,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
                for (j = 0; ; j++) {
                        tmp = bcma_erom_get_addr_desc(bus, eromptr,
                                SCAN_ADDR_TYPE_SLAVE, i);
-                       if (tmp < 0) {
+                       if (IS_ERR_VALUE(tmp)) {
                                /* no more entries for port _i_ */
                                /* pr_debug("erom: slave port %d "
                                 * "has %d descriptors\n", i, j); */
@@ -374,7 +386,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
                for (j = 0; ; j++) {
                        tmp = bcma_erom_get_addr_desc(bus, eromptr,
                                SCAN_ADDR_TYPE_MWRAP, i);
-                       if (tmp < 0) {
+                       if (IS_ERR_VALUE(tmp)) {
                                /* no more entries for port _i_ */
                                /* pr_debug("erom: master wrapper %d "
                                 * "has %d descriptors\n", i, j); */
@@ -392,7 +404,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
                for (j = 0; ; j++) {
                        tmp = bcma_erom_get_addr_desc(bus, eromptr,
                                SCAN_ADDR_TYPE_SWRAP, i + hack);
-                       if (tmp < 0) {
+                       if (IS_ERR_VALUE(tmp)) {
                                /* no more entries for port _i_ */
                                /* pr_debug("erom: master wrapper %d "
                                 * has %d descriptors\n", i, j); */
index 11f467c00d0ac836a1c6509bffd31e49b891a844..a12b923bbaca91f14b923e0b271b00ebc1be8d28 100644 (file)
@@ -91,6 +91,10 @@ static struct usb_device_id ath3k_table[] = {
        { USB_DEVICE(0x0489, 0xe04e) },
        { USB_DEVICE(0x0489, 0xe056) },
        { USB_DEVICE(0x0489, 0xe04d) },
+       { USB_DEVICE(0x04c5, 0x1330) },
+       { USB_DEVICE(0x13d3, 0x3402) },
+       { USB_DEVICE(0x0cf3, 0x3121) },
+       { USB_DEVICE(0x0cf3, 0xe003) },
 
        /* Atheros AR5BBU12 with sflash firmware */
        { USB_DEVICE(0x0489, 0xE02C) },
@@ -128,6 +132,10 @@ static struct usb_device_id ath3k_blist_tbl[] = {
        { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0cf3, 0xe003), .driver_info = BTUSB_ATH3012 },
 
        /* Atheros AR5BBU22 with sflash firmware */
        { USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 },
@@ -193,24 +201,44 @@ error:
 
 static int ath3k_get_state(struct usb_device *udev, unsigned char *state)
 {
-       int pipe = 0;
+       int ret, pipe = 0;
+       char *buf;
+
+       buf = kmalloc(sizeof(*buf), GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
 
        pipe = usb_rcvctrlpipe(udev, 0);
-       return usb_control_msg(udev, pipe, ATH3K_GETSTATE,
-                       USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
-                       state, 0x01, USB_CTRL_SET_TIMEOUT);
+       ret = usb_control_msg(udev, pipe, ATH3K_GETSTATE,
+                             USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
+                             buf, sizeof(*buf), USB_CTRL_SET_TIMEOUT);
+
+       *state = *buf;
+       kfree(buf);
+
+       return ret;
 }
 
 static int ath3k_get_version(struct usb_device *udev,
                        struct ath3k_version *version)
 {
-       int pipe = 0;
+       int ret, pipe = 0;
+       struct ath3k_version *buf;
+       const int size = sizeof(*buf);
+
+       buf = kmalloc(size, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
 
        pipe = usb_rcvctrlpipe(udev, 0);
-       return usb_control_msg(udev, pipe, ATH3K_GETVERSION,
-                       USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, version,
-                       sizeof(struct ath3k_version),
-                       USB_CTRL_SET_TIMEOUT);
+       ret = usb_control_msg(udev, pipe, ATH3K_GETVERSION,
+                             USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
+                             buf, size, USB_CTRL_SET_TIMEOUT);
+
+       memcpy(version, buf, size);
+       kfree(buf);
+
+       return ret;
 }
 
 static int ath3k_load_fwfile(struct usb_device *udev,
index db2c3c305df8ea183d499861089e7e446d2beabe..023d35e3c7a75b573a52d99cbda5bd98c64e017f 100644 (file)
@@ -43,7 +43,7 @@ static ssize_t btmrvl_hscfgcmd_write(struct file *file,
        if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
                return -EFAULT;
 
-       ret = strict_strtol(buf, 10, &result);
+       ret = kstrtol(buf, 10, &result);
        if (ret)
                return ret;
 
@@ -89,7 +89,7 @@ static ssize_t btmrvl_pscmd_write(struct file *file, const char __user *ubuf,
        if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
                return -EFAULT;
 
-       ret = strict_strtol(buf, 10, &result);
+       ret = kstrtol(buf, 10, &result);
        if (ret)
                return ret;
 
@@ -135,7 +135,7 @@ static ssize_t btmrvl_hscmd_write(struct file *file, const char __user *ubuf,
        if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
                return -EFAULT;
 
-       ret = strict_strtol(buf, 10, &result);
+       ret = kstrtol(buf, 10, &result);
        if (ret)
                return ret;
 
index de4cf4daa2f4cefa3a270ccaf8e4e8fb22af1015..8e16f0af6358872606fbe102bddc9ade2c6ab470 100644 (file)
@@ -154,6 +154,10 @@ static struct usb_device_id blacklist_table[] = {
        { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0cf3, 0xe003), .driver_info = BTUSB_ATH3012 },
 
        /* Atheros AR5BBU12 with sflash firmware */
        { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
@@ -1095,7 +1099,7 @@ static int btusb_setup_intel_patching(struct hci_dev *hdev,
        if (IS_ERR(skb)) {
                BT_ERR("%s sending Intel patch command (0x%4.4x) failed (%ld)",
                       hdev->name, cmd->opcode, PTR_ERR(skb));
-               return -PTR_ERR(skb);
+               return PTR_ERR(skb);
        }
 
        /* It ensures that the returned event matches the event data read from
@@ -1147,7 +1151,7 @@ static int btusb_setup_intel(struct hci_dev *hdev)
        if (IS_ERR(skb)) {
                BT_ERR("%s sending initial HCI reset command failed (%ld)",
                       hdev->name, PTR_ERR(skb));
-               return -PTR_ERR(skb);
+               return PTR_ERR(skb);
        }
        kfree_skb(skb);
 
@@ -1161,7 +1165,7 @@ static int btusb_setup_intel(struct hci_dev *hdev)
        if (IS_ERR(skb)) {
                BT_ERR("%s reading Intel fw version command failed (%ld)",
                       hdev->name, PTR_ERR(skb));
-               return -PTR_ERR(skb);
+               return PTR_ERR(skb);
        }
 
        if (skb->len != sizeof(*ver)) {
@@ -1219,7 +1223,7 @@ static int btusb_setup_intel(struct hci_dev *hdev)
                BT_ERR("%s entering Intel manufacturer mode failed (%ld)",
                       hdev->name, PTR_ERR(skb));
                release_firmware(fw);
-               return -PTR_ERR(skb);
+               return PTR_ERR(skb);
        }
 
        if (skb->data[0]) {
@@ -1276,7 +1280,7 @@ static int btusb_setup_intel(struct hci_dev *hdev)
        if (IS_ERR(skb)) {
                BT_ERR("%s exiting Intel manufacturer mode failed (%ld)",
                       hdev->name, PTR_ERR(skb));
-               return -PTR_ERR(skb);
+               return PTR_ERR(skb);
        }
        kfree_skb(skb);
 
@@ -1292,7 +1296,7 @@ exit_mfg_disable:
        if (IS_ERR(skb)) {
                BT_ERR("%s exiting Intel manufacturer mode failed (%ld)",
                       hdev->name, PTR_ERR(skb));
-               return -PTR_ERR(skb);
+               return PTR_ERR(skb);
        }
        kfree_skb(skb);
 
@@ -1310,7 +1314,7 @@ exit_mfg_deactivate:
        if (IS_ERR(skb)) {
                BT_ERR("%s exiting Intel manufacturer mode failed (%ld)",
                       hdev->name, PTR_ERR(skb));
-               return -PTR_ERR(skb);
+               return PTR_ERR(skb);
        }
        kfree_skb(skb);
 
index 19a12ac64a9ec966149286a84a2f0db5e3e0ee60..6a86b6f56af22c08810acdeb861f2599549f2827 100644 (file)
@@ -164,7 +164,9 @@ static int __init mxc_rnga_probe(struct platform_device *pdev)
                goto out;
        }
 
-       clk_prepare_enable(mxc_rng->clk);
+       err = clk_prepare_enable(mxc_rng->clk);
+       if (err)
+               goto out;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        mxc_rng->mem = devm_ioremap_resource(&pdev->dev, res);
index bf2349dbbf7ffd301839bf24242b9fd2127b53db..7cc1fe2241fd622990c94c3755fe2995e716a8b8 100644 (file)
@@ -876,11 +876,6 @@ found:
        if (useinput)
                sonypi_report_input_event(event);
 
-#ifdef CONFIG_ACPI
-       if (sonypi_acpi_device)
-               acpi_bus_generate_proc_event(sonypi_acpi_device, 1, event);
-#endif
-
        kfifo_in_locked(&sonypi_device.fifo, (unsigned char *)&event,
                        sizeof(event), &sonypi_device.fifo_lock);
        kill_fasync(&sonypi_device.fifo_async, SIGIO, POLL_IN);
index 1b456fe9b87a12f98e8a6d691487c252271cb3e6..d0e75aa904ac92dc1f53973a7b274a039dc45b46 100644 (file)
@@ -272,9 +272,12 @@ static struct port *find_port_by_devt_in_portdev(struct ports_device *portdev,
        unsigned long flags;
 
        spin_lock_irqsave(&portdev->ports_lock, flags);
-       list_for_each_entry(port, &portdev->ports, list)
-               if (port->cdev->dev == dev)
+       list_for_each_entry(port, &portdev->ports, list) {
+               if (port->cdev->dev == dev) {
+                       kref_get(&port->kref);
                        goto out;
+               }
+       }
        port = NULL;
 out:
        spin_unlock_irqrestore(&portdev->ports_lock, flags);
@@ -746,6 +749,10 @@ static ssize_t port_fops_read(struct file *filp, char __user *ubuf,
 
        port = filp->private_data;
 
+       /* Port is hot-unplugged. */
+       if (!port->guest_connected)
+               return -ENODEV;
+
        if (!port_has_data(port)) {
                /*
                 * If nothing's connected on the host just return 0 in
@@ -762,7 +769,7 @@ static ssize_t port_fops_read(struct file *filp, char __user *ubuf,
                if (ret < 0)
                        return ret;
        }
-       /* Port got hot-unplugged. */
+       /* Port got hot-unplugged while we were waiting above. */
        if (!port->guest_connected)
                return -ENODEV;
        /*
@@ -932,13 +939,25 @@ static ssize_t port_fops_splice_write(struct pipe_inode_info *pipe,
        if (is_rproc_serial(port->out_vq->vdev))
                return -EINVAL;
 
+       /*
+        * pipe->nrbufs == 0 means there are no data to transfer,
+        * so this returns just 0 for no data.
+        */
+       pipe_lock(pipe);
+       if (!pipe->nrbufs) {
+               ret = 0;
+               goto error_out;
+       }
+
        ret = wait_port_writable(port, filp->f_flags & O_NONBLOCK);
        if (ret < 0)
-               return ret;
+               goto error_out;
 
        buf = alloc_buf(port->out_vq, 0, pipe->nrbufs);
-       if (!buf)
-               return -ENOMEM;
+       if (!buf) {
+               ret = -ENOMEM;
+               goto error_out;
+       }
 
        sgl.n = 0;
        sgl.len = 0;
@@ -946,12 +965,17 @@ static ssize_t port_fops_splice_write(struct pipe_inode_info *pipe,
        sgl.sg = buf->sg;
        sg_init_table(sgl.sg, sgl.size);
        ret = __splice_from_pipe(pipe, &sd, pipe_to_sg);
+       pipe_unlock(pipe);
        if (likely(ret > 0))
                ret = __send_to_port(port, buf->sg, sgl.n, sgl.len, buf, true);
 
        if (unlikely(ret <= 0))
                free_buf(buf, true);
        return ret;
+
+error_out:
+       pipe_unlock(pipe);
+       return ret;
 }
 
 static unsigned int port_fops_poll(struct file *filp, poll_table *wait)
@@ -1019,14 +1043,14 @@ static int port_fops_open(struct inode *inode, struct file *filp)
        struct port *port;
        int ret;
 
+       /* We get the port with a kref here */
        port = find_port_by_devt(cdev->dev);
+       if (!port) {
+               /* Port was unplugged before we could proceed */
+               return -ENXIO;
+       }
        filp->private_data = port;
 
-       /* Prevent against a port getting hot-unplugged at the same time */
-       spin_lock_irq(&port->portdev->ports_lock);
-       kref_get(&port->kref);
-       spin_unlock_irq(&port->portdev->ports_lock);
-
        /*
         * Don't allow opening of console port devices -- that's done
         * via /dev/hvc
@@ -1498,14 +1522,6 @@ static void remove_port(struct kref *kref)
 
        port = container_of(kref, struct port, kref);
 
-       sysfs_remove_group(&port->dev->kobj, &port_attribute_group);
-       device_destroy(pdrvdata.class, port->dev->devt);
-       cdev_del(port->cdev);
-
-       kfree(port->name);
-
-       debugfs_remove(port->debugfs_file);
-
        kfree(port);
 }
 
@@ -1513,18 +1529,22 @@ static void remove_port_data(struct port *port)
 {
        struct port_buffer *buf;
 
+       spin_lock_irq(&port->inbuf_lock);
        /* Remove unused data this port might have received. */
        discard_port_data(port);
 
-       reclaim_consumed_buffers(port);
-
        /* Remove buffers we queued up for the Host to send us data in. */
        while ((buf = virtqueue_detach_unused_buf(port->in_vq)))
                free_buf(buf, true);
+       spin_unlock_irq(&port->inbuf_lock);
+
+       spin_lock_irq(&port->outvq_lock);
+       reclaim_consumed_buffers(port);
 
        /* Free pending buffers from the out-queue. */
        while ((buf = virtqueue_detach_unused_buf(port->out_vq)))
                free_buf(buf, true);
+       spin_unlock_irq(&port->outvq_lock);
 }
 
 /*
@@ -1538,14 +1558,18 @@ static void unplug_port(struct port *port)
        list_del(&port->list);
        spin_unlock_irq(&port->portdev->ports_lock);
 
+       spin_lock_irq(&port->inbuf_lock);
        if (port->guest_connected) {
+               /* Let the app know the port is going down. */
+               send_sigio_to_port(port);
+
+               /* Do this after sigio is actually sent */
                port->guest_connected = false;
                port->host_connected = false;
-               wake_up_interruptible(&port->waitqueue);
 
-               /* Let the app know the port is going down. */
-               send_sigio_to_port(port);
+               wake_up_interruptible(&port->waitqueue);
        }
+       spin_unlock_irq(&port->inbuf_lock);
 
        if (is_console_port(port)) {
                spin_lock_irq(&pdrvdata_lock);
@@ -1563,6 +1587,14 @@ static void unplug_port(struct port *port)
         */
        port->portdev = NULL;
 
+       sysfs_remove_group(&port->dev->kobj, &port_attribute_group);
+       device_destroy(pdrvdata.class, port->dev->devt);
+       cdev_del(port->cdev);
+
+       kfree(port->name);
+
+       debugfs_remove(port->debugfs_file);
+
        /*
         * Locks around here are not necessary - a port can't be
         * opened after we removed the port struct from ports_list
@@ -1655,7 +1687,9 @@ static void handle_control_message(struct ports_device *portdev,
                 * If the guest is connected, it'll be interested in
                 * knowing the host connection state changed.
                 */
+               spin_lock_irq(&port->inbuf_lock);
                send_sigio_to_port(port);
+               spin_unlock_irq(&port->inbuf_lock);
                break;
        case VIRTIO_CONSOLE_PORT_NAME:
                /*
@@ -1775,13 +1809,13 @@ static void in_intr(struct virtqueue *vq)
        if (!port->guest_connected && !is_rproc_serial(port->portdev->vdev))
                discard_port_data(port);
 
+       /* Send a SIGIO indicating new data in case the process asked for it */
+       send_sigio_to_port(port);
+
        spin_unlock_irqrestore(&port->inbuf_lock, flags);
 
        wake_up_interruptible(&port->waitqueue);
 
-       /* Send a SIGIO indicating new data in case the process asked for it */
-       send_sigio_to_port(port);
-
        if (is_console_port(port) && hvc_poll(port->cons.hvc))
                hvc_kick();
 }
@@ -2215,10 +2249,8 @@ static int __init init(void)
        }
 
        pdrvdata.debugfs_dir = debugfs_create_dir("virtio-ports", NULL);
-       if (!pdrvdata.debugfs_dir) {
-               pr_warning("Error %ld creating debugfs dir for virtio-ports\n",
-                          PTR_ERR(pdrvdata.debugfs_dir));
-       }
+       if (!pdrvdata.debugfs_dir)
+               pr_warning("Error creating debugfs dir for virtio-ports\n");
        INIT_LIST_HEAD(&pdrvdata.consoles);
        INIT_LIST_HEAD(&pdrvdata.portdevs);
 
index d345b5a7aa719e52fd660013afdf96b4d3da6335..ad5866c2ada0a5bd219305954682dbc7aae4f5a2 100644 (file)
@@ -23,7 +23,7 @@ obj-$(CONFIG_GENERIC_CPUFREQ_CPU0)    += cpufreq-cpu0.o
 # powernow-k8 can load then. ACPI is preferred to all other hardware-specific drivers.
 # speedstep-* is preferred over p4-clockmod.
 
-obj-$(CONFIG_X86_ACPI_CPUFREQ)         += acpi-cpufreq.o mperf.o
+obj-$(CONFIG_X86_ACPI_CPUFREQ)         += acpi-cpufreq.o
 obj-$(CONFIG_X86_POWERNOW_K8)          += powernow-k8.o
 obj-$(CONFIG_X86_PCC_CPUFREQ)          += pcc-cpufreq.o
 obj-$(CONFIG_X86_POWERNOW_K6)          += powernow-k6.o
index 39264020b88a1b2e7d461a8d0a3f2f909a31dbb4..e673670d2321fdbfe53349dafc4754d08ebcadc0 100644 (file)
@@ -45,7 +45,6 @@
 #include <asm/msr.h>
 #include <asm/processor.h>
 #include <asm/cpufeature.h>
-#include "mperf.h"
 
 MODULE_AUTHOR("Paul Diefenbaugh, Dominik Brodowski");
 MODULE_DESCRIPTION("ACPI Processor P-States Driver");
@@ -861,10 +860,6 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
        /* notify BIOS that we exist */
        acpi_processor_notify_smm(THIS_MODULE);
 
-       /* Check for APERF/MPERF support in hardware */
-       if (boot_cpu_has(X86_FEATURE_APERFMPERF))
-               acpi_cpufreq_driver.getavg = cpufreq_get_measured_perf;
-
        pr_debug("CPU%u - ACPI performance management activated.\n", cpu);
        for (i = 0; i < perf->state_count; i++)
                pr_debug("     %cP%d: %d MHz, %d mW, %d uS\n",
index a4ad7339588d7122fee7f4f86271c74629980709..80c0e204c6d285e51b55a5567ed3699ab593b6ee 100644 (file)
@@ -44,6 +44,7 @@
  */
 static struct cpufreq_driver *cpufreq_driver;
 static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
+static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data_fallback);
 static DEFINE_RWLOCK(cpufreq_driver_lock);
 static DEFINE_MUTEX(cpufreq_governor_lock);
 
@@ -805,41 +806,35 @@ void cpufreq_sysfs_remove_file(const struct attribute *attr)
 EXPORT_SYMBOL(cpufreq_sysfs_remove_file);
 
 /* symlink affected CPUs */
-static int cpufreq_add_dev_symlink(unsigned int cpu,
-                                  struct cpufreq_policy *policy)
+static int cpufreq_add_dev_symlink(struct cpufreq_policy *policy)
 {
        unsigned int j;
        int ret = 0;
 
        for_each_cpu(j, policy->cpus) {
-               struct cpufreq_policy *managed_policy;
                struct device *cpu_dev;
 
-               if (j == cpu)
+               if (j == policy->cpu)
                        continue;
 
-               pr_debug("CPU %u already managed, adding link\n", j);
-               managed_policy = cpufreq_cpu_get(cpu);
+               pr_debug("Adding link for CPU: %u\n", j);
+               cpufreq_cpu_get(policy->cpu);
                cpu_dev = get_cpu_device(j);
                ret = sysfs_create_link(&cpu_dev->kobj, &policy->kobj,
                                        "cpufreq");
                if (ret) {
-                       cpufreq_cpu_put(managed_policy);
+                       cpufreq_cpu_put(policy);
                        return ret;
                }
        }
        return ret;
 }
 
-static int cpufreq_add_dev_interface(unsigned int cpu,
-                                    struct cpufreq_policy *policy,
+static int cpufreq_add_dev_interface(struct cpufreq_policy *policy,
                                     struct device *dev)
 {
-       struct cpufreq_policy new_policy;
        struct freq_attr **drv_attr;
-       unsigned long flags;
        int ret = 0;
-       unsigned int j;
 
        /* prepare interface data */
        ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq,
@@ -871,17 +866,23 @@ static int cpufreq_add_dev_interface(unsigned int cpu,
                        goto err_out_kobj_put;
        }
 
-       write_lock_irqsave(&cpufreq_driver_lock, flags);
-       for_each_cpu(j, policy->cpus) {
-               per_cpu(cpufreq_cpu_data, j) = policy;
-               per_cpu(cpufreq_policy_cpu, j) = policy->cpu;
-       }
-       write_unlock_irqrestore(&cpufreq_driver_lock, flags);
-
-       ret = cpufreq_add_dev_symlink(cpu, policy);
+       ret = cpufreq_add_dev_symlink(policy);
        if (ret)
                goto err_out_kobj_put;
 
+       return ret;
+
+err_out_kobj_put:
+       kobject_put(&policy->kobj);
+       wait_for_completion(&policy->kobj_unregister);
+       return ret;
+}
+
+static void cpufreq_init_policy(struct cpufreq_policy *policy)
+{
+       struct cpufreq_policy new_policy;
+       int ret = 0;
+
        memcpy(&new_policy, policy, sizeof(struct cpufreq_policy));
        /* assure that the starting sequence is run in __cpufreq_set_policy */
        policy->governor = NULL;
@@ -896,17 +897,11 @@ static int cpufreq_add_dev_interface(unsigned int cpu,
                if (cpufreq_driver->exit)
                        cpufreq_driver->exit(policy);
        }
-       return ret;
-
-err_out_kobj_put:
-       kobject_put(&policy->kobj);
-       wait_for_completion(&policy->kobj_unregister);
-       return ret;
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
 static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling,
-                                 struct device *dev)
+                                 struct device *dev, bool frozen)
 {
        struct cpufreq_policy *policy;
        int ret = 0, has_target = !!cpufreq_driver->target;
@@ -934,26 +929,68 @@ static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling,
                __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
        }
 
-       ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq");
-       if (ret) {
+       /* Don't touch sysfs links during light-weight init */
+       if (frozen) {
+               /* Drop the extra refcount that we took above */
                cpufreq_cpu_put(policy);
-               return ret;
+               return 0;
        }
 
-       return 0;
+       ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq");
+       if (ret)
+               cpufreq_cpu_put(policy);
+
+       return ret;
 }
 #endif
 
-/**
- * cpufreq_add_dev - add a CPU device
- *
- * Adds the cpufreq interface for a CPU device.
- *
- * The Oracle says: try running cpufreq registration/unregistration concurrently
- * with with cpu hotplugging and all hell will break loose. Tried to clean this
- * mess up, but more thorough testing is needed. - Mathieu
- */
-static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
+static struct cpufreq_policy *cpufreq_policy_restore(unsigned int cpu)
+{
+       struct cpufreq_policy *policy;
+       unsigned long flags;
+
+       write_lock_irqsave(&cpufreq_driver_lock, flags);
+
+       policy = per_cpu(cpufreq_cpu_data_fallback, cpu);
+
+       write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
+       return policy;
+}
+
+static struct cpufreq_policy *cpufreq_policy_alloc(void)
+{
+       struct cpufreq_policy *policy;
+
+       policy = kzalloc(sizeof(*policy), GFP_KERNEL);
+       if (!policy)
+               return NULL;
+
+       if (!alloc_cpumask_var(&policy->cpus, GFP_KERNEL))
+               goto err_free_policy;
+
+       if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL))
+               goto err_free_cpumask;
+
+       return policy;
+
+err_free_cpumask:
+       free_cpumask_var(policy->cpus);
+err_free_policy:
+       kfree(policy);
+
+       return NULL;
+}
+
+static void cpufreq_policy_free(struct cpufreq_policy *policy)
+{
+       free_cpumask_var(policy->related_cpus);
+       free_cpumask_var(policy->cpus);
+       kfree(policy);
+}
+
+static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
+                            bool frozen)
 {
        unsigned int j, cpu = dev->id;
        int ret = -ENOMEM;
@@ -985,7 +1022,8 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
                struct cpufreq_policy *cp = per_cpu(cpufreq_cpu_data, sibling);
                if (cp && cpumask_test_cpu(cpu, cp->related_cpus)) {
                        read_unlock_irqrestore(&cpufreq_driver_lock, flags);
-                       return cpufreq_add_policy_cpu(cpu, sibling, dev);
+                       return cpufreq_add_policy_cpu(cpu, sibling, dev,
+                                                     frozen);
                }
        }
        read_unlock_irqrestore(&cpufreq_driver_lock, flags);
@@ -997,16 +1035,15 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
                goto module_out;
        }
 
-       policy = kzalloc(sizeof(struct cpufreq_policy), GFP_KERNEL);
+       if (frozen)
+               /* Restore the saved policy when doing light-weight init */
+               policy = cpufreq_policy_restore(cpu);
+       else
+               policy = cpufreq_policy_alloc();
+
        if (!policy)
                goto nomem_out;
 
-       if (!alloc_cpumask_var(&policy->cpus, GFP_KERNEL))
-               goto err_free_policy;
-
-       if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL))
-               goto err_free_cpumask;
-
        policy->cpu = cpu;
        policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        cpumask_copy(policy->cpus, cpumask_of(cpu));
@@ -1050,9 +1087,20 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
        }
 #endif
 
-       ret = cpufreq_add_dev_interface(cpu, policy, dev);
-       if (ret)
-               goto err_out_unregister;
+       write_lock_irqsave(&cpufreq_driver_lock, flags);
+       for_each_cpu(j, policy->cpus) {
+               per_cpu(cpufreq_cpu_data, j) = policy;
+               per_cpu(cpufreq_policy_cpu, j) = policy->cpu;
+       }
+       write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
+       if (!frozen) {
+               ret = cpufreq_add_dev_interface(policy, dev);
+               if (ret)
+                       goto err_out_unregister;
+       }
+
+       cpufreq_init_policy(policy);
 
        kobject_uevent(&policy->kobj, KOBJ_ADD);
        module_put(cpufreq_driver->owner);
@@ -1062,8 +1110,11 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
 
 err_out_unregister:
        write_lock_irqsave(&cpufreq_driver_lock, flags);
-       for_each_cpu(j, policy->cpus)
+       for_each_cpu(j, policy->cpus) {
                per_cpu(cpufreq_cpu_data, j) = NULL;
+               if (j != cpu)
+                       per_cpu(cpufreq_policy_cpu, j) = -1;
+       }
        write_unlock_irqrestore(&cpufreq_driver_lock, flags);
 
        kobject_put(&policy->kobj);
@@ -1071,17 +1122,27 @@ err_out_unregister:
 
 err_set_policy_cpu:
        per_cpu(cpufreq_policy_cpu, cpu) = -1;
-       free_cpumask_var(policy->related_cpus);
-err_free_cpumask:
-       free_cpumask_var(policy->cpus);
-err_free_policy:
-       kfree(policy);
+       cpufreq_policy_free(policy);
 nomem_out:
        module_put(cpufreq_driver->owner);
 module_out:
        return ret;
 }
 
+/**
+ * cpufreq_add_dev - add a CPU device
+ *
+ * Adds the cpufreq interface for a CPU device.
+ *
+ * The Oracle says: try running cpufreq registration/unregistration concurrently
+ * with with cpu hotplugging and all hell will break loose. Tried to clean this
+ * mess up, but more thorough testing is needed. - Mathieu
+ */
+static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
+{
+       return __cpufreq_add_dev(dev, sif, false);
+}
+
 static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
 {
        int j;
@@ -1099,6 +1160,43 @@ static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
                        CPUFREQ_UPDATE_POLICY_CPU, policy);
 }
 
+static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *data,
+                                          unsigned int old_cpu, bool frozen)
+{
+       struct device *cpu_dev;
+       unsigned long flags;
+       int ret;
+
+       /* first sibling now owns the new sysfs dir */
+       cpu_dev = get_cpu_device(cpumask_first(data->cpus));
+
+       /* Don't touch sysfs files during light-weight tear-down */
+       if (frozen)
+               return cpu_dev->id;
+
+       sysfs_remove_link(&cpu_dev->kobj, "cpufreq");
+       ret = kobject_move(&data->kobj, &cpu_dev->kobj);
+       if (ret) {
+               pr_err("%s: Failed to move kobj: %d", __func__, ret);
+
+               WARN_ON(lock_policy_rwsem_write(old_cpu));
+               cpumask_set_cpu(old_cpu, data->cpus);
+
+               write_lock_irqsave(&cpufreq_driver_lock, flags);
+               per_cpu(cpufreq_cpu_data, old_cpu) = data;
+               write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
+               unlock_policy_rwsem_write(old_cpu);
+
+               ret = sysfs_create_link(&cpu_dev->kobj, &data->kobj,
+                                       "cpufreq");
+
+               return -EINVAL;
+       }
+
+       return cpu_dev->id;
+}
+
 /**
  * __cpufreq_remove_dev - remove a CPU device
  *
@@ -1107,14 +1205,14 @@ static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
  * This routine frees the rwsem before returning.
  */
 static int __cpufreq_remove_dev(struct device *dev,
-               struct subsys_interface *sif)
+                               struct subsys_interface *sif, bool frozen)
 {
-       unsigned int cpu = dev->id, ret, cpus;
+       unsigned int cpu = dev->id, cpus;
+       int new_cpu;
        unsigned long flags;
        struct cpufreq_policy *data;
        struct kobject *kobj;
        struct completion *cmp;
-       struct device *cpu_dev;
 
        pr_debug("%s: unregistering CPU %u\n", __func__, cpu);
 
@@ -1123,6 +1221,10 @@ static int __cpufreq_remove_dev(struct device *dev,
        data = per_cpu(cpufreq_cpu_data, cpu);
        per_cpu(cpufreq_cpu_data, cpu) = NULL;
 
+       /* Save the policy somewhere when doing a light-weight tear-down */
+       if (frozen)
+               per_cpu(cpufreq_cpu_data_fallback, cpu) = data;
+
        write_unlock_irqrestore(&cpufreq_driver_lock, flags);
 
        if (!data) {
@@ -1146,68 +1248,66 @@ static int __cpufreq_remove_dev(struct device *dev,
                cpumask_clear_cpu(cpu, data->cpus);
        unlock_policy_rwsem_write(cpu);
 
-       if (cpu != data->cpu) {
+       if (cpu != data->cpu && !frozen) {
                sysfs_remove_link(&dev->kobj, "cpufreq");
        } else if (cpus > 1) {
-               /* first sibling now owns the new sysfs dir */
-               cpu_dev = get_cpu_device(cpumask_first(data->cpus));
-               sysfs_remove_link(&cpu_dev->kobj, "cpufreq");
-               ret = kobject_move(&data->kobj, &cpu_dev->kobj);
-               if (ret) {
-                       pr_err("%s: Failed to move kobj: %d", __func__, ret);
 
+               new_cpu = cpufreq_nominate_new_policy_cpu(data, cpu, frozen);
+               if (new_cpu >= 0) {
                        WARN_ON(lock_policy_rwsem_write(cpu));
-                       cpumask_set_cpu(cpu, data->cpus);
-
-                       write_lock_irqsave(&cpufreq_driver_lock, flags);
-                       per_cpu(cpufreq_cpu_data, cpu) = data;
-                       write_unlock_irqrestore(&cpufreq_driver_lock, flags);
-
+                       update_policy_cpu(data, new_cpu);
                        unlock_policy_rwsem_write(cpu);
 
-                       ret = sysfs_create_link(&cpu_dev->kobj, &data->kobj,
-                                       "cpufreq");
-                       return -EINVAL;
+                       if (!frozen) {
+                               pr_debug("%s: policy Kobject moved to cpu: %d "
+                                        "from: %d\n",__func__, new_cpu, cpu);
+                       }
                }
-
-               WARN_ON(lock_policy_rwsem_write(cpu));
-               update_policy_cpu(data, cpu_dev->id);
-               unlock_policy_rwsem_write(cpu);
-               pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n",
-                               __func__, cpu_dev->id, cpu);
        }
 
-       if ((cpus == 1) && (cpufreq_driver->target))
-               __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT);
-
-       pr_debug("%s: removing link, cpu: %d\n", __func__, cpu);
-       cpufreq_cpu_put(data);
-
        /* If cpu is last user of policy, free policy */
        if (cpus == 1) {
-               lock_policy_rwsem_read(cpu);
-               kobj = &data->kobj;
-               cmp = &data->kobj_unregister;
-               unlock_policy_rwsem_read(cpu);
-               kobject_put(kobj);
-
-               /* we need to make sure that the underlying kobj is actually
-                * not referenced anymore by anybody before we proceed with
-                * unloading.
-                */
-               pr_debug("waiting for dropping of refcount\n");
-               wait_for_completion(cmp);
-               pr_debug("wait complete\n");
+               if (cpufreq_driver->target)
+                       __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT);
+
+               if (!frozen) {
+                       lock_policy_rwsem_read(cpu);
+                       kobj = &data->kobj;
+                       cmp = &data->kobj_unregister;
+                       unlock_policy_rwsem_read(cpu);
+                       kobject_put(kobj);
+
+                       /*
+                        * We need to make sure that the underlying kobj is
+                        * actually not referenced anymore by anybody before we
+                        * proceed with unloading.
+                        */
+                       pr_debug("waiting for dropping of refcount\n");
+                       wait_for_completion(cmp);
+                       pr_debug("wait complete\n");
+               }
 
+               /*
+                * Perform the ->exit() even during light-weight tear-down,
+                * since this is a core component, and is essential for the
+                * subsequent light-weight ->init() to succeed.
+                */
                if (cpufreq_driver->exit)
                        cpufreq_driver->exit(data);
 
-               free_cpumask_var(data->related_cpus);
-               free_cpumask_var(data->cpus);
-               kfree(data);
-       } else if (cpufreq_driver->target) {
-               __cpufreq_governor(data, CPUFREQ_GOV_START);
-               __cpufreq_governor(data, CPUFREQ_GOV_LIMITS);
+               if (!frozen)
+                       cpufreq_policy_free(data);
+       } else {
+
+               if (!frozen) {
+                       pr_debug("%s: removing link, cpu: %d\n", __func__, cpu);
+                       cpufreq_cpu_put(data);
+               }
+
+               if (cpufreq_driver->target) {
+                       __cpufreq_governor(data, CPUFREQ_GOV_START);
+                       __cpufreq_governor(data, CPUFREQ_GOV_LIMITS);
+               }
        }
 
        per_cpu(cpufreq_policy_cpu, cpu) = -1;
@@ -1222,7 +1322,7 @@ static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
        if (cpu_is_offline(cpu))
                return 0;
 
-       retval = __cpufreq_remove_dev(dev, sif);
+       retval = __cpufreq_remove_dev(dev, sif, false);
        return retval;
 }
 
@@ -1593,18 +1693,6 @@ fail:
 }
 EXPORT_SYMBOL_GPL(cpufreq_driver_target);
 
-int __cpufreq_driver_getavg(struct cpufreq_policy *policy, unsigned int cpu)
-{
-       if (cpufreq_disabled())
-               return 0;
-
-       if (!cpufreq_driver->getavg)
-               return 0;
-
-       return cpufreq_driver->getavg(policy, cpu);
-}
-EXPORT_SYMBOL_GPL(__cpufreq_driver_getavg);
-
 /*
  * when "event" is CPUFREQ_GOV_LIMITS
  */
@@ -1937,21 +2025,26 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
 {
        unsigned int cpu = (unsigned long)hcpu;
        struct device *dev;
+       bool frozen = false;
 
        dev = get_cpu_device(cpu);
        if (dev) {
-               switch (action) {
+
+               if (action & CPU_TASKS_FROZEN)
+                       frozen = true;
+
+               switch (action & ~CPU_TASKS_FROZEN) {
                case CPU_ONLINE:
-               case CPU_ONLINE_FROZEN:
-                       cpufreq_add_dev(dev, NULL);
+                       __cpufreq_add_dev(dev, NULL, frozen);
+                       cpufreq_update_policy(cpu);
                        break;
+
                case CPU_DOWN_PREPARE:
-               case CPU_DOWN_PREPARE_FROZEN:
-                       __cpufreq_remove_dev(dev, NULL);
+                       __cpufreq_remove_dev(dev, NULL, frozen);
                        break;
+
                case CPU_DOWN_FAILED:
-               case CPU_DOWN_FAILED_FROZEN:
-                       cpufreq_add_dev(dev, NULL);
+                       __cpufreq_add_dev(dev, NULL, frozen);
                        break;
                }
        }
index 7b839a8db2a7ae6f0bc647e249c326a70623b62a..7409dbd1d897d7ee6a3a5f23ceef1ce02f392f31 100644 (file)
@@ -53,7 +53,7 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
 
        policy = cdbs->cur_policy;
 
-       /* Get Absolute Load (in terms of freq for ondemand gov) */
+       /* Get Absolute Load */
        for_each_cpu(j, policy->cpus) {
                struct cpu_dbs_common_info *j_cdbs;
                u64 cur_wall_time, cur_idle_time;
@@ -104,14 +104,6 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
 
                load = 100 * (wall_time - idle_time) / wall_time;
 
-               if (dbs_data->cdata->governor == GOV_ONDEMAND) {
-                       int freq_avg = __cpufreq_driver_getavg(policy, j);
-                       if (freq_avg <= 0)
-                               freq_avg = policy->cur;
-
-                       load *= freq_avg;
-               }
-
                if (load > max_load)
                        max_load = load;
        }
index 6663ec3b30565ac7efb6a7b5842e301ad2160bba..0e0dd4c82020b480444ed076c0679409fe3e5f00 100644 (file)
@@ -169,7 +169,6 @@ struct od_dbs_tuners {
        unsigned int sampling_rate;
        unsigned int sampling_down_factor;
        unsigned int up_threshold;
-       unsigned int adj_up_threshold;
        unsigned int powersave_bias;
        unsigned int io_is_busy;
 };
index 93eb5cbcc1f639bf1ec52479a169a49deecd72f5..a3c5574f9b3a9ef2383789a77e056dab9648255f 100644 (file)
 #include "cpufreq_governor.h"
 
 /* On-demand governor macros */
-#define DEF_FREQUENCY_DOWN_DIFFERENTIAL                (10)
 #define DEF_FREQUENCY_UP_THRESHOLD             (80)
 #define DEF_SAMPLING_DOWN_FACTOR               (1)
 #define MAX_SAMPLING_DOWN_FACTOR               (100000)
-#define MICRO_FREQUENCY_DOWN_DIFFERENTIAL      (3)
 #define MICRO_FREQUENCY_UP_THRESHOLD           (95)
 #define MICRO_FREQUENCY_MIN_SAMPLE_RATE                (10000)
 #define MIN_FREQUENCY_UP_THRESHOLD             (11)
@@ -161,14 +159,10 @@ static void dbs_freq_increase(struct cpufreq_policy *p, unsigned int freq)
 
 /*
  * Every sampling_rate, we check, if current idle time is less than 20%
- * (default), then we try to increase frequency. Every sampling_rate, we look
- * for the lowest frequency which can sustain the load while keeping idle time
- * over 30%. If such a frequency exist, we try to decrease to this frequency.
- *
- * Any frequency increase takes it to the maximum frequency. Frequency reduction
- * happens at minimum steps of 5% (default) of current frequency
+ * (default), then we try to increase frequency. Else, we adjust the frequency
+ * proportional to load.
  */
-static void od_check_cpu(int cpu, unsigned int load_freq)
+static void od_check_cpu(int cpu, unsigned int load)
 {
        struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
        struct cpufreq_policy *policy = dbs_info->cdbs.cur_policy;
@@ -178,29 +172,17 @@ static void od_check_cpu(int cpu, unsigned int load_freq)
        dbs_info->freq_lo = 0;
 
        /* Check for frequency increase */
-       if (load_freq > od_tuners->up_threshold * policy->cur) {
+       if (load > od_tuners->up_threshold) {
                /* If switching to max speed, apply sampling_down_factor */
                if (policy->cur < policy->max)
                        dbs_info->rate_mult =
                                od_tuners->sampling_down_factor;
                dbs_freq_increase(policy, policy->max);
                return;
-       }
-
-       /* Check for frequency decrease */
-       /* if we cannot reduce the frequency anymore, break out early */
-       if (policy->cur == policy->min)
-               return;
-
-       /*
-        * The optimal frequency is the frequency that is the lowest that can
-        * support the current CPU usage without triggering the up policy. To be
-        * safe, we focus 10 points under the threshold.
-        */
-       if (load_freq < od_tuners->adj_up_threshold
-                       * policy->cur) {
+       } else {
+               /* Calculate the next frequency proportional to load */
                unsigned int freq_next;
-               freq_next = load_freq / od_tuners->adj_up_threshold;
+               freq_next = load * policy->cpuinfo.max_freq / 100;
 
                /* No longer fully busy, reset rate_mult */
                dbs_info->rate_mult = 1;
@@ -374,9 +356,6 @@ static ssize_t store_up_threshold(struct dbs_data *dbs_data, const char *buf,
                        input < MIN_FREQUENCY_UP_THRESHOLD) {
                return -EINVAL;
        }
-       /* Calculate the new adj_up_threshold */
-       od_tuners->adj_up_threshold += input;
-       od_tuners->adj_up_threshold -= od_tuners->up_threshold;
 
        od_tuners->up_threshold = input;
        return count;
@@ -525,8 +504,6 @@ static int od_init(struct dbs_data *dbs_data)
        if (idle_time != -1ULL) {
                /* Idle micro accounting is supported. Use finer thresholds */
                tuners->up_threshold = MICRO_FREQUENCY_UP_THRESHOLD;
-               tuners->adj_up_threshold = MICRO_FREQUENCY_UP_THRESHOLD -
-                       MICRO_FREQUENCY_DOWN_DIFFERENTIAL;
                /*
                 * In nohz/micro accounting case we set the minimum frequency
                 * not depending on HZ, but fixed (very low). The deferred
@@ -535,8 +512,6 @@ static int od_init(struct dbs_data *dbs_data)
                dbs_data->min_sampling_rate = MICRO_FREQUENCY_MIN_SAMPLE_RATE;
        } else {
                tuners->up_threshold = DEF_FREQUENCY_UP_THRESHOLD;
-               tuners->adj_up_threshold = DEF_FREQUENCY_UP_THRESHOLD -
-                       DEF_FREQUENCY_DOWN_DIFFERENTIAL;
 
                /* For correct statistics, we need 10 ticks for each measure */
                dbs_data->min_sampling_rate = MIN_SAMPLING_RATE_RATIO *
index d37568c5ca9c36b32dc69a8361337450c0ca1ddc..cb3841355454f0d79b73db914f59328a4400c99e 100644 (file)
@@ -348,16 +348,10 @@ static int cpufreq_stat_cpu_callback(struct notifier_block *nfb,
        unsigned int cpu = (unsigned long)hcpu;
 
        switch (action) {
-       case CPU_ONLINE:
-       case CPU_ONLINE_FROZEN:
-               cpufreq_update_policy(cpu);
-               break;
        case CPU_DOWN_PREPARE:
-       case CPU_DOWN_PREPARE_FROZEN:
                cpufreq_stats_free_sysfs(cpu);
                break;
        case CPU_DEAD:
-       case CPU_DEAD_FROZEN:
                cpufreq_stats_free_table(cpu);
                break;
        }
@@ -390,8 +384,6 @@ static int __init cpufreq_stats_init(void)
                return ret;
 
        register_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
-       for_each_online_cpu(cpu)
-               cpufreq_update_policy(cpu);
 
        ret = cpufreq_register_notifier(&notifier_trans_block,
                                CPUFREQ_TRANSITION_NOTIFIER);
diff --git a/drivers/cpufreq/mperf.c b/drivers/cpufreq/mperf.c
deleted file mode 100644 (file)
index 911e193..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/smp.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/cpufreq.h>
-#include <linux/slab.h>
-
-#include "mperf.h"
-
-static DEFINE_PER_CPU(struct aperfmperf, acfreq_old_perf);
-
-/* Called via smp_call_function_single(), on the target CPU */
-static void read_measured_perf_ctrs(void *_cur)
-{
-       struct aperfmperf *am = _cur;
-
-       get_aperfmperf(am);
-}
-
-/*
- * Return the measured active (C0) frequency on this CPU since last call
- * to this function.
- * Input: cpu number
- * Return: Average CPU frequency in terms of max frequency (zero on error)
- *
- * We use IA32_MPERF and IA32_APERF MSRs to get the measured performance
- * over a period of time, while CPU is in C0 state.
- * IA32_MPERF counts at the rate of max advertised frequency
- * IA32_APERF counts at the rate of actual CPU frequency
- * Only IA32_APERF/IA32_MPERF ratio is architecturally defined and
- * no meaning should be associated with absolute values of these MSRs.
- */
-unsigned int cpufreq_get_measured_perf(struct cpufreq_policy *policy,
-                                       unsigned int cpu)
-{
-       struct aperfmperf perf;
-       unsigned long ratio;
-       unsigned int retval;
-
-       if (smp_call_function_single(cpu, read_measured_perf_ctrs, &perf, 1))
-               return 0;
-
-       ratio = calc_aperfmperf_ratio(&per_cpu(acfreq_old_perf, cpu), &perf);
-       per_cpu(acfreq_old_perf, cpu) = perf;
-
-       retval = (policy->cpuinfo.max_freq * ratio) >> APERFMPERF_SHIFT;
-
-       return retval;
-}
-EXPORT_SYMBOL_GPL(cpufreq_get_measured_perf);
-MODULE_LICENSE("GPL");
diff --git a/drivers/cpufreq/mperf.h b/drivers/cpufreq/mperf.h
deleted file mode 100644 (file)
index 5dbf295..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- *  (c) 2010 Advanced Micro Devices, Inc.
- *  Your use of this code is subject to the terms and conditions of the
- *  GNU general public license version 2. See "COPYING" or
- *  http://www.gnu.org/licenses/gpl.html
- */
-
-unsigned int cpufreq_get_measured_perf(struct cpufreq_policy *policy,
-                                       unsigned int cpu);
index 0e2cd5cab4d0924392d8c4d0a99ffb9a75d4485e..b3fb81d7cf0410bb9358d94a4e345899323f1ef3 100644 (file)
@@ -1,5 +1,6 @@
+menu "CPU Idle"
 
-menuconfig CPU_IDLE
+config CPU_IDLE
        bool "CPU idle PM support"
        default y if ACPI || PPC_PSERIES
        select CPU_IDLE_GOV_LADDER if (!NO_HZ && !NO_HZ_IDLE)
@@ -29,20 +30,13 @@ config CPU_IDLE_GOV_MENU
        bool "Menu governor (for tickless system)"
        default y
 
-config CPU_IDLE_CALXEDA
-       bool "CPU Idle Driver for Calxeda processors"
-       depends on ARCH_HIGHBANK
-       select ARM_CPU_SUSPEND
-       help
-         Select this to enable cpuidle on Calxeda processors.
-
-config CPU_IDLE_ZYNQ
-       bool "CPU Idle Driver for Xilinx Zynq processors"
-       depends on ARCH_ZYNQ
-       help
-         Select this to enable cpuidle on Xilinx Zynq processors.
+menu "ARM CPU Idle Drivers"
+depends on ARM
+source "drivers/cpuidle/Kconfig.arm"
+endmenu
 
 endif
 
 config ARCH_NEEDS_CPU_IDLE_COUPLED
        def_bool n
+endmenu
diff --git a/drivers/cpuidle/Kconfig.arm b/drivers/cpuidle/Kconfig.arm
new file mode 100644 (file)
index 0000000..b330219
--- /dev/null
@@ -0,0 +1,29 @@
+#
+# ARM CPU Idle drivers
+#
+
+config ARM_HIGHBANK_CPUIDLE
+       bool "CPU Idle Driver for Calxeda processors"
+       depends on ARCH_HIGHBANK
+       select ARM_CPU_SUSPEND
+       help
+         Select this to enable cpuidle on Calxeda processors.
+
+config ARM_KIRKWOOD_CPUIDLE
+       bool "CPU Idle Driver for Marvell Kirkwood SoCs"
+       depends on ARCH_KIRKWOOD
+       help
+         This adds the CPU Idle driver for Marvell Kirkwood SoCs.
+
+config ARM_ZYNQ_CPUIDLE
+       bool "CPU Idle Driver for Xilinx Zynq processors"
+       depends on ARCH_ZYNQ
+       help
+         Select this to enable cpuidle on Xilinx Zynq processors.
+
+config ARM_U8500_CPUIDLE
+       bool "Cpu Idle Driver for the ST-E u8500 processors"
+       depends on ARCH_U8500
+       help
+         Select this to enable cpuidle for ST-E u8500 processors
+
index 8767a7b3eb913d9b5eb530f6df208eafe6476aa2..0b9d200c7e454eefd4864abbc83bfee7f7dcb129 100644 (file)
@@ -5,6 +5,9 @@
 obj-y += cpuidle.o driver.o governor.o sysfs.o governors/
 obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o
 
-obj-$(CONFIG_CPU_IDLE_CALXEDA) += cpuidle-calxeda.o
-obj-$(CONFIG_ARCH_KIRKWOOD) += cpuidle-kirkwood.o
-obj-$(CONFIG_CPU_IDLE_ZYNQ) += cpuidle-zynq.o
+##################################################################################
+# ARM SoC drivers
+obj-$(CONFIG_ARM_HIGHBANK_CPUIDLE)     += cpuidle-calxeda.o
+obj-$(CONFIG_ARM_KIRKWOOD_CPUIDLE)     += cpuidle-kirkwood.o
+obj-$(CONFIG_ARM_ZYNQ_CPUIDLE)         += cpuidle-zynq.o
+obj-$(CONFIG_ARM_U8500_CPUIDLE)         += cpuidle-ux500.o
similarity index 90%
rename from arch/arm/mach-ux500/cpuidle.c
rename to drivers/cpuidle/cpuidle-ux500.c
index a45dd09daed9212c2d799ce1ef9421be8d13bab5..e0564652af35114f2d73227b68bf781758975629 100644 (file)
 #include <linux/smp.h>
 #include <linux/mfd/dbx500-prcmu.h>
 #include <linux/platform_data/arm-ux500-pm.h>
+#include <linux/platform_device.h>
 
 #include <asm/cpuidle.h>
 #include <asm/proc-fns.h>
 
-#include "db8500-regs.h"
-#include "id.h"
-
 static atomic_t master = ATOMIC_INIT(0);
 static DEFINE_SPINLOCK(master_lock);
 
@@ -113,11 +111,8 @@ static struct cpuidle_driver ux500_idle_driver = {
        .state_count = 2,
 };
 
-int __init ux500_idle_init(void)
+static int __init dbx500_cpuidle_probe(struct platform_device *pdev)
 {
-       if (!(cpu_is_u8500_family() || cpu_is_ux540_family()))
-               return -ENODEV;
-
        /* Configure wake up reasons */
        prcmu_enable_wakeups(PRCMU_WAKEUP(ARM) | PRCMU_WAKEUP(RTC) |
                             PRCMU_WAKEUP(ABB));
@@ -125,4 +120,12 @@ int __init ux500_idle_init(void)
        return cpuidle_register(&ux500_idle_driver, NULL);
 }
 
-device_initcall(ux500_idle_init);
+static struct platform_driver dbx500_cpuidle_plat_driver = {
+       .driver = {
+               .name = "cpuidle-dbx500",
+               .owner = THIS_MODULE,
+       },
+       .probe = dbx500_cpuidle_probe,
+};
+
+module_platform_driver(dbx500_cpuidle_plat_driver);
index fdc432f18022b331f2102dccf13b539e74fae3ec..d75040ddd2b3ba8e317dfc76f5367faa62340b8f 100644 (file)
@@ -42,8 +42,6 @@ void disable_cpuidle(void)
        off = 1;
 }
 
-static int __cpuidle_register_device(struct cpuidle_device *dev);
-
 /**
  * cpuidle_play_dead - cpu off-lining
  *
@@ -278,7 +276,7 @@ static void poll_idle_init(struct cpuidle_driver *drv) {}
  */
 int cpuidle_enable_device(struct cpuidle_device *dev)
 {
-       int ret, i;
+       int ret;
        struct cpuidle_driver *drv;
 
        if (!dev)
@@ -292,15 +290,12 @@ int cpuidle_enable_device(struct cpuidle_device *dev)
        if (!drv || !cpuidle_curr_governor)
                return -EIO;
 
+       if (!dev->registered)
+               return -EINVAL;
+
        if (!dev->state_count)
                dev->state_count = drv->state_count;
 
-       if (dev->registered == 0) {
-               ret = __cpuidle_register_device(dev);
-               if (ret)
-                       return ret;
-       }
-
        poll_idle_init(drv);
 
        ret = cpuidle_add_device_sysfs(dev);
@@ -311,12 +306,6 @@ int cpuidle_enable_device(struct cpuidle_device *dev)
            (ret = cpuidle_curr_governor->enable(drv, dev)))
                goto fail_sysfs;
 
-       for (i = 0; i < dev->state_count; i++) {
-               dev->states_usage[i].usage = 0;
-               dev->states_usage[i].time = 0;
-       }
-       dev->last_residency = 0;
-
        smp_wmb();
 
        dev->enabled = 1;
@@ -360,6 +349,23 @@ void cpuidle_disable_device(struct cpuidle_device *dev)
 
 EXPORT_SYMBOL_GPL(cpuidle_disable_device);
 
+static void __cpuidle_unregister_device(struct cpuidle_device *dev)
+{
+       struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
+
+       list_del(&dev->device_list);
+       per_cpu(cpuidle_devices, dev->cpu) = NULL;
+       module_put(drv->owner);
+}
+
+static int __cpuidle_device_init(struct cpuidle_device *dev)
+{
+       memset(dev->states_usage, 0, sizeof(dev->states_usage));
+       dev->last_residency = 0;
+
+       return 0;
+}
+
 /**
  * __cpuidle_register_device - internal register function called before register
  * and enable routines
@@ -377,24 +383,15 @@ static int __cpuidle_register_device(struct cpuidle_device *dev)
 
        per_cpu(cpuidle_devices, dev->cpu) = dev;
        list_add(&dev->device_list, &cpuidle_detected_devices);
-       ret = cpuidle_add_sysfs(dev);
-       if (ret)
-               goto err_sysfs;
 
        ret = cpuidle_coupled_register_device(dev);
-       if (ret)
-               goto err_coupled;
+       if (ret) {
+               __cpuidle_unregister_device(dev);
+               return ret;
+       }
 
        dev->registered = 1;
        return 0;
-
-err_coupled:
-       cpuidle_remove_sysfs(dev);
-err_sysfs:
-       list_del(&dev->device_list);
-       per_cpu(cpuidle_devices, dev->cpu) = NULL;
-       module_put(drv->owner);
-       return ret;
 }
 
 /**
@@ -403,25 +400,44 @@ err_sysfs:
  */
 int cpuidle_register_device(struct cpuidle_device *dev)
 {
-       int ret;
+       int ret = -EBUSY;
 
        if (!dev)
                return -EINVAL;
 
        mutex_lock(&cpuidle_lock);
 
-       if ((ret = __cpuidle_register_device(dev))) {
-               mutex_unlock(&cpuidle_lock);
-               return ret;
-       }
+       if (dev->registered)
+               goto out_unlock;
+
+       ret = __cpuidle_device_init(dev);
+       if (ret)
+               goto out_unlock;
+
+       ret = __cpuidle_register_device(dev);
+       if (ret)
+               goto out_unlock;
+
+       ret = cpuidle_add_sysfs(dev);
+       if (ret)
+               goto out_unregister;
+
+       ret = cpuidle_enable_device(dev);
+       if (ret)
+               goto out_sysfs;
 
-       cpuidle_enable_device(dev);
        cpuidle_install_idle_handler();
 
+out_unlock:
        mutex_unlock(&cpuidle_lock);
 
-       return 0;
+       return ret;
 
+out_sysfs:
+       cpuidle_remove_sysfs(dev);
+out_unregister:
+       __cpuidle_unregister_device(dev);
+       goto out_unlock;
 }
 
 EXPORT_SYMBOL_GPL(cpuidle_register_device);
@@ -432,8 +448,6 @@ EXPORT_SYMBOL_GPL(cpuidle_register_device);
  */
 void cpuidle_unregister_device(struct cpuidle_device *dev)
 {
-       struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
-
        if (dev->registered == 0)
                return;
 
@@ -442,14 +456,12 @@ void cpuidle_unregister_device(struct cpuidle_device *dev)
        cpuidle_disable_device(dev);
 
        cpuidle_remove_sysfs(dev);
-       list_del(&dev->device_list);
-       per_cpu(cpuidle_devices, dev->cpu) = NULL;
+
+       __cpuidle_unregister_device(dev);
 
        cpuidle_coupled_unregister_device(dev);
 
        cpuidle_resume_and_unlock();
-
-       module_put(drv->owner);
 }
 
 EXPORT_SYMBOL_GPL(cpuidle_unregister_device);
index 9b784051ec12b47564b3d07429096556b2fc2035..9f08e8cce1af89c17b14bfed7358382b7ae3e542 100644 (file)
@@ -192,14 +192,4 @@ static int __init init_ladder(void)
        return cpuidle_register_governor(&ladder_governor);
 }
 
-/**
- * exit_ladder - exits the governor
- */
-static void __exit exit_ladder(void)
-{
-       cpuidle_unregister_governor(&ladder_governor);
-}
-
-MODULE_LICENSE("GPL");
-module_init(init_ladder);
-module_exit(exit_ladder);
+postcore_initcall(init_ladder);
index fe343a06b7da3278ba68c9c15c261ea14afde685..cbbb73b37a6d1d0d99a9d4613633324ef0833219 100644 (file)
 #define MAX_INTERESTING 50000
 #define STDDEV_THRESH 400
 
-/* 60 * 60 > STDDEV_THRESH * INTERVALS = 400 * 8 */
-#define MAX_DEVIATION 60
-
-static DEFINE_PER_CPU(struct hrtimer, menu_hrtimer);
-static DEFINE_PER_CPU(int, hrtimer_status);
-/* menu hrtimer mode */
-enum {MENU_HRTIMER_STOP, MENU_HRTIMER_REPEAT, MENU_HRTIMER_GENERAL};
 
 /*
  * Concepts and ideas behind the menu governor
@@ -116,13 +109,6 @@ enum {MENU_HRTIMER_STOP, MENU_HRTIMER_REPEAT, MENU_HRTIMER_GENERAL};
  *
  */
 
-/*
- * The C-state residency is so long that is is worthwhile to exit
- * from the shallow C-state and re-enter into a deeper C-state.
- */
-static unsigned int perfect_cstate_ms __read_mostly = 30;
-module_param(perfect_cstate_ms, uint, 0000);
-
 struct menu_device {
        int             last_state_idx;
        int             needs_update;
@@ -205,52 +191,17 @@ static u64 div_round64(u64 dividend, u32 divisor)
        return div_u64(dividend + (divisor / 2), divisor);
 }
 
-/* Cancel the hrtimer if it is not triggered yet */
-void menu_hrtimer_cancel(void)
-{
-       int cpu = smp_processor_id();
-       struct hrtimer *hrtmr = &per_cpu(menu_hrtimer, cpu);
-
-       /* The timer is still not time out*/
-       if (per_cpu(hrtimer_status, cpu)) {
-               hrtimer_cancel(hrtmr);
-               per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_STOP;
-       }
-}
-EXPORT_SYMBOL_GPL(menu_hrtimer_cancel);
-
-/* Call back for hrtimer is triggered */
-static enum hrtimer_restart menu_hrtimer_notify(struct hrtimer *hrtimer)
-{
-       int cpu = smp_processor_id();
-       struct menu_device *data = &per_cpu(menu_devices, cpu);
-
-       /* In general case, the expected residency is much larger than
-        *  deepest C-state target residency, but prediction logic still
-        *  predicts a small predicted residency, so the prediction
-        *  history is totally broken if the timer is triggered.
-        *  So reset the correction factor.
-        */
-       if (per_cpu(hrtimer_status, cpu) == MENU_HRTIMER_GENERAL)
-               data->correction_factor[data->bucket] = RESOLUTION * DECAY;
-
-       per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_STOP;
-
-       return HRTIMER_NORESTART;
-}
-
 /*
  * Try detecting repeating patterns by keeping track of the last 8
  * intervals, and checking if the standard deviation of that set
  * of points is below a threshold. If it is... then use the
  * average of these 8 points as the estimated value.
  */
-static u32 get_typical_interval(struct menu_device *data)
+static void get_typical_interval(struct menu_device *data)
 {
        int i = 0, divisor = 0;
        uint64_t max = 0, avg = 0, stddev = 0;
        int64_t thresh = LLONG_MAX; /* Discard outliers above this value. */
-       unsigned int ret = 0;
 
 again:
 
@@ -291,16 +242,13 @@ again:
        if (((avg > stddev * 6) && (divisor * 4 >= INTERVALS * 3))
                                                        || stddev <= 20) {
                data->predicted_us = avg;
-               ret = 1;
-               return ret;
+               return;
 
        } else if ((divisor * 4) > INTERVALS * 3) {
                /* Exclude the max interval */
                thresh = max - 1;
                goto again;
        }
-
-       return ret;
 }
 
 /**
@@ -315,9 +263,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
        int i;
        int multiplier;
        struct timespec t;
-       int repeat = 0, low_predicted = 0;
-       int cpu = smp_processor_id();
-       struct hrtimer *hrtmr = &per_cpu(menu_hrtimer, cpu);
 
        if (data->needs_update) {
                menu_update(drv, dev);
@@ -352,7 +297,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
        data->predicted_us = div_round64(data->expected_us * data->correction_factor[data->bucket],
                                         RESOLUTION * DECAY);
 
-       repeat = get_typical_interval(data);
+       get_typical_interval(data);
 
        /*
         * We want to default to C1 (hlt), not to busy polling
@@ -373,10 +318,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
 
                if (s->disabled || su->disable)
                        continue;
-               if (s->target_residency > data->predicted_us) {
-                       low_predicted = 1;
+               if (s->target_residency > data->predicted_us)
                        continue;
-               }
                if (s->exit_latency > latency_req)
                        continue;
                if (s->exit_latency * multiplier > data->predicted_us)
@@ -386,44 +329,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
                data->exit_us = s->exit_latency;
        }
 
-       /* not deepest C-state chosen for low predicted residency */
-       if (low_predicted) {
-               unsigned int timer_us = 0;
-               unsigned int perfect_us = 0;
-
-               /*
-                * Set a timer to detect whether this sleep is much
-                * longer than repeat mode predicted.  If the timer
-                * triggers, the code will evaluate whether to put
-                * the CPU into a deeper C-state.
-                * The timer is cancelled on CPU wakeup.
-                */
-               timer_us = 2 * (data->predicted_us + MAX_DEVIATION);
-
-               perfect_us = perfect_cstate_ms * 1000;
-
-               if (repeat && (4 * timer_us < data->expected_us)) {
-                       RCU_NONIDLE(hrtimer_start(hrtmr,
-                               ns_to_ktime(1000 * timer_us),
-                               HRTIMER_MODE_REL_PINNED));
-                       /* In repeat case, menu hrtimer is started */
-                       per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_REPEAT;
-               } else if (perfect_us < data->expected_us) {
-                       /*
-                        * The next timer is long. This could be because
-                        * we did not make a useful prediction.
-                        * In that case, it makes sense to re-enter
-                        * into a deeper C-state after some time.
-                        */
-                       RCU_NONIDLE(hrtimer_start(hrtmr,
-                               ns_to_ktime(1000 * timer_us),
-                               HRTIMER_MODE_REL_PINNED));
-                       /* In general case, menu hrtimer is started */
-                       per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_GENERAL;
-               }
-
-       }
-
        return data->last_state_idx;
 }
 
@@ -514,9 +419,6 @@ static int menu_enable_device(struct cpuidle_driver *drv,
                                struct cpuidle_device *dev)
 {
        struct menu_device *data = &per_cpu(menu_devices, dev->cpu);
-       struct hrtimer *t = &per_cpu(menu_hrtimer, dev->cpu);
-       hrtimer_init(t, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-       t->function = menu_hrtimer_notify;
 
        memset(data, 0, sizeof(struct menu_device));
 
@@ -540,14 +442,4 @@ static int __init init_menu(void)
        return cpuidle_register_governor(&menu_governor);
 }
 
-/**
- * exit_menu - exits the governor
- */
-static void __exit exit_menu(void)
-{
-       cpuidle_unregister_governor(&menu_governor);
-}
-
-MODULE_LICENSE("GPL");
-module_init(init_menu);
-module_exit(exit_menu);
+postcore_initcall(init_menu);
index 428754af62366cda8fe71dee47b128c5da602969..8739cc05228ca97512a60b9cc3770097f3a044aa 100644 (file)
 #include <linux/sysfs.h>
 #include <linux/slab.h>
 #include <linux/cpu.h>
+#include <linux/completion.h>
 #include <linux/capability.h>
 #include <linux/device.h>
+#include <linux/kobject.h>
 
 #include "cpuidle.h"
 
@@ -33,7 +35,8 @@ static ssize_t show_available_governors(struct device *dev,
 
        mutex_lock(&cpuidle_lock);
        list_for_each_entry(tmp, &cpuidle_governors, governor_list) {
-               if (i >= (ssize_t) ((PAGE_SIZE/sizeof(char)) - CPUIDLE_NAME_LEN - 2))
+               if (i >= (ssize_t) ((PAGE_SIZE/sizeof(char)) -
+                                   CPUIDLE_NAME_LEN - 2))
                        goto out;
                i += scnprintf(&buf[i], CPUIDLE_NAME_LEN, "%s ", tmp->name);
        }
@@ -166,13 +169,28 @@ struct cpuidle_attr {
 #define define_one_rw(_name, show, store) \
        static struct cpuidle_attr attr_##_name = __ATTR(_name, 0644, show, store)
 
-#define kobj_to_cpuidledev(k) container_of(k, struct cpuidle_device, kobj)
 #define attr_to_cpuidleattr(a) container_of(a, struct cpuidle_attr, attr)
-static ssize_t cpuidle_show(struct kobject * kobj, struct attribute * attr ,char * buf)
+
+struct cpuidle_device_kobj {
+       struct cpuidle_device *dev;
+       struct completion kobj_unregister;
+       struct kobject kobj;
+};
+
+static inline struct cpuidle_device *to_cpuidle_device(struct kobject *kobj)
+{
+       struct cpuidle_device_kobj *kdev =
+               container_of(kobj, struct cpuidle_device_kobj, kobj);
+
+       return kdev->dev;
+}
+
+static ssize_t cpuidle_show(struct kobject *kobj, struct attribute *attr,
+                           char *buf)
 {
        int ret = -EIO;
-       struct cpuidle_device *dev = kobj_to_cpuidledev(kobj);
-       struct cpuidle_attr * cattr = attr_to_cpuidleattr(attr);
+       struct cpuidle_device *dev = to_cpuidle_device(kobj);
+       struct cpuidle_attr *cattr = attr_to_cpuidleattr(attr);
 
        if (cattr->show) {
                mutex_lock(&cpuidle_lock);
@@ -182,12 +200,12 @@ static ssize_t cpuidle_show(struct kobject * kobj, struct attribute * attr ,char
        return ret;
 }
 
-static ssize_t cpuidle_store(struct kobject * kobj, struct attribute * attr,
-                    const char * buf, size_t count)
+static ssize_t cpuidle_store(struct kobject *kobj, struct attribute *attr,
+                            const char *buf, size_t count)
 {
        int ret = -EIO;
-       struct cpuidle_device *dev = kobj_to_cpuidledev(kobj);
-       struct cpuidle_attr * cattr = attr_to_cpuidleattr(attr);
+       struct cpuidle_device *dev = to_cpuidle_device(kobj);
+       struct cpuidle_attr *cattr = attr_to_cpuidleattr(attr);
 
        if (cattr->store) {
                mutex_lock(&cpuidle_lock);
@@ -204,9 +222,10 @@ static const struct sysfs_ops cpuidle_sysfs_ops = {
 
 static void cpuidle_sysfs_release(struct kobject *kobj)
 {
-       struct cpuidle_device *dev = kobj_to_cpuidledev(kobj);
+       struct cpuidle_device_kobj *kdev =
+               container_of(kobj, struct cpuidle_device_kobj, kobj);
 
-       complete(&dev->kobj_unregister);
+       complete(&kdev->kobj_unregister);
 }
 
 static struct kobj_type ktype_cpuidle = {
@@ -237,8 +256,8 @@ static ssize_t show_state_##_name(struct cpuidle_state *state, \
 
 #define define_store_state_ull_function(_name) \
 static ssize_t store_state_##_name(struct cpuidle_state *state, \
-               struct cpuidle_state_usage *state_usage, \
-               const char *buf, size_t size) \
+                                  struct cpuidle_state_usage *state_usage, \
+                                  const char *buf, size_t size)        \
 { \
        unsigned long long value; \
        int err; \
@@ -256,14 +275,16 @@ static ssize_t store_state_##_name(struct cpuidle_state *state, \
 
 #define define_show_state_ull_function(_name) \
 static ssize_t show_state_##_name(struct cpuidle_state *state, \
-                       struct cpuidle_state_usage *state_usage, char *buf) \
+                                 struct cpuidle_state_usage *state_usage, \
+                                 char *buf)                            \
 { \
        return sprintf(buf, "%llu\n", state_usage->_name);\
 }
 
 #define define_show_state_str_function(_name) \
 static ssize_t show_state_##_name(struct cpuidle_state *state, \
-                       struct cpuidle_state_usage *state_usage, char *buf) \
+                                 struct cpuidle_state_usage *state_usage, \
+                                 char *buf)                            \
 { \
        if (state->_name[0] == '\0')\
                return sprintf(buf, "<null>\n");\
@@ -309,8 +330,9 @@ struct cpuidle_state_kobj {
 #define kobj_to_state(k) (kobj_to_state_obj(k)->state)
 #define kobj_to_state_usage(k) (kobj_to_state_obj(k)->state_usage)
 #define attr_to_stateattr(a) container_of(a, struct cpuidle_state_attr, attr)
-static ssize_t cpuidle_state_show(struct kobject * kobj,
-       struct attribute * attr ,char * buf)
+
+static ssize_t cpuidle_state_show(struct kobject *kobj, struct attribute *attr,
+                                 char * buf)
 {
        int ret = -EIO;
        struct cpuidle_state *state = kobj_to_state(kobj);
@@ -323,8 +345,8 @@ static ssize_t cpuidle_state_show(struct kobject * kobj,
        return ret;
 }
 
-static ssize_t cpuidle_state_store(struct kobject *kobj,
-       struct attribute *attr, const char *buf, size_t size)
+static ssize_t cpuidle_state_store(struct kobject *kobj, struct attribute *attr,
+                                  const char *buf, size_t size)
 {
        int ret = -EIO;
        struct cpuidle_state *state = kobj_to_state(kobj);
@@ -371,6 +393,7 @@ static int cpuidle_add_state_sysfs(struct cpuidle_device *device)
 {
        int i, ret = -ENOMEM;
        struct cpuidle_state_kobj *kobj;
+       struct cpuidle_device_kobj *kdev = device->kobj_dev;
        struct cpuidle_driver *drv = cpuidle_get_cpu_driver(device);
 
        /* state statistics */
@@ -383,7 +406,7 @@ static int cpuidle_add_state_sysfs(struct cpuidle_device *device)
                init_completion(&kobj->kobj_unregister);
 
                ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle,
-                                          &device->kobj, "state%d", i);
+                                          &kdev->kobj, "state%d", i);
                if (ret) {
                        kfree(kobj);
                        goto error_state;
@@ -449,8 +472,8 @@ static void cpuidle_driver_sysfs_release(struct kobject *kobj)
        complete(&driver_kobj->kobj_unregister);
 }
 
-static ssize_t cpuidle_driver_show(struct kobject *kobj, struct attribute * attr,
-                                  char * buf)
+static ssize_t cpuidle_driver_show(struct kobject *kobj, struct attribute *attr,
+                                  char *buf)
 {
        int ret = -EIO;
        struct cpuidle_driver_kobj *driver_kobj = kobj_to_driver_kobj(kobj);
@@ -500,6 +523,7 @@ static struct kobj_type ktype_driver_cpuidle = {
 static int cpuidle_add_driver_sysfs(struct cpuidle_device *dev)
 {
        struct cpuidle_driver_kobj *kdrv;
+       struct cpuidle_device_kobj *kdev = dev->kobj_dev;
        struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
        int ret;
 
@@ -511,7 +535,7 @@ static int cpuidle_add_driver_sysfs(struct cpuidle_device *dev)
        init_completion(&kdrv->kobj_unregister);
 
        ret = kobject_init_and_add(&kdrv->kobj, &ktype_driver_cpuidle,
-                                  &dev->kobj, "driver");
+                                  &kdev->kobj, "driver");
        if (ret) {
                kfree(kdrv);
                return ret;
@@ -580,16 +604,28 @@ void cpuidle_remove_device_sysfs(struct cpuidle_device *device)
  */
 int cpuidle_add_sysfs(struct cpuidle_device *dev)
 {
+       struct cpuidle_device_kobj *kdev;
        struct device *cpu_dev = get_cpu_device((unsigned long)dev->cpu);
        int error;
 
-       init_completion(&dev->kobj_unregister);
+       kdev = kzalloc(sizeof(*kdev), GFP_KERNEL);
+       if (!kdev)
+               return -ENOMEM;
+       kdev->dev = dev;
+       dev->kobj_dev = kdev;
 
-       error = kobject_init_and_add(&dev->kobj, &ktype_cpuidle, &cpu_dev->kobj,
-                                    "cpuidle");
-       if (!error)
-               kobject_uevent(&dev->kobj, KOBJ_ADD);
-       return error;
+       init_completion(&kdev->kobj_unregister);
+
+       error = kobject_init_and_add(&kdev->kobj, &ktype_cpuidle, &cpu_dev->kobj,
+                                  "cpuidle");
+       if (error) {
+               kfree(kdev);
+               return error;
+       }
+
+       kobject_uevent(&kdev->kobj, KOBJ_ADD);
+
+       return 0;
 }
 
 /**
@@ -598,6 +634,9 @@ int cpuidle_add_sysfs(struct cpuidle_device *dev)
  */
 void cpuidle_remove_sysfs(struct cpuidle_device *dev)
 {
-       kobject_put(&dev->kobj);
-       wait_for_completion(&dev->kobj_unregister);
+       struct cpuidle_device_kobj *kdev = dev->kobj_dev;
+
+       kobject_put(&kdev->kobj);
+       wait_for_completion(&kdev->kobj_unregister);
+       kfree(kdev);
 }
index 8ff7c230d82e487d9644c6c5c4552c228764074e..62fb673b28df4b817de44518d6657e1b2edc1bcd 100644 (file)
@@ -242,13 +242,16 @@ config CRYPTO_DEV_PPC4XX
          This option allows you to have support for AMCC crypto acceleration.
 
 config CRYPTO_DEV_OMAP_SHAM
-       tristate "Support for OMAP SHA1/MD5 hw accelerator"
-       depends on ARCH_OMAP2 || ARCH_OMAP3
+       tristate "Support for OMAP MD5/SHA1/SHA2 hw accelerator"
+       depends on ARCH_OMAP2PLUS
        select CRYPTO_SHA1
        select CRYPTO_MD5
+       select CRYPTO_SHA256
+       select CRYPTO_SHA512
+       select CRYPTO_HMAC
        help
-         OMAP processors have SHA1/MD5 hw accelerator. Select this if you
-         want to use the OMAP module for SHA1/MD5 algorithms.
+         OMAP processors have MD5/SHA1/SHA2 hw accelerator. Select this if you
+         want to use the OMAP module for MD5/SHA1/SHA2 algorithms.
 
 config CRYPTO_DEV_OMAP_AES
        tristate "Support for OMAP AES hw engine"
index bf416a8391a77ec94dc3686d773e5afb7b437b3d..7a9052c442381be50c5053475900757f8e0cdac4 100644 (file)
@@ -65,8 +65,6 @@
 #define CAAM_MAX_IV_LENGTH             16
 
 /* length of descriptors text */
-#define DESC_JOB_IO_LEN                        (CAAM_CMD_SZ * 5 + CAAM_PTR_SZ * 3)
-
 #define DESC_AEAD_BASE                 (4 * CAAM_CMD_SZ)
 #define DESC_AEAD_ENC_LEN              (DESC_AEAD_BASE + 16 * CAAM_CMD_SZ)
 #define DESC_AEAD_DEC_LEN              (DESC_AEAD_BASE + 21 * CAAM_CMD_SZ)
index 84573b4d6f92809d5cd98fa968f6dd1a617482d3..98429b80f7bb8860215580d25d4e032d8e41c0a2 100644 (file)
@@ -72,8 +72,6 @@
 #define CAAM_MAX_HASH_DIGEST_SIZE      SHA512_DIGEST_SIZE
 
 /* length of descriptors text */
-#define DESC_JOB_IO_LEN                        (CAAM_CMD_SZ * 5 + CAAM_PTR_SZ * 3)
-
 #define DESC_AHASH_BASE                        (4 * CAAM_CMD_SZ)
 #define DESC_AHASH_UPDATE_LEN          (6 * CAAM_CMD_SZ)
 #define DESC_AHASH_UPDATE_FIRST_LEN    (DESC_AHASH_BASE + 4 * CAAM_CMD_SZ)
index f5d6deced1cbaac0b00702e60aabdf0a9598c3b7..b010d42a18035fa48a8797dc802267f70db531d2 100644 (file)
@@ -75,55 +75,53 @@ static void build_instantiation_desc(u32 *desc)
                         OP_ALG_RNG4_SK);
 }
 
-struct instantiate_result {
-       struct completion completion;
-       int err;
-};
-
-static void rng4_init_done(struct device *dev, u32 *desc, u32 err,
-                          void *context)
-{
-       struct instantiate_result *instantiation = context;
-
-       if (err) {
-               char tmp[CAAM_ERROR_STR_MAX];
-
-               dev_err(dev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err));
-       }
-
-       instantiation->err = err;
-       complete(&instantiation->completion);
-}
-
-static int instantiate_rng(struct device *jrdev)
+static int instantiate_rng(struct device *ctrldev)
 {
-       struct instantiate_result instantiation;
-
-       dma_addr_t desc_dma;
+       struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev);
+       struct caam_full __iomem *topregs;
+       unsigned int timeout = 100000;
        u32 *desc;
-       int ret;
+       int i, ret = 0;
 
        desc = kmalloc(CAAM_CMD_SZ * 6, GFP_KERNEL | GFP_DMA);
        if (!desc) {
-               dev_err(jrdev, "cannot allocate RNG init descriptor memory\n");
+               dev_err(ctrldev, "can't allocate RNG init descriptor memory\n");
                return -ENOMEM;
        }
-
        build_instantiation_desc(desc);
-       desc_dma = dma_map_single(jrdev, desc, desc_bytes(desc), DMA_TO_DEVICE);
-       init_completion(&instantiation.completion);
-       ret = caam_jr_enqueue(jrdev, desc, rng4_init_done, &instantiation);
-       if (!ret) {
-               wait_for_completion_interruptible(&instantiation.completion);
-               ret = instantiation.err;
-               if (ret)
-                       dev_err(jrdev, "unable to instantiate RNG\n");
+
+       /* Set the bit to request direct access to DECO0 */
+       topregs = (struct caam_full __iomem *)ctrlpriv->ctrl;
+       setbits32(&topregs->ctrl.deco_rq, DECORR_RQD0ENABLE);
+
+       while (!(rd_reg32(&topregs->ctrl.deco_rq) & DECORR_DEN0) &&
+                                                                --timeout)
+               cpu_relax();
+
+       if (!timeout) {
+               dev_err(ctrldev, "failed to acquire DECO 0\n");
+               ret = -EIO;
+               goto out;
        }
 
-       dma_unmap_single(jrdev, desc_dma, desc_bytes(desc), DMA_TO_DEVICE);
+       for (i = 0; i < desc_len(desc); i++)
+               topregs->deco.descbuf[i] = *(desc + i);
 
-       kfree(desc);
+       wr_reg32(&topregs->deco.jr_ctl_hi, DECO_JQCR_WHL | DECO_JQCR_FOUR);
 
+       timeout = 10000000;
+       while ((rd_reg32(&topregs->deco.desc_dbg) & DECO_DBG_VALID) &&
+                                                                --timeout)
+               cpu_relax();
+
+       if (!timeout) {
+               dev_err(ctrldev, "failed to instantiate RNG\n");
+               ret = -EIO;
+       }
+
+       clrbits32(&topregs->ctrl.deco_rq, DECORR_RQD0ENABLE);
+out:
+       kfree(desc);
        return ret;
 }
 
@@ -303,7 +301,7 @@ static int caam_probe(struct platform_device *pdev)
        if ((cha_vid & CHA_ID_RNG_MASK) >> CHA_ID_RNG_SHIFT >= 4 &&
            !(rd_reg32(&topregs->ctrl.r4tst[0].rdsta) & RDSTA_IF0)) {
                kick_trng(pdev);
-               ret = instantiate_rng(ctrlpriv->jrdev[0]);
+               ret = instantiate_rng(dev);
                if (ret) {
                        caam_remove(pdev);
                        return ret;
@@ -315,9 +313,6 @@ static int caam_probe(struct platform_device *pdev)
 
        /* NOTE: RTIC detection ought to go here, around Si time */
 
-       /* Initialize queue allocator lock */
-       spin_lock_init(&ctrlpriv->jr_alloc_lock);
-
        caam_id = rd_reg64(&topregs->ctrl.perfmon.caam_id);
 
        /* Report "alive" for developer to see */
index fe3bfd1b08cae14bf00c59ccddf9d026e9b2c717..cd5f678847ce3e7e93b1634a510bcd548abafe01 100644 (file)
@@ -10,6 +10,7 @@
 #define CAAM_CMD_SZ sizeof(u32)
 #define CAAM_PTR_SZ sizeof(dma_addr_t)
 #define CAAM_DESC_BYTES_MAX (CAAM_CMD_SZ * MAX_CAAM_DESCSIZE)
+#define DESC_JOB_IO_LEN (CAAM_CMD_SZ * 5 + CAAM_PTR_SZ * 3)
 
 #ifdef DEBUG
 #define PRINT_POS do { printk(KERN_DEBUG "%02d: %s\n", desc_len(desc),\
index e4a16b741371d1df496d6344be5fc214896ba50c..34c4b9f7fbfae414a1578e37da245fd9119ac8fd 100644 (file)
@@ -9,9 +9,6 @@
 #ifndef INTERN_H
 #define INTERN_H
 
-#define JOBR_UNASSIGNED 0
-#define JOBR_ASSIGNED 1
-
 /* Currently comes from Kconfig param as a ^2 (driver-required) */
 #define JOBR_DEPTH (1 << CONFIG_CRYPTO_DEV_FSL_CAAM_RINGSIZE)
 
@@ -46,7 +43,6 @@ struct caam_drv_private_jr {
        struct caam_job_ring __iomem *rregs;    /* JobR's register space */
        struct tasklet_struct irqtask;
        int irq;                        /* One per queue */
-       int assign;                     /* busy/free */
 
        /* Job ring info */
        int ringsize;   /* Size of rings (assume input = output) */
@@ -68,7 +64,6 @@ struct caam_drv_private {
 
        struct device *dev;
        struct device **jrdev; /* Alloc'ed array per sub-device */
-       spinlock_t jr_alloc_lock;
        struct platform_device *pdev;
 
        /* Physical-presence section */
index b4aa773ecbc83ec7f61548bae34145639ddbf5ec..105ba4da618059b63a71a36747008e362a04233f 100644 (file)
@@ -125,72 +125,6 @@ static void caam_jr_dequeue(unsigned long devarg)
        clrbits32(&jrp->rregs->rconfig_lo, JRCFG_IMSK);
 }
 
-/**
- * caam_jr_register() - Alloc a ring for someone to use as needed. Returns
- * an ordinal of the rings allocated, else returns -ENODEV if no rings
- * are available.
- * @ctrldev: points to the controller level dev (parent) that
- *           owns rings available for use.
- * @dev:     points to where a pointer to the newly allocated queue's
- *           dev can be written to if successful.
- **/
-int caam_jr_register(struct device *ctrldev, struct device **rdev)
-{
-       struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev);
-       struct caam_drv_private_jr *jrpriv = NULL;
-       int ring;
-
-       /* Lock, if free ring - assign, unlock */
-       spin_lock(&ctrlpriv->jr_alloc_lock);
-       for (ring = 0; ring < ctrlpriv->total_jobrs; ring++) {
-               jrpriv = dev_get_drvdata(ctrlpriv->jrdev[ring]);
-               if (jrpriv->assign == JOBR_UNASSIGNED) {
-                       jrpriv->assign = JOBR_ASSIGNED;
-                       *rdev = ctrlpriv->jrdev[ring];
-                       spin_unlock(&ctrlpriv->jr_alloc_lock);
-                       return ring;
-               }
-       }
-
-       /* If assigned, write dev where caller needs it */
-       spin_unlock(&ctrlpriv->jr_alloc_lock);
-       *rdev = NULL;
-
-       return -ENODEV;
-}
-EXPORT_SYMBOL(caam_jr_register);
-
-/**
- * caam_jr_deregister() - Deregister an API and release the queue.
- * Returns 0 if OK, -EBUSY if queue still contains pending entries
- * or unprocessed results at the time of the call
- * @dev     - points to the dev that identifies the queue to
- *            be released.
- **/
-int caam_jr_deregister(struct device *rdev)
-{
-       struct caam_drv_private_jr *jrpriv = dev_get_drvdata(rdev);
-       struct caam_drv_private *ctrlpriv;
-
-       /* Get the owning controller's private space */
-       ctrlpriv = dev_get_drvdata(jrpriv->parentdev);
-
-       /*
-        * Make sure ring empty before release
-        */
-       if (rd_reg32(&jrpriv->rregs->outring_used) ||
-           (rd_reg32(&jrpriv->rregs->inpring_avail) != JOBR_DEPTH))
-               return -EBUSY;
-
-       /* Release ring */
-       spin_lock(&ctrlpriv->jr_alloc_lock);
-       jrpriv->assign = JOBR_UNASSIGNED;
-       spin_unlock(&ctrlpriv->jr_alloc_lock);
-
-       return 0;
-}
-EXPORT_SYMBOL(caam_jr_deregister);
-
 /**
  * caam_jr_enqueue() - Enqueue a job descriptor head. Returns 0 if OK,
  * -EBUSY if the queue is full, -EIO if it cannot map the caller's
@@ -379,7 +313,6 @@ static int caam_jr_init(struct device *dev)
                  (JOBR_INTC_COUNT_THLD << JRCFG_ICDCT_SHIFT) |
                  (JOBR_INTC_TIME_THLD << JRCFG_ICTT_SHIFT));
 
-       jrp->assign = JOBR_UNASSIGNED;
        return 0;
 }
 
index c23df395b6220b2b294610ea17254492b2e1dfd7..9d8741a59037f82ea162ef2a0b894bca49b5b040 100644 (file)
@@ -8,8 +8,6 @@
 #define JR_H
 
 /* Prototypes for backend-level services exposed to APIs */
-int caam_jr_register(struct device *ctrldev, struct device **rdev);
-int caam_jr_deregister(struct device *rdev);
 int caam_jr_enqueue(struct device *dev, u32 *desc,
                    void (*cbk)(struct device *dev, u32 *desc, u32 status,
                                void *areq),
index c09142fc13e372171fe6093b45bdd6a3121f65f1..4455396918de84320380fcca2eca01d694971114 100644 (file)
@@ -341,6 +341,8 @@ struct caam_ctrl {
 #define MCFGR_DMA_RESET                0x10000000
 #define MCFGR_LONG_PTR         0x00010000 /* Use >32-bit desc addressing */
 #define SCFGR_RDBENABLE                0x00000400
+#define DECORR_RQD0ENABLE      0x00000001 /* Enable DECO0 for direct access */
+#define DECORR_DEN0            0x00010000 /* DECO0 available for access*/
 
 /* AXI read cache control */
 #define MCFGR_ARCACHE_SHIFT    12
@@ -703,9 +705,16 @@ struct caam_deco {
        struct deco_sg_table sctr_tbl[4];       /* DxSTR - Scatter Tables */
        u32 rsvd29[48];
        u32 descbuf[64];        /* DxDESB - Descriptor buffer */
-       u32 rsvd30[320];
+       u32 rscvd30[193];
+       u32 desc_dbg;           /* DxDDR - DECO Debug Register */
+       u32 rsvd31[126];
 };
 
+/* DECO DBG Register Valid Bit*/
+#define DECO_DBG_VALID         0x80000000
+#define DECO_JQCR_WHL          0x20000000
+#define DECO_JQCR_FOUR         0x10000000
+
 /*
  * Current top-level view of memory map is:
  *
@@ -733,6 +742,7 @@ struct caam_full {
        u64 rsvd[512];
        struct caam_assurance assure;
        struct caam_queue_if qi;
+       struct caam_deco deco;
 };
 
 #endif /* REGS_H */
index 4bb67652c2005ea46cf2677172665f8a261e58e3..ae1ca8b2dfb250ed5eb8084482f2e0704b3a1eda 100644 (file)
@@ -44,7 +44,6 @@
 #include <crypto/hash.h>
 #include <crypto/internal/hash.h>
 
-#define SHA1_MD5_BLOCK_SIZE            SHA1_BLOCK_SIZE
 #define MD5_DIGEST_SIZE                        16
 
 #define DST_MAXBURST                   16
@@ -54,7 +53,7 @@
 #define SHA_REG_DIN(dd, x)             ((dd)->pdata->din_ofs + ((x) * 0x04))
 #define SHA_REG_DIGCNT(dd)             ((dd)->pdata->digcnt_ofs)
 
-#define SHA_REG_ODIGEST(x)             (0x00 + ((x) * 0x04))
+#define SHA_REG_ODIGEST(dd, x)         ((dd)->pdata->odigest_ofs + (x * 0x04))
 
 #define SHA_REG_CTRL                   0x18
 #define SHA_REG_CTRL_LENGTH            (0xFFFFFFFF << 5)
 #define SHA_REG_SYSSTATUS(dd)          ((dd)->pdata->sysstatus_ofs)
 #define SHA_REG_SYSSTATUS_RESETDONE    (1 << 0)
 
-#define SHA_REG_MODE                   0x44
+#define SHA_REG_MODE(dd)               ((dd)->pdata->mode_ofs)
 #define SHA_REG_MODE_HMAC_OUTER_HASH   (1 << 7)
 #define SHA_REG_MODE_HMAC_KEY_PROC     (1 << 5)
 #define SHA_REG_MODE_CLOSE_HASH                (1 << 4)
 #define SHA_REG_MODE_ALGO_CONSTANT     (1 << 3)
-#define SHA_REG_MODE_ALGO_MASK         (3 << 1)
-#define                SHA_REG_MODE_ALGO_MD5_128       (0 << 1)
-#define                SHA_REG_MODE_ALGO_SHA1_160      (1 << 1)
-#define                SHA_REG_MODE_ALGO_SHA2_224      (2 << 1)
-#define                SHA_REG_MODE_ALGO_SHA2_256      (3 << 1)
 
-#define SHA_REG_LENGTH                 0x48
+#define SHA_REG_MODE_ALGO_MASK         (7 << 0)
+#define SHA_REG_MODE_ALGO_MD5_128      (0 << 1)
+#define SHA_REG_MODE_ALGO_SHA1_160     (1 << 1)
+#define SHA_REG_MODE_ALGO_SHA2_224     (2 << 1)
+#define SHA_REG_MODE_ALGO_SHA2_256     (3 << 1)
+#define SHA_REG_MODE_ALGO_SHA2_384     (1 << 0)
+#define SHA_REG_MODE_ALGO_SHA2_512     (3 << 0)
+
+#define SHA_REG_LENGTH(dd)             ((dd)->pdata->length_ofs)
 
 #define SHA_REG_IRQSTATUS              0x118
 #define SHA_REG_IRQSTATUS_CTX_RDY      (1 << 3)
 #define FLAGS_SG               17
 
 #define FLAGS_MODE_SHIFT       18
-#define FLAGS_MODE_MASK                (SHA_REG_MODE_ALGO_MASK                 \
-                                       << (FLAGS_MODE_SHIFT - 1))
-#define                FLAGS_MODE_MD5          (SHA_REG_MODE_ALGO_MD5_128      \
-                                               << (FLAGS_MODE_SHIFT - 1))
-#define                FLAGS_MODE_SHA1         (SHA_REG_MODE_ALGO_SHA1_160     \
-                                               << (FLAGS_MODE_SHIFT - 1))
-#define                FLAGS_MODE_SHA224       (SHA_REG_MODE_ALGO_SHA2_224     \
-                                               << (FLAGS_MODE_SHIFT - 1))
-#define                FLAGS_MODE_SHA256       (SHA_REG_MODE_ALGO_SHA2_256     \
-                                               << (FLAGS_MODE_SHIFT - 1))
-#define FLAGS_HMAC             20
-#define FLAGS_ERROR            21
+#define FLAGS_MODE_MASK                (SHA_REG_MODE_ALGO_MASK << FLAGS_MODE_SHIFT)
+#define FLAGS_MODE_MD5         (SHA_REG_MODE_ALGO_MD5_128 << FLAGS_MODE_SHIFT)
+#define FLAGS_MODE_SHA1                (SHA_REG_MODE_ALGO_SHA1_160 << FLAGS_MODE_SHIFT)
+#define FLAGS_MODE_SHA224      (SHA_REG_MODE_ALGO_SHA2_224 << FLAGS_MODE_SHIFT)
+#define FLAGS_MODE_SHA256      (SHA_REG_MODE_ALGO_SHA2_256 << FLAGS_MODE_SHIFT)
+#define FLAGS_MODE_SHA384      (SHA_REG_MODE_ALGO_SHA2_384 << FLAGS_MODE_SHIFT)
+#define FLAGS_MODE_SHA512      (SHA_REG_MODE_ALGO_SHA2_512 << FLAGS_MODE_SHIFT)
+
+#define FLAGS_HMAC             21
+#define FLAGS_ERROR            22
 
 #define OP_UPDATE              1
 #define OP_FINAL               2
@@ -145,7 +145,7 @@ struct omap_sham_reqctx {
        unsigned long           flags;
        unsigned long           op;
 
-       u8                      digest[SHA256_DIGEST_SIZE] OMAP_ALIGNED;
+       u8                      digest[SHA512_DIGEST_SIZE] OMAP_ALIGNED;
        size_t                  digcnt;
        size_t                  bufcnt;
        size_t                  buflen;
@@ -162,8 +162,8 @@ struct omap_sham_reqctx {
 
 struct omap_sham_hmac_ctx {
        struct crypto_shash     *shash;
-       u8                      ipad[SHA1_MD5_BLOCK_SIZE] OMAP_ALIGNED;
-       u8                      opad[SHA1_MD5_BLOCK_SIZE] OMAP_ALIGNED;
+       u8                      ipad[SHA512_BLOCK_SIZE] OMAP_ALIGNED;
+       u8                      opad[SHA512_BLOCK_SIZE] OMAP_ALIGNED;
 };
 
 struct omap_sham_ctx {
@@ -205,6 +205,8 @@ struct omap_sham_pdata {
        u32             rev_ofs;
        u32             mask_ofs;
        u32             sysstatus_ofs;
+       u32             mode_ofs;
+       u32             length_ofs;
 
        u32             major_mask;
        u32             major_shift;
@@ -306,9 +308,9 @@ static void omap_sham_copy_hash_omap4(struct ahash_request *req, int out)
                for (i = 0; i < dd->pdata->digest_size / sizeof(u32); i++) {
                        if (out)
                                opad[i] = omap_sham_read(dd,
-                                               SHA_REG_ODIGEST(i));
+                                               SHA_REG_ODIGEST(dd, i));
                        else
-                               omap_sham_write(dd, SHA_REG_ODIGEST(i),
+                               omap_sham_write(dd, SHA_REG_ODIGEST(dd, i),
                                                opad[i]);
                }
        }
@@ -342,6 +344,12 @@ static void omap_sham_copy_ready_hash(struct ahash_request *req)
        case FLAGS_MODE_SHA256:
                d = SHA256_DIGEST_SIZE / sizeof(u32);
                break;
+       case FLAGS_MODE_SHA384:
+               d = SHA384_DIGEST_SIZE / sizeof(u32);
+               break;
+       case FLAGS_MODE_SHA512:
+               d = SHA512_DIGEST_SIZE / sizeof(u32);
+               break;
        default:
                d = 0;
        }
@@ -404,6 +412,30 @@ static int omap_sham_poll_irq_omap2(struct omap_sham_dev *dd)
        return omap_sham_wait(dd, SHA_REG_CTRL, SHA_REG_CTRL_INPUT_READY);
 }
 
+static int get_block_size(struct omap_sham_reqctx *ctx)
+{
+       int d;
+
+       switch (ctx->flags & FLAGS_MODE_MASK) {
+       case FLAGS_MODE_MD5:
+       case FLAGS_MODE_SHA1:
+               d = SHA1_BLOCK_SIZE;
+               break;
+       case FLAGS_MODE_SHA224:
+       case FLAGS_MODE_SHA256:
+               d = SHA256_BLOCK_SIZE;
+               break;
+       case FLAGS_MODE_SHA384:
+       case FLAGS_MODE_SHA512:
+               d = SHA512_BLOCK_SIZE;
+               break;
+       default:
+               d = 0;
+       }
+
+       return d;
+}
+
 static void omap_sham_write_n(struct omap_sham_dev *dd, u32 offset,
                                    u32 *value, int count)
 {
@@ -422,20 +454,24 @@ static void omap_sham_write_ctrl_omap4(struct omap_sham_dev *dd, size_t length,
         * CLOSE_HASH only for the last one. Note that flags mode bits
         * correspond to algorithm encoding in mode register.
         */
-       val = (ctx->flags & FLAGS_MODE_MASK) >> (FLAGS_MODE_SHIFT - 1);
+       val = (ctx->flags & FLAGS_MODE_MASK) >> (FLAGS_MODE_SHIFT);
        if (!ctx->digcnt) {
                struct crypto_ahash *tfm = crypto_ahash_reqtfm(dd->req);
                struct omap_sham_ctx *tctx = crypto_ahash_ctx(tfm);
                struct omap_sham_hmac_ctx *bctx = tctx->base;
+               int bs, nr_dr;
 
                val |= SHA_REG_MODE_ALGO_CONSTANT;
 
                if (ctx->flags & BIT(FLAGS_HMAC)) {
+                       bs = get_block_size(ctx);
+                       nr_dr = bs / (2 * sizeof(u32));
                        val |= SHA_REG_MODE_HMAC_KEY_PROC;
-                       omap_sham_write_n(dd, SHA_REG_ODIGEST(0),
-                                         (u32 *)bctx->ipad,
-                                         SHA1_BLOCK_SIZE / sizeof(u32));
-                       ctx->digcnt += SHA1_BLOCK_SIZE;
+                       omap_sham_write_n(dd, SHA_REG_ODIGEST(dd, 0),
+                                         (u32 *)bctx->ipad, nr_dr);
+                       omap_sham_write_n(dd, SHA_REG_IDIGEST(dd, 0),
+                                         (u32 *)bctx->ipad + nr_dr, nr_dr);
+                       ctx->digcnt += bs;
                }
        }
 
@@ -451,7 +487,7 @@ static void omap_sham_write_ctrl_omap4(struct omap_sham_dev *dd, size_t length,
               SHA_REG_MODE_HMAC_KEY_PROC;
 
        dev_dbg(dd->dev, "ctrl: %08x, flags: %08lx\n", val, ctx->flags);
-       omap_sham_write_mask(dd, SHA_REG_MODE, val, mask);
+       omap_sham_write_mask(dd, SHA_REG_MODE(dd), val, mask);
        omap_sham_write(dd, SHA_REG_IRQENA, SHA_REG_IRQENA_OUTPUT_RDY);
        omap_sham_write_mask(dd, SHA_REG_MASK(dd),
                             SHA_REG_MASK_IT_EN |
@@ -461,7 +497,7 @@ static void omap_sham_write_ctrl_omap4(struct omap_sham_dev *dd, size_t length,
 
 static void omap_sham_trigger_omap4(struct omap_sham_dev *dd, size_t length)
 {
-       omap_sham_write(dd, SHA_REG_LENGTH, length);
+       omap_sham_write(dd, SHA_REG_LENGTH(dd), length);
 }
 
 static int omap_sham_poll_irq_omap4(struct omap_sham_dev *dd)
@@ -666,14 +702,14 @@ static int omap_sham_update_dma_slow(struct omap_sham_dev *dd)
 /* Start address alignment */
 #define SG_AA(sg)      (IS_ALIGNED(sg->offset, sizeof(u32)))
 /* SHA1 block size alignment */
-#define SG_SA(sg)      (IS_ALIGNED(sg->length, SHA1_MD5_BLOCK_SIZE))
+#define SG_SA(sg, bs)  (IS_ALIGNED(sg->length, bs))
 
 static int omap_sham_update_dma_start(struct omap_sham_dev *dd)
 {
        struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
        unsigned int length, final, tail;
        struct scatterlist *sg;
-       int ret;
+       int ret, bs;
 
        if (!ctx->total)
                return 0;
@@ -694,23 +730,24 @@ static int omap_sham_update_dma_start(struct omap_sham_dev *dd)
                        ctx->digcnt, ctx->bufcnt, ctx->total);
 
        sg = ctx->sg;
+       bs = get_block_size(ctx);
 
        if (!SG_AA(sg))
                return omap_sham_update_dma_slow(dd);
 
-       if (!sg_is_last(sg) && !SG_SA(sg))
-               /* size is not SHA1_BLOCK_SIZE aligned */
+       if (!sg_is_last(sg) && !SG_SA(sg, bs))
+               /* size is not BLOCK_SIZE aligned */
                return omap_sham_update_dma_slow(dd);
 
        length = min(ctx->total, sg->length);
 
        if (sg_is_last(sg)) {
                if (!(ctx->flags & BIT(FLAGS_FINUP))) {
-                       /* not last sg must be SHA1_MD5_BLOCK_SIZE aligned */
-                       tail = length & (SHA1_MD5_BLOCK_SIZE - 1);
+                       /* not last sg must be BLOCK_SIZE aligned */
+                       tail = length & (bs - 1);
                        /* without finup() we need one block to close hash */
                        if (!tail)
-                               tail = SHA1_MD5_BLOCK_SIZE;
+                               tail = bs;
                        length -= tail;
                }
        }
@@ -773,6 +810,7 @@ static int omap_sham_init(struct ahash_request *req)
        struct omap_sham_ctx *tctx = crypto_ahash_ctx(tfm);
        struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
        struct omap_sham_dev *dd = NULL, *tmp;
+       int bs = 0;
 
        spin_lock_bh(&sham.lock);
        if (!tctx->dd) {
@@ -796,15 +834,27 @@ static int omap_sham_init(struct ahash_request *req)
        switch (crypto_ahash_digestsize(tfm)) {
        case MD5_DIGEST_SIZE:
                ctx->flags |= FLAGS_MODE_MD5;
+               bs = SHA1_BLOCK_SIZE;
                break;
        case SHA1_DIGEST_SIZE:
                ctx->flags |= FLAGS_MODE_SHA1;
+               bs = SHA1_BLOCK_SIZE;
                break;
        case SHA224_DIGEST_SIZE:
                ctx->flags |= FLAGS_MODE_SHA224;
+               bs = SHA224_BLOCK_SIZE;
                break;
        case SHA256_DIGEST_SIZE:
                ctx->flags |= FLAGS_MODE_SHA256;
+               bs = SHA256_BLOCK_SIZE;
+               break;
+       case SHA384_DIGEST_SIZE:
+               ctx->flags |= FLAGS_MODE_SHA384;
+               bs = SHA384_BLOCK_SIZE;
+               break;
+       case SHA512_DIGEST_SIZE:
+               ctx->flags |= FLAGS_MODE_SHA512;
+               bs = SHA512_BLOCK_SIZE;
                break;
        }
 
@@ -816,8 +866,8 @@ static int omap_sham_init(struct ahash_request *req)
                if (!test_bit(FLAGS_AUTO_XOR, &dd->flags)) {
                        struct omap_sham_hmac_ctx *bctx = tctx->base;
 
-                       memcpy(ctx->buffer, bctx->ipad, SHA1_MD5_BLOCK_SIZE);
-                       ctx->bufcnt = SHA1_MD5_BLOCK_SIZE;
+                       memcpy(ctx->buffer, bctx->ipad, bs);
+                       ctx->bufcnt = bs;
                }
 
                ctx->flags |= BIT(FLAGS_HMAC);
@@ -1006,6 +1056,7 @@ static int omap_sham_enqueue(struct ahash_request *req, unsigned int op)
 static int omap_sham_update(struct ahash_request *req)
 {
        struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
+       int bs = get_block_size(ctx);
 
        if (!req->nbytes)
                return 0;
@@ -1023,7 +1074,7 @@ static int omap_sham_update(struct ahash_request *req)
                        */
                        omap_sham_append_sg(ctx);
                        return 0;
-               } else if (ctx->bufcnt + ctx->total <= SHA1_MD5_BLOCK_SIZE) {
+               } else if (ctx->bufcnt + ctx->total <= bs) {
                        /*
                        * faster to use CPU for short transfers
                        */
@@ -1214,6 +1265,16 @@ static int omap_sham_cra_md5_init(struct crypto_tfm *tfm)
        return omap_sham_cra_init_alg(tfm, "md5");
 }
 
+static int omap_sham_cra_sha384_init(struct crypto_tfm *tfm)
+{
+       return omap_sham_cra_init_alg(tfm, "sha384");
+}
+
+static int omap_sham_cra_sha512_init(struct crypto_tfm *tfm)
+{
+       return omap_sham_cra_init_alg(tfm, "sha512");
+}
+
 static void omap_sham_cra_exit(struct crypto_tfm *tfm)
 {
        struct omap_sham_ctx *tctx = crypto_tfm_ctx(tfm);
@@ -1422,6 +1483,101 @@ static struct ahash_alg algs_sha224_sha256[] = {
 },
 };
 
+static struct ahash_alg algs_sha384_sha512[] = {
+{
+       .init           = omap_sham_init,
+       .update         = omap_sham_update,
+       .final          = omap_sham_final,
+       .finup          = omap_sham_finup,
+       .digest         = omap_sham_digest,
+       .halg.digestsize        = SHA384_DIGEST_SIZE,
+       .halg.base      = {
+               .cra_name               = "sha384",
+               .cra_driver_name        = "omap-sha384",
+               .cra_priority           = 100,
+               .cra_flags              = CRYPTO_ALG_TYPE_AHASH |
+                                               CRYPTO_ALG_ASYNC |
+                                               CRYPTO_ALG_NEED_FALLBACK,
+               .cra_blocksize          = SHA384_BLOCK_SIZE,
+               .cra_ctxsize            = sizeof(struct omap_sham_ctx),
+               .cra_alignmask          = 0,
+               .cra_module             = THIS_MODULE,
+               .cra_init               = omap_sham_cra_init,
+               .cra_exit               = omap_sham_cra_exit,
+       }
+},
+{
+       .init           = omap_sham_init,
+       .update         = omap_sham_update,
+       .final          = omap_sham_final,
+       .finup          = omap_sham_finup,
+       .digest         = omap_sham_digest,
+       .halg.digestsize        = SHA512_DIGEST_SIZE,
+       .halg.base      = {
+               .cra_name               = "sha512",
+               .cra_driver_name        = "omap-sha512",
+               .cra_priority           = 100,
+               .cra_flags              = CRYPTO_ALG_TYPE_AHASH |
+                                               CRYPTO_ALG_ASYNC |
+                                               CRYPTO_ALG_NEED_FALLBACK,
+               .cra_blocksize          = SHA512_BLOCK_SIZE,
+               .cra_ctxsize            = sizeof(struct omap_sham_ctx),
+               .cra_alignmask          = 0,
+               .cra_module             = THIS_MODULE,
+               .cra_init               = omap_sham_cra_init,
+               .cra_exit               = omap_sham_cra_exit,
+       }
+},
+{
+       .init           = omap_sham_init,
+       .update         = omap_sham_update,
+       .final          = omap_sham_final,
+       .finup          = omap_sham_finup,
+       .digest         = omap_sham_digest,
+       .setkey         = omap_sham_setkey,
+       .halg.digestsize        = SHA384_DIGEST_SIZE,
+       .halg.base      = {
+               .cra_name               = "hmac(sha384)",
+               .cra_driver_name        = "omap-hmac-sha384",
+               .cra_priority           = 100,
+               .cra_flags              = CRYPTO_ALG_TYPE_AHASH |
+                                               CRYPTO_ALG_ASYNC |
+                                               CRYPTO_ALG_NEED_FALLBACK,
+               .cra_blocksize          = SHA384_BLOCK_SIZE,
+               .cra_ctxsize            = sizeof(struct omap_sham_ctx) +
+                                       sizeof(struct omap_sham_hmac_ctx),
+               .cra_alignmask          = OMAP_ALIGN_MASK,
+               .cra_module             = THIS_MODULE,
+               .cra_init               = omap_sham_cra_sha384_init,
+               .cra_exit               = omap_sham_cra_exit,
+       }
+},
+{
+       .init           = omap_sham_init,
+       .update         = omap_sham_update,
+       .final          = omap_sham_final,
+       .finup          = omap_sham_finup,
+       .digest         = omap_sham_digest,
+       .setkey         = omap_sham_setkey,
+       .halg.digestsize        = SHA512_DIGEST_SIZE,
+       .halg.base      = {
+               .cra_name               = "hmac(sha512)",
+               .cra_driver_name        = "omap-hmac-sha512",
+               .cra_priority           = 100,
+               .cra_flags              = CRYPTO_ALG_TYPE_AHASH |
+                                               CRYPTO_ALG_ASYNC |
+                                               CRYPTO_ALG_NEED_FALLBACK,
+               .cra_blocksize          = SHA512_BLOCK_SIZE,
+               .cra_ctxsize            = sizeof(struct omap_sham_ctx) +
+                                       sizeof(struct omap_sham_hmac_ctx),
+               .cra_alignmask          = OMAP_ALIGN_MASK,
+               .cra_module             = THIS_MODULE,
+               .cra_init               = omap_sham_cra_sha512_init,
+               .cra_exit               = omap_sham_cra_exit,
+       }
+},
+};
+
 static void omap_sham_done_task(unsigned long data)
 {
        struct omap_sham_dev *dd = (struct omap_sham_dev *)data;
@@ -1548,11 +1704,54 @@ static const struct omap_sham_pdata omap_sham_pdata_omap4 = {
        .poll_irq       = omap_sham_poll_irq_omap4,
        .intr_hdlr      = omap_sham_irq_omap4,
        .idigest_ofs    = 0x020,
+       .odigest_ofs    = 0x0,
        .din_ofs        = 0x080,
        .digcnt_ofs     = 0x040,
        .rev_ofs        = 0x100,
        .mask_ofs       = 0x110,
        .sysstatus_ofs  = 0x114,
+       .mode_ofs       = 0x44,
+       .length_ofs     = 0x48,
+       .major_mask     = 0x0700,
+       .major_shift    = 8,
+       .minor_mask     = 0x003f,
+       .minor_shift    = 0,
+};
+
+static struct omap_sham_algs_info omap_sham_algs_info_omap5[] = {
+       {
+               .algs_list      = algs_sha1_md5,
+               .size           = ARRAY_SIZE(algs_sha1_md5),
+       },
+       {
+               .algs_list      = algs_sha224_sha256,
+               .size           = ARRAY_SIZE(algs_sha224_sha256),
+       },
+       {
+               .algs_list      = algs_sha384_sha512,
+               .size           = ARRAY_SIZE(algs_sha384_sha512),
+       },
+};
+
+static const struct omap_sham_pdata omap_sham_pdata_omap5 = {
+       .algs_info      = omap_sham_algs_info_omap5,
+       .algs_info_size = ARRAY_SIZE(omap_sham_algs_info_omap5),
+       .flags          = BIT(FLAGS_AUTO_XOR),
+       .digest_size    = SHA512_DIGEST_SIZE,
+       .copy_hash      = omap_sham_copy_hash_omap4,
+       .write_ctrl     = omap_sham_write_ctrl_omap4,
+       .trigger        = omap_sham_trigger_omap4,
+       .poll_irq       = omap_sham_poll_irq_omap4,
+       .intr_hdlr      = omap_sham_irq_omap4,
+       .idigest_ofs    = 0x240,
+       .odigest_ofs    = 0x200,
+       .din_ofs        = 0x080,
+       .digcnt_ofs     = 0x280,
+       .rev_ofs        = 0x100,
+       .mask_ofs       = 0x110,
+       .sysstatus_ofs  = 0x114,
+       .mode_ofs       = 0x284,
+       .length_ofs     = 0x288,
        .major_mask     = 0x0700,
        .major_shift    = 8,
        .minor_mask     = 0x003f,
@@ -1568,6 +1767,10 @@ static const struct of_device_id omap_sham_of_match[] = {
                .compatible     = "ti,omap4-sham",
                .data           = &omap_sham_pdata_omap4,
        },
+       {
+               .compatible     = "ti,omap5-sham",
+               .data           = &omap_sham_pdata_omap5,
+       },
        {},
 };
 MODULE_DEVICE_TABLE(of, omap_sham_of_match);
@@ -1667,7 +1870,7 @@ static int omap_sham_probe(struct platform_device *pdev)
        int err, i, j;
        u32 rev;
 
-       dd = kzalloc(sizeof(struct omap_sham_dev), GFP_KERNEL);
+       dd = devm_kzalloc(dev, sizeof(struct omap_sham_dev), GFP_KERNEL);
        if (dd == NULL) {
                dev_err(dev, "unable to alloc data struct.\n");
                err = -ENOMEM;
@@ -1684,20 +1887,21 @@ static int omap_sham_probe(struct platform_device *pdev)
        err = (dev->of_node) ? omap_sham_get_res_of(dd, dev, &res) :
                               omap_sham_get_res_pdev(dd, pdev, &res);
        if (err)
-               goto res_err;
+               goto data_err;
 
        dd->io_base = devm_ioremap_resource(dev, &res);
        if (IS_ERR(dd->io_base)) {
                err = PTR_ERR(dd->io_base);
-               goto res_err;
+               goto data_err;
        }
        dd->phys_base = res.start;
 
-       err = request_irq(dd->irq, dd->pdata->intr_hdlr, IRQF_TRIGGER_LOW,
-                         dev_name(dev), dd);
+       err = devm_request_irq(dev, dd->irq, dd->pdata->intr_hdlr,
+                              IRQF_TRIGGER_NONE, dev_name(dev), dd);
        if (err) {
-               dev_err(dev, "unable to request irq.\n");
-               goto res_err;
+               dev_err(dev, "unable to request irq %d, err = %d\n",
+                       dd->irq, err);
+               goto data_err;
        }
 
        dma_cap_zero(mask);
@@ -1709,7 +1913,7 @@ static int omap_sham_probe(struct platform_device *pdev)
                dev_err(dev, "unable to obtain RX DMA engine channel %u\n",
                        dd->dma);
                err = -ENXIO;
-               goto dma_err;
+               goto data_err;
        }
 
        dd->flags |= dd->pdata->flags;
@@ -1747,11 +1951,6 @@ err_algs:
                                        &dd->pdata->algs_info[i].algs_list[j]);
        pm_runtime_disable(dev);
        dma_release_channel(dd->dma_lch);
-dma_err:
-       free_irq(dd->irq, dd);
-res_err:
-       kfree(dd);
-       dd = NULL;
 data_err:
        dev_err(dev, "initialization failed.\n");
 
@@ -1776,9 +1975,6 @@ static int omap_sham_remove(struct platform_device *pdev)
        tasklet_kill(&dd->done_task);
        pm_runtime_disable(&pdev->dev);
        dma_release_channel(dd->dma_lch);
-       free_irq(dd->irq, dd);
-       kfree(dd);
-       dd = NULL;
 
        return 0;
 }
index 496ae6aae3164309b9cf99f0d7a1c35af59f4755..1c73f4fbc2526027f96b2323b21b0c4c0c1e1b0f 100644 (file)
@@ -11,6 +11,8 @@
  * License terms: GNU General Public License (GPL) version 2
  */
 
+#define pr_fmt(fmt) "hashX hashX: " fmt
+
 #include <linux/clk.h>
 #include <linux/device.h>
 #include <linux/err.h>
@@ -35,8 +37,6 @@
 
 #include "hash_alg.h"
 
-#define DEV_DBG_NAME "hashX hashX:"
-
 static int hash_mode;
 module_param(hash_mode, int, 0);
 MODULE_PARM_DESC(hash_mode, "CPU or DMA mode. CPU = 0 (default), DMA = 1");
@@ -44,13 +44,13 @@ MODULE_PARM_DESC(hash_mode, "CPU or DMA mode. CPU = 0 (default), DMA = 1");
 /**
  * Pre-calculated empty message digests.
  */
-static u8 zero_message_hash_sha1[SHA1_DIGEST_SIZE] = {
+static const u8 zero_message_hash_sha1[SHA1_DIGEST_SIZE] = {
        0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d,
        0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90,
        0xaf, 0xd8, 0x07, 0x09
 };
 
-static u8 zero_message_hash_sha256[SHA256_DIGEST_SIZE] = {
+static const u8 zero_message_hash_sha256[SHA256_DIGEST_SIZE] = {
        0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14,
        0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
        0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c,
@@ -58,14 +58,14 @@ static u8 zero_message_hash_sha256[SHA256_DIGEST_SIZE] = {
 };
 
 /* HMAC-SHA1, no key */
-static u8 zero_message_hmac_sha1[SHA1_DIGEST_SIZE] = {
+static const u8 zero_message_hmac_sha1[SHA1_DIGEST_SIZE] = {
        0xfb, 0xdb, 0x1d, 0x1b, 0x18, 0xaa, 0x6c, 0x08,
        0x32, 0x4b, 0x7d, 0x64, 0xb7, 0x1f, 0xb7, 0x63,
        0x70, 0x69, 0x0e, 0x1d
 };
 
 /* HMAC-SHA256, no key */
-static u8 zero_message_hmac_sha256[SHA256_DIGEST_SIZE] = {
+static const u8 zero_message_hmac_sha256[SHA256_DIGEST_SIZE] = {
        0xb6, 0x13, 0x67, 0x9a, 0x08, 0x14, 0xd9, 0xec,
        0x77, 0x2f, 0x95, 0xd7, 0x78, 0xc3, 0x5f, 0xc5,
        0xff, 0x16, 0x97, 0xc4, 0x93, 0x71, 0x56, 0x53,
@@ -97,7 +97,7 @@ static struct hash_driver_data        driver_data;
  *
  */
 static void hash_messagepad(struct hash_device_data *device_data,
-               const u32 *message, u8 index_bytes);
+                           const u32 *message, u8 index_bytes);
 
 /**
  * release_hash_device - Releases a previously allocated hash device.
@@ -119,7 +119,7 @@ static void release_hash_device(struct hash_device_data *device_data)
 }
 
 static void hash_dma_setup_channel(struct hash_device_data *device_data,
-                               struct device *dev)
+                                  struct device *dev)
 {
        struct hash_platform_data *platform_data = dev->platform_data;
        struct dma_slave_config conf = {
@@ -127,7 +127,7 @@ static void hash_dma_setup_channel(struct hash_device_data *device_data,
                .dst_addr = device_data->phybase + HASH_DMA_FIFO,
                .dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES,
                .dst_maxburst = 16,
-        };
+       };
 
        dma_cap_zero(device_data->dma.mask);
        dma_cap_set(DMA_SLAVE, device_data->dma.mask);
@@ -135,8 +135,8 @@ static void hash_dma_setup_channel(struct hash_device_data *device_data,
        device_data->dma.cfg_mem2hash = platform_data->mem_to_engine;
        device_data->dma.chan_mem2hash =
                dma_request_channel(device_data->dma.mask,
-                               platform_data->dma_filter,
-                               device_data->dma.cfg_mem2hash);
+                                   platform_data->dma_filter,
+                                   device_data->dma.cfg_mem2hash);
 
        dmaengine_slave_config(device_data->dma.chan_mem2hash, &conf);
 
@@ -145,21 +145,21 @@ static void hash_dma_setup_channel(struct hash_device_data *device_data,
 
 static void hash_dma_callback(void *data)
 {
-       struct hash_ctx *ctx = (struct hash_ctx *) data;
+       struct hash_ctx *ctx = data;
 
        complete(&ctx->device->dma.complete);
 }
 
 static int hash_set_dma_transfer(struct hash_ctx *ctx, struct scatterlist *sg,
-               int len, enum dma_data_direction direction)
+                                int len, enum dma_data_direction direction)
 {
        struct dma_async_tx_descriptor *desc = NULL;
        struct dma_chan *channel = NULL;
        dma_cookie_t cookie;
 
        if (direction != DMA_TO_DEVICE) {
-               dev_err(ctx->device->dev, "[%s] Invalid DMA direction",
-                               __func__);
+               dev_err(ctx->device->dev, "%s: Invalid DMA direction\n",
+                       __func__);
                return -EFAULT;
        }
 
@@ -172,20 +172,19 @@ static int hash_set_dma_transfer(struct hash_ctx *ctx, struct scatterlist *sg,
                        direction);
 
        if (!ctx->device->dma.sg_len) {
-               dev_err(ctx->device->dev,
-                               "[%s]: Could not map the sg list (TO_DEVICE)",
-                               __func__);
+               dev_err(ctx->device->dev, "%s: Could not map the sg list (TO_DEVICE)\n",
+                       __func__);
                return -EFAULT;
        }
 
-       dev_dbg(ctx->device->dev, "[%s]: Setting up DMA for buffer "
-                       "(TO_DEVICE)", __func__);
+       dev_dbg(ctx->device->dev, "%s: Setting up DMA for buffer (TO_DEVICE)\n",
+               __func__);
        desc = dmaengine_prep_slave_sg(channel,
                        ctx->device->dma.sg, ctx->device->dma.sg_len,
                        direction, DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
        if (!desc) {
                dev_err(ctx->device->dev,
-                       "[%s]: device_prep_slave_sg() failed!", __func__);
+                       "%s: device_prep_slave_sg() failed!\n", __func__);
                return -EFAULT;
        }
 
@@ -205,17 +204,16 @@ static void hash_dma_done(struct hash_ctx *ctx)
        chan = ctx->device->dma.chan_mem2hash;
        dmaengine_device_control(chan, DMA_TERMINATE_ALL, 0);
        dma_unmap_sg(chan->device->dev, ctx->device->dma.sg,
-                       ctx->device->dma.sg_len, DMA_TO_DEVICE);
-
+                    ctx->device->dma.sg_len, DMA_TO_DEVICE);
 }
 
 static int hash_dma_write(struct hash_ctx *ctx,
-               struct scatterlist *sg, int len)
+                         struct scatterlist *sg, int len)
 {
        int error = hash_set_dma_transfer(ctx, sg, len, DMA_TO_DEVICE);
        if (error) {
-               dev_dbg(ctx->device->dev, "[%s]: hash_set_dma_transfer() "
-                       "failed", __func__);
+               dev_dbg(ctx->device->dev,
+                       "%s: hash_set_dma_transfer() failed\n", __func__);
                return error;
        }
 
@@ -245,19 +243,18 @@ static int get_empty_message_digest(
        if (HASH_OPER_MODE_HASH == ctx->config.oper_mode) {
                if (HASH_ALGO_SHA1 == ctx->config.algorithm) {
                        memcpy(zero_hash, &zero_message_hash_sha1[0],
-                                       SHA1_DIGEST_SIZE);
+                              SHA1_DIGEST_SIZE);
                        *zero_hash_size = SHA1_DIGEST_SIZE;
                        *zero_digest = true;
                } else if (HASH_ALGO_SHA256 ==
                                ctx->config.algorithm) {
                        memcpy(zero_hash, &zero_message_hash_sha256[0],
-                                       SHA256_DIGEST_SIZE);
+                              SHA256_DIGEST_SIZE);
                        *zero_hash_size = SHA256_DIGEST_SIZE;
                        *zero_digest = true;
                } else {
-                       dev_err(device_data->dev, "[%s] "
-                                       "Incorrect algorithm!"
-                                       , __func__);
+                       dev_err(device_data->dev, "%s: Incorrect algorithm!\n",
+                               __func__);
                        ret = -EINVAL;
                        goto out;
                }
@@ -265,25 +262,24 @@ static int get_empty_message_digest(
                if (!ctx->keylen) {
                        if (HASH_ALGO_SHA1 == ctx->config.algorithm) {
                                memcpy(zero_hash, &zero_message_hmac_sha1[0],
-                                               SHA1_DIGEST_SIZE);
+                                      SHA1_DIGEST_SIZE);
                                *zero_hash_size = SHA1_DIGEST_SIZE;
                                *zero_digest = true;
                        } else if (HASH_ALGO_SHA256 == ctx->config.algorithm) {
                                memcpy(zero_hash, &zero_message_hmac_sha256[0],
-                                               SHA256_DIGEST_SIZE);
+                                      SHA256_DIGEST_SIZE);
                                *zero_hash_size = SHA256_DIGEST_SIZE;
                                *zero_digest = true;
                        } else {
-                               dev_err(device_data->dev, "[%s] "
-                                               "Incorrect algorithm!"
-                                               , __func__);
+                               dev_err(device_data->dev, "%s: Incorrect algorithm!\n",
+                                       __func__);
                                ret = -EINVAL;
                                goto out;
                        }
                } else {
-                       dev_dbg(device_data->dev, "[%s] Continue hash "
-                                       "calculation, since hmac key avalable",
-                                       __func__);
+                       dev_dbg(device_data->dev,
+                               "%s: Continue hash calculation, since hmac key available\n",
+                               __func__);
                }
        }
 out:
@@ -299,9 +295,8 @@ out:
  * This function request for disabling power (regulator) and clock,
  * and could also save current hw state.
  */
-static int hash_disable_power(
-               struct hash_device_data *device_data,
-               bool                    save_device_state)
+static int hash_disable_power(struct hash_device_data *device_data,
+                             bool save_device_state)
 {
        int ret = 0;
        struct device *dev = device_data->dev;
@@ -319,7 +314,7 @@ static int hash_disable_power(
        clk_disable(device_data->clk);
        ret = regulator_disable(device_data->regulator);
        if (ret)
-               dev_err(dev, "[%s] regulator_disable() failed!", __func__);
+               dev_err(dev, "%s: regulator_disable() failed!\n", __func__);
 
        device_data->power_state = false;
 
@@ -337,9 +332,8 @@ out:
  * This function request for enabling power (regulator) and clock,
  * and could also restore a previously saved hw state.
  */
-static int hash_enable_power(
-               struct hash_device_data *device_data,
-               bool                    restore_device_state)
+static int hash_enable_power(struct hash_device_data *device_data,
+                            bool restore_device_state)
 {
        int ret = 0;
        struct device *dev = device_data->dev;
@@ -348,14 +342,13 @@ static int hash_enable_power(
        if (!device_data->power_state) {
                ret = regulator_enable(device_data->regulator);
                if (ret) {
-                       dev_err(dev, "[%s]: regulator_enable() failed!",
-                                       __func__);
+                       dev_err(dev, "%s: regulator_enable() failed!\n",
+                               __func__);
                        goto out;
                }
                ret = clk_enable(device_data->clk);
                if (ret) {
-                       dev_err(dev, "[%s]: clk_enable() failed!",
-                                       __func__);
+                       dev_err(dev, "%s: clk_enable() failed!\n", __func__);
                        ret = regulator_disable(
                                        device_data->regulator);
                        goto out;
@@ -366,8 +359,7 @@ static int hash_enable_power(
        if (device_data->restore_dev_state) {
                if (restore_device_state) {
                        device_data->restore_dev_state = false;
-                       hash_resume_state(device_data,
-                               &device_data->state);
+                       hash_resume_state(device_data, &device_data->state);
                }
        }
 out:
@@ -447,7 +439,7 @@ static int hash_get_device_data(struct hash_ctx *ctx,
  * spec or due to a bug in the hw.
  */
 static void hash_hw_write_key(struct hash_device_data *device_data,
-               const u8 *key, unsigned int keylen)
+                             const u8 *key, unsigned int keylen)
 {
        u32 word = 0;
        int nwords = 1;
@@ -491,14 +483,14 @@ static void hash_hw_write_key(struct hash_device_data *device_data,
  * calculation.
  */
 static int init_hash_hw(struct hash_device_data *device_data,
-               struct hash_ctx *ctx)
+                       struct hash_ctx *ctx)
 {
        int ret = 0;
 
        ret = hash_setconfiguration(device_data, &ctx->config);
        if (ret) {
-               dev_err(device_data->dev, "[%s] hash_setconfiguration() "
-                               "failed!", __func__);
+               dev_err(device_data->dev, "%s: hash_setconfiguration() failed!\n",
+                       __func__);
                return ret;
        }
 
@@ -528,9 +520,8 @@ static int hash_get_nents(struct scatterlist *sg, int size, bool *aligned)
                size -= sg->length;
 
                /* hash_set_dma_transfer will align last nent */
-               if ((aligned && !IS_ALIGNED(sg->offset, HASH_DMA_ALIGN_SIZE))
-                       || (!IS_ALIGNED(sg->length, HASH_DMA_ALIGN_SIZE) &&
-                               size > 0))
+               if ((aligned && !IS_ALIGNED(sg->offset, HASH_DMA_ALIGN_SIZE)) ||
+                   (!IS_ALIGNED(sg->length, HASH_DMA_ALIGN_SIZE) && size > 0))
                        aligned_data = false;
 
                sg = sg_next(sg);
@@ -585,21 +576,17 @@ static int hash_init(struct ahash_request *req)
                if (req->nbytes < HASH_DMA_ALIGN_SIZE) {
                        req_ctx->dma_mode = false; /* Don't use DMA */
 
-                       pr_debug(DEV_DBG_NAME " [%s] DMA mode, but direct "
-                                       "to CPU mode for data size < %d",
-                                       __func__, HASH_DMA_ALIGN_SIZE);
+                       pr_debug("%s: DMA mode, but direct to CPU mode for data size < %d\n",
+                                __func__, HASH_DMA_ALIGN_SIZE);
                } else {
                        if (req->nbytes >= HASH_DMA_PERFORMANCE_MIN_SIZE &&
-                                       hash_dma_valid_data(req->src,
-                                               req->nbytes)) {
+                           hash_dma_valid_data(req->src, req->nbytes)) {
                                req_ctx->dma_mode = true;
                        } else {
                                req_ctx->dma_mode = false;
-                               pr_debug(DEV_DBG_NAME " [%s] DMA mode, but use"
-                                               " CPU mode for datalength < %d"
-                                               " or non-aligned data, except "
-                                               "in last nent", __func__,
-                                               HASH_DMA_PERFORMANCE_MIN_SIZE);
+                               pr_debug("%s: DMA mode, but use CPU mode for datalength < %d or non-aligned data, except in last nent\n",
+                                        __func__,
+                                        HASH_DMA_PERFORMANCE_MIN_SIZE);
                        }
                }
        }
@@ -614,9 +601,8 @@ static int hash_init(struct ahash_request *req)
  *                     the HASH hardware.
  *
  */
-static void hash_processblock(
-               struct hash_device_data *device_data,
-               const u32 *message, int length)
+static void hash_processblock(struct hash_device_data *device_data,
+                             const u32 *message, int length)
 {
        int len = length / HASH_BYTES_PER_WORD;
        /*
@@ -641,7 +627,7 @@ static void hash_processblock(
  *
  */
 static void hash_messagepad(struct hash_device_data *device_data,
-               const u32 *message, u8 index_bytes)
+                           const u32 *message, u8 index_bytes)
 {
        int nwords = 1;
 
@@ -666,15 +652,13 @@ static void hash_messagepad(struct hash_device_data *device_data,
 
        /* num_of_bytes == 0 => NBLW <- 0 (32 bits valid in DATAIN) */
        HASH_SET_NBLW(index_bytes * 8);
-       dev_dbg(device_data->dev, "[%s] DIN=0x%08x NBLW=%d", __func__,
-                       readl_relaxed(&device_data->base->din),
-                       (int)(readl_relaxed(&device_data->base->str) &
-                               HASH_STR_NBLW_MASK));
+       dev_dbg(device_data->dev, "%s: DIN=0x%08x NBLW=%lu\n",
+               __func__, readl_relaxed(&device_data->base->din),
+               readl_relaxed(&device_data->base->str) & HASH_STR_NBLW_MASK);
        HASH_SET_DCAL;
-       dev_dbg(device_data->dev, "[%s] after dcal -> DIN=0x%08x NBLW=%d",
-                       __func__, readl_relaxed(&device_data->base->din),
-                       (int)(readl_relaxed(&device_data->base->str) &
-                               HASH_STR_NBLW_MASK));
+       dev_dbg(device_data->dev, "%s: after dcal -> DIN=0x%08x NBLW=%lu\n",
+               __func__, readl_relaxed(&device_data->base->din),
+               readl_relaxed(&device_data->base->str) & HASH_STR_NBLW_MASK);
 
        while (readl(&device_data->base->str) & HASH_STR_DCAL_MASK)
                cpu_relax();
@@ -704,7 +688,7 @@ static void hash_incrementlength(struct hash_req_ctx *ctx, u32 incr)
  * @config:            Pointer to a configuration structure.
  */
 int hash_setconfiguration(struct hash_device_data *device_data,
-               struct hash_config *config)
+                         struct hash_config *config)
 {
        int ret = 0;
 
@@ -731,8 +715,8 @@ int hash_setconfiguration(struct hash_device_data *device_data,
                break;
 
        default:
-               dev_err(device_data->dev, "[%s] Incorrect algorithm.",
-                               __func__);
+               dev_err(device_data->dev, "%s: Incorrect algorithm\n",
+                       __func__);
                return -EPERM;
        }
 
@@ -744,23 +728,22 @@ int hash_setconfiguration(struct hash_device_data *device_data,
                HASH_CLEAR_BITS(&device_data->base->cr,
                                HASH_CR_MODE_MASK);
        else if (HASH_OPER_MODE_HMAC == config->oper_mode) {
-               HASH_SET_BITS(&device_data->base->cr,
-                               HASH_CR_MODE_MASK);
+               HASH_SET_BITS(&device_data->base->cr, HASH_CR_MODE_MASK);
                if (device_data->current_ctx->keylen > HASH_BLOCK_SIZE) {
                        /* Truncate key to blocksize */
-                       dev_dbg(device_data->dev, "[%s] LKEY set", __func__);
+                       dev_dbg(device_data->dev, "%s: LKEY set\n", __func__);
                        HASH_SET_BITS(&device_data->base->cr,
-                                       HASH_CR_LKEY_MASK);
+                                     HASH_CR_LKEY_MASK);
                } else {
-                       dev_dbg(device_data->dev, "[%s] LKEY cleared",
-                                       __func__);
+                       dev_dbg(device_data->dev, "%s: LKEY cleared\n",
+                               __func__);
                        HASH_CLEAR_BITS(&device_data->base->cr,
                                        HASH_CR_LKEY_MASK);
                }
        } else {        /* Wrong hash mode */
                ret = -EPERM;
-               dev_err(device_data->dev, "[%s] HASH_INVALID_PARAMETER!",
-                               __func__);
+               dev_err(device_data->dev, "%s: HASH_INVALID_PARAMETER!\n",
+                       __func__);
        }
        return ret;
 }
@@ -793,8 +776,9 @@ void hash_begin(struct hash_device_data *device_data, struct hash_ctx *ctx)
 }
 
 static int hash_process_data(struct hash_device_data *device_data,
-               struct hash_ctx *ctx, struct hash_req_ctx *req_ctx,
-               int msg_length, u8 *data_buffer, u8 *buffer, u8 *index)
+                            struct hash_ctx *ctx, struct hash_req_ctx *req_ctx,
+                            int msg_length, u8 *data_buffer, u8 *buffer,
+                            u8 *index)
 {
        int ret = 0;
        u32 count;
@@ -809,24 +793,23 @@ static int hash_process_data(struct hash_device_data *device_data,
                        msg_length = 0;
                } else {
                        if (req_ctx->updated) {
-
                                ret = hash_resume_state(device_data,
                                                &device_data->state);
                                memmove(req_ctx->state.buffer,
-                                               device_data->state.buffer,
-                                               HASH_BLOCK_SIZE / sizeof(u32));
+                                       device_data->state.buffer,
+                                       HASH_BLOCK_SIZE / sizeof(u32));
                                if (ret) {
-                                       dev_err(device_data->dev, "[%s] "
-                                                       "hash_resume_state()"
-                                                       " failed!", __func__);
+                                       dev_err(device_data->dev,
+                                               "%s: hash_resume_state() failed!\n",
+                                               __func__);
                                        goto out;
                                }
                        } else {
                                ret = init_hash_hw(device_data, ctx);
                                if (ret) {
-                                       dev_err(device_data->dev, "[%s] "
-                                                       "init_hash_hw()"
-                                                       " failed!", __func__);
+                                       dev_err(device_data->dev,
+                                               "%s: init_hash_hw() failed!\n",
+                                               __func__);
                                        goto out;
                                }
                                req_ctx->updated = 1;
@@ -838,22 +821,21 @@ static int hash_process_data(struct hash_device_data *device_data,
                         * HW peripheral, otherwise we first copy data
                         * to a local buffer
                         */
-                       if ((0 == (((u32)data_buffer) % 4))
-                                       && (0 == *index))
+                       if ((0 == (((u32)data_buffer) % 4)) &&
+                           (0 == *index))
                                hash_processblock(device_data,
-                                               (const u32 *)
-                                               data_buffer, HASH_BLOCK_SIZE);
+                                                 (const u32 *)data_buffer,
+                                                 HASH_BLOCK_SIZE);
                        else {
-                               for (count = 0; count <
-                                               (u32)(HASH_BLOCK_SIZE -
-                                                       *index);
-                                               count++) {
+                               for (count = 0;
+                                    count < (u32)(HASH_BLOCK_SIZE - *index);
+                                    count++) {
                                        buffer[*index + count] =
                                                *(data_buffer + count);
                                }
                                hash_processblock(device_data,
-                                               (const u32 *)buffer,
-                                               HASH_BLOCK_SIZE);
+                                                 (const u32 *)buffer,
+                                                 HASH_BLOCK_SIZE);
                        }
                        hash_incrementlength(req_ctx, HASH_BLOCK_SIZE);
                        data_buffer += (HASH_BLOCK_SIZE - *index);
@@ -865,12 +847,11 @@ static int hash_process_data(struct hash_device_data *device_data,
                                        &device_data->state);
 
                        memmove(device_data->state.buffer,
-                                       req_ctx->state.buffer,
-                                       HASH_BLOCK_SIZE / sizeof(u32));
+                               req_ctx->state.buffer,
+                               HASH_BLOCK_SIZE / sizeof(u32));
                        if (ret) {
-                               dev_err(device_data->dev, "[%s] "
-                                               "hash_save_state()"
-                                               " failed!", __func__);
+                               dev_err(device_data->dev, "%s: hash_save_state() failed!\n",
+                                       __func__);
                                goto out;
                        }
                }
@@ -898,25 +879,24 @@ static int hash_dma_final(struct ahash_request *req)
        if (ret)
                return ret;
 
-       dev_dbg(device_data->dev, "[%s] (ctx=0x%x)!", __func__, (u32) ctx);
+       dev_dbg(device_data->dev, "%s: (ctx=0x%x)!\n", __func__, (u32) ctx);
 
        if (req_ctx->updated) {
                ret = hash_resume_state(device_data, &device_data->state);
 
                if (ret) {
-                       dev_err(device_data->dev, "[%s] hash_resume_state() "
-                                       "failed!", __func__);
+                       dev_err(device_data->dev, "%s: hash_resume_state() failed!\n",
+                               __func__);
                        goto out;
                }
-
        }
 
        if (!req_ctx->updated) {
                ret = hash_setconfiguration(device_data, &ctx->config);
                if (ret) {
-                       dev_err(device_data->dev, "[%s] "
-                                       "hash_setconfiguration() failed!",
-                                       __func__);
+                       dev_err(device_data->dev,
+                               "%s: hash_setconfiguration() failed!\n",
+                               __func__);
                        goto out;
                }
 
@@ -926,9 +906,9 @@ static int hash_dma_final(struct ahash_request *req)
                                        HASH_CR_DMAE_MASK);
                } else {
                        HASH_SET_BITS(&device_data->base->cr,
-                                       HASH_CR_DMAE_MASK);
+                                     HASH_CR_DMAE_MASK);
                        HASH_SET_BITS(&device_data->base->cr,
-                                       HASH_CR_PRIVN_MASK);
+                                     HASH_CR_PRIVN_MASK);
                }
 
                HASH_INITIALIZE;
@@ -944,16 +924,16 @@ static int hash_dma_final(struct ahash_request *req)
        /* Store the nents in the dma struct. */
        ctx->device->dma.nents = hash_get_nents(req->src, req->nbytes, NULL);
        if (!ctx->device->dma.nents) {
-               dev_err(device_data->dev, "[%s] "
-                               "ctx->device->dma.nents = 0", __func__);
+               dev_err(device_data->dev, "%s: ctx->device->dma.nents = 0\n",
+                       __func__);
                ret = ctx->device->dma.nents;
                goto out;
        }
 
        bytes_written = hash_dma_write(ctx, req->src, req->nbytes);
        if (bytes_written != req->nbytes) {
-               dev_err(device_data->dev, "[%s] "
-                               "hash_dma_write() failed!", __func__);
+               dev_err(device_data->dev, "%s: hash_dma_write() failed!\n",
+                       __func__);
                ret = bytes_written;
                goto out;
        }
@@ -968,8 +948,8 @@ static int hash_dma_final(struct ahash_request *req)
                unsigned int keylen = ctx->keylen;
                u8 *key = ctx->key;
 
-               dev_dbg(device_data->dev, "[%s] keylen: %d", __func__,
-                               ctx->keylen);
+               dev_dbg(device_data->dev, "%s: keylen: %d\n",
+                       __func__, ctx->keylen);
                hash_hw_write_key(device_data, key, keylen);
        }
 
@@ -1004,14 +984,14 @@ static int hash_hw_final(struct ahash_request *req)
        if (ret)
                return ret;
 
-       dev_dbg(device_data->dev, "[%s] (ctx=0x%x)!", __func__, (u32) ctx);
+       dev_dbg(device_data->dev, "%s: (ctx=0x%x)!\n", __func__, (u32) ctx);
 
        if (req_ctx->updated) {
                ret = hash_resume_state(device_data, &device_data->state);
 
                if (ret) {
-                       dev_err(device_data->dev, "[%s] hash_resume_state() "
-                                       "failed!", __func__);
+                       dev_err(device_data->dev,
+                               "%s: hash_resume_state() failed!\n", __func__);
                        goto out;
                }
        } else if (req->nbytes == 0 && ctx->keylen == 0) {
@@ -1025,31 +1005,33 @@ static int hash_hw_final(struct ahash_request *req)
                ret = get_empty_message_digest(device_data, &zero_hash[0],
                                &zero_hash_size, &zero_digest);
                if (!ret && likely(zero_hash_size == ctx->digestsize) &&
-                               zero_digest) {
+                   zero_digest) {
                        memcpy(req->result, &zero_hash[0], ctx->digestsize);
                        goto out;
                } else if (!ret && !zero_digest) {
-                       dev_dbg(device_data->dev, "[%s] HMAC zero msg with "
-                                       "key, continue...", __func__);
+                       dev_dbg(device_data->dev,
+                               "%s: HMAC zero msg with key, continue...\n",
+                               __func__);
                } else {
-                       dev_err(device_data->dev, "[%s] ret=%d, or wrong "
-                                       "digest size? %s", __func__, ret,
-                                       (zero_hash_size == ctx->digestsize) ?
-                                       "true" : "false");
+                       dev_err(device_data->dev,
+                               "%s: ret=%d, or wrong digest size? %s\n",
+                               __func__, ret,
+                               zero_hash_size == ctx->digestsize ?
+                               "true" : "false");
                        /* Return error */
                        goto out;
                }
        } else if (req->nbytes == 0 && ctx->keylen > 0) {
-               dev_err(device_data->dev, "[%s] Empty message with "
-                               "keylength > 0, NOT supported.", __func__);
+               dev_err(device_data->dev, "%s: Empty message with keylength > 0, NOT supported\n",
+                       __func__);
                goto out;
        }
 
        if (!req_ctx->updated) {
                ret = init_hash_hw(device_data, ctx);
                if (ret) {
-                       dev_err(device_data->dev, "[%s] init_hash_hw() "
-                                       "failed!", __func__);
+                       dev_err(device_data->dev,
+                               "%s: init_hash_hw() failed!\n", __func__);
                        goto out;
                }
        }
@@ -1067,8 +1049,8 @@ static int hash_hw_final(struct ahash_request *req)
                unsigned int keylen = ctx->keylen;
                u8 *key = ctx->key;
 
-               dev_dbg(device_data->dev, "[%s] keylen: %d", __func__,
-                               ctx->keylen);
+               dev_dbg(device_data->dev, "%s: keylen: %d\n",
+                       __func__, ctx->keylen);
                hash_hw_write_key(device_data, key, keylen);
        }
 
@@ -1115,10 +1097,8 @@ int hash_hw_update(struct ahash_request *req)
        /* Check if ctx->state.length + msg_length
           overflows */
        if (msg_length > (req_ctx->state.length.low_word + msg_length) &&
-                       HASH_HIGH_WORD_MAX_VAL ==
-                       req_ctx->state.length.high_word) {
-               pr_err(DEV_DBG_NAME " [%s] HASH_MSG_LENGTH_OVERFLOW!",
-                               __func__);
+           HASH_HIGH_WORD_MAX_VAL == req_ctx->state.length.high_word) {
+               pr_err("%s: HASH_MSG_LENGTH_OVERFLOW!\n", __func__);
                return -EPERM;
        }
 
@@ -1133,8 +1113,8 @@ int hash_hw_update(struct ahash_request *req)
                                data_buffer, buffer, &index);
 
                if (ret) {
-                       dev_err(device_data->dev, "[%s] hash_internal_hw_"
-                                       "update() failed!", __func__);
+                       dev_err(device_data->dev, "%s: hash_internal_hw_update() failed!\n",
+                               __func__);
                        goto out;
                }
 
@@ -1142,9 +1122,8 @@ int hash_hw_update(struct ahash_request *req)
        }
 
        req_ctx->state.index = index;
-       dev_dbg(device_data->dev, "[%s] indata length=%d, bin=%d))",
-                       __func__, req_ctx->state.index,
-                       req_ctx->state.bit_index);
+       dev_dbg(device_data->dev, "%s: indata length=%d, bin=%d\n",
+               __func__, req_ctx->state.index, req_ctx->state.bit_index);
 
 out:
        release_hash_device(device_data);
@@ -1158,23 +1137,23 @@ out:
  * @device_state:      The state to be restored in the hash hardware
  */
 int hash_resume_state(struct hash_device_data *device_data,
-               const struct hash_state *device_state)
+                     const struct hash_state *device_state)
 {
        u32 temp_cr;
        s32 count;
        int hash_mode = HASH_OPER_MODE_HASH;
 
        if (NULL == device_state) {
-               dev_err(device_data->dev, "[%s] HASH_INVALID_PARAMETER!",
-                               __func__);
+               dev_err(device_data->dev, "%s: HASH_INVALID_PARAMETER!\n",
+                       __func__);
                return -EPERM;
        }
 
        /* Check correctness of index and length members */
-       if (device_state->index > HASH_BLOCK_SIZE
-           || (device_state->length.low_word % HASH_BLOCK_SIZE) != 0) {
-               dev_err(device_data->dev, "[%s] HASH_INVALID_PARAMETER!",
-                               __func__);
+       if (device_state->index > HASH_BLOCK_SIZE ||
+           (device_state->length.low_word % HASH_BLOCK_SIZE) != 0) {
+               dev_err(device_data->dev, "%s: HASH_INVALID_PARAMETER!\n",
+                       __func__);
                return -EPERM;
        }
 
@@ -1198,7 +1177,7 @@ int hash_resume_state(struct hash_device_data *device_data,
                        break;
 
                writel_relaxed(device_state->csr[count],
-                               &device_data->base->csrx[count]);
+                              &device_data->base->csrx[count]);
        }
 
        writel_relaxed(device_state->csfull, &device_data->base->csfull);
@@ -1216,15 +1195,15 @@ int hash_resume_state(struct hash_device_data *device_data,
  * @device_state:      The strucure where the hardware state should be saved.
  */
 int hash_save_state(struct hash_device_data *device_data,
-               struct hash_state *device_state)
+                   struct hash_state *device_state)
 {
        u32 temp_cr;
        u32 count;
        int hash_mode = HASH_OPER_MODE_HASH;
 
        if (NULL == device_state) {
-               dev_err(device_data->dev, "[%s] HASH_INVALID_PARAMETER!",
-                               __func__);
+               dev_err(device_data->dev, "%s: HASH_INVALID_PARAMETER!\n",
+                       __func__);
                return -ENOTSUPP;
        }
 
@@ -1270,20 +1249,18 @@ int hash_save_state(struct hash_device_data *device_data,
 int hash_check_hw(struct hash_device_data *device_data)
 {
        /* Checking Peripheral Ids  */
-       if (HASH_P_ID0 == readl_relaxed(&device_data->base->periphid0)
-               && HASH_P_ID1 == readl_relaxed(&device_data->base->periphid1)
-               && HASH_P_ID2 == readl_relaxed(&device_data->base->periphid2)
-               && HASH_P_ID3 == readl_relaxed(&device_data->base->periphid3)
-               && HASH_CELL_ID0 == readl_relaxed(&device_data->base->cellid0)
-               && HASH_CELL_ID1 == readl_relaxed(&device_data->base->cellid1)
-               && HASH_CELL_ID2 == readl_relaxed(&device_data->base->cellid2)
-               && HASH_CELL_ID3 == readl_relaxed(&device_data->base->cellid3)
-          ) {
+       if (HASH_P_ID0 == readl_relaxed(&device_data->base->periphid0) &&
+           HASH_P_ID1 == readl_relaxed(&device_data->base->periphid1) &&
+           HASH_P_ID2 == readl_relaxed(&device_data->base->periphid2) &&
+           HASH_P_ID3 == readl_relaxed(&device_data->base->periphid3) &&
+           HASH_CELL_ID0 == readl_relaxed(&device_data->base->cellid0) &&
+           HASH_CELL_ID1 == readl_relaxed(&device_data->base->cellid1) &&
+           HASH_CELL_ID2 == readl_relaxed(&device_data->base->cellid2) &&
+           HASH_CELL_ID3 == readl_relaxed(&device_data->base->cellid3)) {
                return 0;
        }
 
-       dev_err(device_data->dev, "[%s] HASH_UNSUPPORTED_HW!",
-                       __func__);
+       dev_err(device_data->dev, "%s: HASH_UNSUPPORTED_HW!\n", __func__);
        return -ENOTSUPP;
 }
 
@@ -1294,14 +1271,14 @@ int hash_check_hw(struct hash_device_data *device_data)
  * @algorithm:         The algorithm in use.
  */
 void hash_get_digest(struct hash_device_data *device_data,
-               u8 *digest, int algorithm)
+                    u8 *digest, int algorithm)
 {
        u32 temp_hx_val, count;
        int loop_ctr;
 
        if (algorithm != HASH_ALGO_SHA1 && algorithm != HASH_ALGO_SHA256) {
-               dev_err(device_data->dev, "[%s] Incorrect algorithm %d",
-                               __func__, algorithm);
+               dev_err(device_data->dev, "%s: Incorrect algorithm %d\n",
+                       __func__, algorithm);
                return;
        }
 
@@ -1310,8 +1287,8 @@ void hash_get_digest(struct hash_device_data *device_data,
        else
                loop_ctr = SHA256_DIGEST_SIZE / sizeof(u32);
 
-       dev_dbg(device_data->dev, "[%s] digest array:(0x%x)",
-                       __func__, (u32) digest);
+       dev_dbg(device_data->dev, "%s: digest array:(0x%x)\n",
+               __func__, (u32) digest);
 
        /* Copy result into digest array */
        for (count = 0; count < loop_ctr; count++) {
@@ -1337,8 +1314,7 @@ static int ahash_update(struct ahash_request *req)
        /* Skip update for DMA, all data will be passed to DMA in final */
 
        if (ret) {
-               pr_err(DEV_DBG_NAME " [%s] hash_hw_update() failed!",
-                               __func__);
+               pr_err("%s: hash_hw_update() failed!\n", __func__);
        }
 
        return ret;
@@ -1353,7 +1329,7 @@ static int ahash_final(struct ahash_request *req)
        int ret = 0;
        struct hash_req_ctx *req_ctx = ahash_request_ctx(req);
 
-       pr_debug(DEV_DBG_NAME " [%s] data size: %d", __func__, req->nbytes);
+       pr_debug("%s: data size: %d\n", __func__, req->nbytes);
 
        if ((hash_mode == HASH_MODE_DMA) && req_ctx->dma_mode)
                ret = hash_dma_final(req);
@@ -1361,15 +1337,14 @@ static int ahash_final(struct ahash_request *req)
                ret = hash_hw_final(req);
 
        if (ret) {
-               pr_err(DEV_DBG_NAME " [%s] hash_hw/dma_final() failed",
-                               __func__);
+               pr_err("%s: hash_hw/dma_final() failed\n", __func__);
        }
 
        return ret;
 }
 
 static int hash_setkey(struct crypto_ahash *tfm,
-               const u8 *key, unsigned int keylen, int alg)
+                      const u8 *key, unsigned int keylen, int alg)
 {
        int ret = 0;
        struct hash_ctx *ctx = crypto_ahash_ctx(tfm);
@@ -1379,8 +1354,8 @@ static int hash_setkey(struct crypto_ahash *tfm,
         */
        ctx->key = kmemdup(key, keylen, GFP_KERNEL);
        if (!ctx->key) {
-               pr_err(DEV_DBG_NAME " [%s] Failed to allocate ctx->key "
-                      "for %d\n", __func__, alg);
+               pr_err("%s: Failed to allocate ctx->key for %d\n",
+                      __func__, alg);
                return -ENOMEM;
        }
        ctx->keylen = keylen;
@@ -1501,13 +1476,13 @@ out:
 }
 
 static int hmac_sha1_setkey(struct crypto_ahash *tfm,
-               const u8 *key, unsigned int keylen)
+                           const u8 *key, unsigned int keylen)
 {
        return hash_setkey(tfm, key, keylen, HASH_ALGO_SHA1);
 }
 
 static int hmac_sha256_setkey(struct crypto_ahash *tfm,
-               const u8 *key, unsigned int keylen)
+                             const u8 *key, unsigned int keylen)
 {
        return hash_setkey(tfm, key, keylen, HASH_ALGO_SHA256);
 }
@@ -1528,7 +1503,7 @@ static int hash_cra_init(struct crypto_tfm *tfm)
                        hash);
 
        crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
-                       sizeof(struct hash_req_ctx));
+                                sizeof(struct hash_req_ctx));
 
        ctx->config.data_format = HASH_DATA_8_BITS;
        ctx->config.algorithm = hash_alg->conf.algorithm;
@@ -1541,98 +1516,97 @@ static int hash_cra_init(struct crypto_tfm *tfm)
 
 static struct hash_algo_template hash_algs[] = {
        {
-                       .conf.algorithm = HASH_ALGO_SHA1,
-                       .conf.oper_mode = HASH_OPER_MODE_HASH,
-                       .hash = {
-                               .init = hash_init,
-                               .update = ahash_update,
-                               .final = ahash_final,
-                               .digest = ahash_sha1_digest,
-                               .halg.digestsize = SHA1_DIGEST_SIZE,
-                               .halg.statesize = sizeof(struct hash_ctx),
-                               .halg.base = {
-                                       .cra_name = "sha1",
-                                       .cra_driver_name = "sha1-ux500",
-                                       .cra_flags = CRYPTO_ALG_TYPE_AHASH |
-                                                       CRYPTO_ALG_ASYNC,
-                                       .cra_blocksize = SHA1_BLOCK_SIZE,
-                                       .cra_ctxsize = sizeof(struct hash_ctx),
-                                       .cra_init = hash_cra_init,
-                                       .cra_module = THIS_MODULE,
+               .conf.algorithm = HASH_ALGO_SHA1,
+               .conf.oper_mode = HASH_OPER_MODE_HASH,
+               .hash = {
+                       .init = hash_init,
+                       .update = ahash_update,
+                       .final = ahash_final,
+                       .digest = ahash_sha1_digest,
+                       .halg.digestsize = SHA1_DIGEST_SIZE,
+                       .halg.statesize = sizeof(struct hash_ctx),
+                       .halg.base = {
+                               .cra_name = "sha1",
+                               .cra_driver_name = "sha1-ux500",
+                               .cra_flags = (CRYPTO_ALG_TYPE_AHASH |
+                                             CRYPTO_ALG_ASYNC),
+                               .cra_blocksize = SHA1_BLOCK_SIZE,
+                               .cra_ctxsize = sizeof(struct hash_ctx),
+                               .cra_init = hash_cra_init,
+                               .cra_module = THIS_MODULE,
                        }
                }
        },
        {
-                       .conf.algorithm         = HASH_ALGO_SHA256,
-                       .conf.oper_mode         = HASH_OPER_MODE_HASH,
-                       .hash = {
-                               .init = hash_init,
-                               .update = ahash_update,
-                               .final = ahash_final,
-                               .digest = ahash_sha256_digest,
-                               .halg.digestsize = SHA256_DIGEST_SIZE,
-                               .halg.statesize = sizeof(struct hash_ctx),
-                               .halg.base = {
-                                       .cra_name = "sha256",
-                                       .cra_driver_name = "sha256-ux500",
-                                       .cra_flags = CRYPTO_ALG_TYPE_AHASH |
-                                                       CRYPTO_ALG_ASYNC,
-                                       .cra_blocksize = SHA256_BLOCK_SIZE,
-                                       .cra_ctxsize = sizeof(struct hash_ctx),
-                                       .cra_type = &crypto_ahash_type,
-                                       .cra_init = hash_cra_init,
-                                       .cra_module = THIS_MODULE,
-                               }
+               .conf.algorithm = HASH_ALGO_SHA256,
+               .conf.oper_mode = HASH_OPER_MODE_HASH,
+               .hash = {
+                       .init = hash_init,
+                       .update = ahash_update,
+                       .final = ahash_final,
+                       .digest = ahash_sha256_digest,
+                       .halg.digestsize = SHA256_DIGEST_SIZE,
+                       .halg.statesize = sizeof(struct hash_ctx),
+                       .halg.base = {
+                               .cra_name = "sha256",
+                               .cra_driver_name = "sha256-ux500",
+                               .cra_flags = (CRYPTO_ALG_TYPE_AHASH |
+                                             CRYPTO_ALG_ASYNC),
+                               .cra_blocksize = SHA256_BLOCK_SIZE,
+                               .cra_ctxsize = sizeof(struct hash_ctx),
+                               .cra_type = &crypto_ahash_type,
+                               .cra_init = hash_cra_init,
+                               .cra_module = THIS_MODULE,
                        }
-
+               }
        },
        {
-                       .conf.algorithm         = HASH_ALGO_SHA1,
-                       .conf.oper_mode         = HASH_OPER_MODE_HMAC,
+               .conf.algorithm = HASH_ALGO_SHA1,
+               .conf.oper_mode = HASH_OPER_MODE_HMAC,
                        .hash = {
-                               .init = hash_init,
-                               .update = ahash_update,
-                               .final = ahash_final,
-                               .digest = hmac_sha1_digest,
-                               .setkey = hmac_sha1_setkey,
-                               .halg.digestsize = SHA1_DIGEST_SIZE,
-                               .halg.statesize = sizeof(struct hash_ctx),
-                               .halg.base = {
-                                       .cra_name = "hmac(sha1)",
-                                       .cra_driver_name = "hmac-sha1-ux500",
-                                       .cra_flags = CRYPTO_ALG_TYPE_AHASH |
-                                                       CRYPTO_ALG_ASYNC,
-                                       .cra_blocksize = SHA1_BLOCK_SIZE,
-                                       .cra_ctxsize = sizeof(struct hash_ctx),
-                                       .cra_type = &crypto_ahash_type,
-                                       .cra_init = hash_cra_init,
-                                       .cra_module = THIS_MODULE,
-                               }
+                       .init = hash_init,
+                       .update = ahash_update,
+                       .final = ahash_final,
+                       .digest = hmac_sha1_digest,
+                       .setkey = hmac_sha1_setkey,
+                       .halg.digestsize = SHA1_DIGEST_SIZE,
+                       .halg.statesize = sizeof(struct hash_ctx),
+                       .halg.base = {
+                               .cra_name = "hmac(sha1)",
+                               .cra_driver_name = "hmac-sha1-ux500",
+                               .cra_flags = (CRYPTO_ALG_TYPE_AHASH |
+                                             CRYPTO_ALG_ASYNC),
+                               .cra_blocksize = SHA1_BLOCK_SIZE,
+                               .cra_ctxsize = sizeof(struct hash_ctx),
+                               .cra_type = &crypto_ahash_type,
+                               .cra_init = hash_cra_init,
+                               .cra_module = THIS_MODULE,
                        }
+               }
        },
        {
-                       .conf.algorithm         = HASH_ALGO_SHA256,
-                       .conf.oper_mode         = HASH_OPER_MODE_HMAC,
-                       .hash = {
-                               .init = hash_init,
-                               .update = ahash_update,
-                               .final = ahash_final,
-                               .digest = hmac_sha256_digest,
-                               .setkey = hmac_sha256_setkey,
-                               .halg.digestsize = SHA256_DIGEST_SIZE,
-                               .halg.statesize = sizeof(struct hash_ctx),
-                               .halg.base = {
-                                       .cra_name = "hmac(sha256)",
-                                       .cra_driver_name = "hmac-sha256-ux500",
-                                       .cra_flags = CRYPTO_ALG_TYPE_AHASH |
-                                                       CRYPTO_ALG_ASYNC,
-                                       .cra_blocksize = SHA256_BLOCK_SIZE,
-                                       .cra_ctxsize = sizeof(struct hash_ctx),
-                                       .cra_type = &crypto_ahash_type,
-                                       .cra_init = hash_cra_init,
-                                       .cra_module = THIS_MODULE,
-                               }
+               .conf.algorithm = HASH_ALGO_SHA256,
+               .conf.oper_mode = HASH_OPER_MODE_HMAC,
+               .hash = {
+                       .init = hash_init,
+                       .update = ahash_update,
+                       .final = ahash_final,
+                       .digest = hmac_sha256_digest,
+                       .setkey = hmac_sha256_setkey,
+                       .halg.digestsize = SHA256_DIGEST_SIZE,
+                       .halg.statesize = sizeof(struct hash_ctx),
+                       .halg.base = {
+                               .cra_name = "hmac(sha256)",
+                               .cra_driver_name = "hmac-sha256-ux500",
+                               .cra_flags = (CRYPTO_ALG_TYPE_AHASH |
+                                             CRYPTO_ALG_ASYNC),
+                               .cra_blocksize = SHA256_BLOCK_SIZE,
+                               .cra_ctxsize = sizeof(struct hash_ctx),
+                               .cra_type = &crypto_ahash_type,
+                               .cra_init = hash_cra_init,
+                               .cra_module = THIS_MODULE,
                        }
+               }
        }
 };
 
@@ -1649,7 +1623,7 @@ static int ahash_algs_register_all(struct hash_device_data *device_data)
                ret = crypto_register_ahash(&hash_algs[i].hash);
                if (ret) {
                        count = i;
-                       dev_err(device_data->dev, "[%s] alg registration failed",
+                       dev_err(device_data->dev, "%s: alg registration failed\n",
                                hash_algs[i].hash.halg.base.cra_driver_name);
                        goto unreg;
                }
@@ -1683,9 +1657,8 @@ static int ux500_hash_probe(struct platform_device *pdev)
        struct hash_device_data *device_data;
        struct device           *dev = &pdev->dev;
 
-       device_data = kzalloc(sizeof(struct hash_device_data), GFP_ATOMIC);
+       device_data = kzalloc(sizeof(*device_data), GFP_ATOMIC);
        if (!device_data) {
-               dev_dbg(dev, "[%s] kzalloc() failed!", __func__);
                ret = -ENOMEM;
                goto out;
        }
@@ -1695,14 +1668,14 @@ static int ux500_hash_probe(struct platform_device *pdev)
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
-               dev_dbg(dev, "[%s] platform_get_resource() failed!", __func__);
+               dev_dbg(dev, "%s: platform_get_resource() failed!\n", __func__);
                ret = -ENODEV;
                goto out_kfree;
        }
 
        res = request_mem_region(res->start, resource_size(res), pdev->name);
        if (res == NULL) {
-               dev_dbg(dev, "[%s] request_mem_region() failed!", __func__);
+               dev_dbg(dev, "%s: request_mem_region() failed!\n", __func__);
                ret = -EBUSY;
                goto out_kfree;
        }
@@ -1710,8 +1683,7 @@ static int ux500_hash_probe(struct platform_device *pdev)
        device_data->phybase = res->start;
        device_data->base = ioremap(res->start, resource_size(res));
        if (!device_data->base) {
-               dev_err(dev, "[%s] ioremap() failed!",
-                               __func__);
+               dev_err(dev, "%s: ioremap() failed!\n", __func__);
                ret = -ENOMEM;
                goto out_free_mem;
        }
@@ -1721,7 +1693,7 @@ static int ux500_hash_probe(struct platform_device *pdev)
        /* Enable power for HASH1 hardware block */
        device_data->regulator = regulator_get(dev, "v-ape");
        if (IS_ERR(device_data->regulator)) {
-               dev_err(dev, "[%s] regulator_get() failed!", __func__);
+               dev_err(dev, "%s: regulator_get() failed!\n", __func__);
                ret = PTR_ERR(device_data->regulator);
                device_data->regulator = NULL;
                goto out_unmap;
@@ -1730,27 +1702,27 @@ static int ux500_hash_probe(struct platform_device *pdev)
        /* Enable the clock for HASH1 hardware block */
        device_data->clk = clk_get(dev, NULL);
        if (IS_ERR(device_data->clk)) {
-               dev_err(dev, "[%s] clk_get() failed!", __func__);
+               dev_err(dev, "%s: clk_get() failed!\n", __func__);
                ret = PTR_ERR(device_data->clk);
                goto out_regulator;
        }
 
        ret = clk_prepare(device_data->clk);
        if (ret) {
-               dev_err(dev, "[%s] clk_prepare() failed!", __func__);
+               dev_err(dev, "%s: clk_prepare() failed!\n", __func__);
                goto out_clk;
        }
 
        /* Enable device power (and clock) */
        ret = hash_enable_power(device_data, false);
        if (ret) {
-               dev_err(dev, "[%s]: hash_enable_power() failed!", __func__);
+               dev_err(dev, "%s: hash_enable_power() failed!\n", __func__);
                goto out_clk_unprepare;
        }
 
        ret = hash_check_hw(device_data);
        if (ret) {
-               dev_err(dev, "[%s] hash_check_hw() failed!", __func__);
+               dev_err(dev, "%s: hash_check_hw() failed!\n", __func__);
                goto out_power;
        }
 
@@ -1766,8 +1738,8 @@ static int ux500_hash_probe(struct platform_device *pdev)
 
        ret = ahash_algs_register_all(device_data);
        if (ret) {
-               dev_err(dev, "[%s] ahash_algs_register_all() "
-                               "failed!", __func__);
+               dev_err(dev, "%s: ahash_algs_register_all() failed!\n",
+                       __func__);
                goto out_power;
        }
 
@@ -1810,8 +1782,7 @@ static int ux500_hash_remove(struct platform_device *pdev)
 
        device_data = platform_get_drvdata(pdev);
        if (!device_data) {
-               dev_err(dev, "[%s]: platform_get_drvdata() failed!",
-                       __func__);
+               dev_err(dev, "%s: platform_get_drvdata() failed!\n", __func__);
                return -ENOMEM;
        }
 
@@ -1841,7 +1812,7 @@ static int ux500_hash_remove(struct platform_device *pdev)
                ahash_algs_unregister_all(device_data);
 
        if (hash_disable_power(device_data, false))
-               dev_err(dev, "[%s]: hash_disable_power() failed",
+               dev_err(dev, "%s: hash_disable_power() failed\n",
                        __func__);
 
        clk_unprepare(device_data->clk);
@@ -1870,8 +1841,8 @@ static void ux500_hash_shutdown(struct platform_device *pdev)
 
        device_data = platform_get_drvdata(pdev);
        if (!device_data) {
-               dev_err(&pdev->dev, "[%s] platform_get_drvdata() failed!",
-                               __func__);
+               dev_err(&pdev->dev, "%s: platform_get_drvdata() failed!\n",
+                       __func__);
                return;
        }
 
@@ -1880,8 +1851,8 @@ static void ux500_hash_shutdown(struct platform_device *pdev)
        /* current_ctx allocates a device, NULL = unallocated */
        if (!device_data->current_ctx) {
                if (down_trylock(&driver_data.device_allocation))
-                       dev_dbg(&pdev->dev, "[%s]: Cryp still in use!"
-                               "Shutting down anyway...", __func__);
+                       dev_dbg(&pdev->dev, "%s: Cryp still in use! Shutting down anyway...\n",
+                               __func__);
                /**
                 * (Allocate the device)
                 * Need to set this to non-null (dummy) value,
@@ -1906,8 +1877,8 @@ static void ux500_hash_shutdown(struct platform_device *pdev)
                release_mem_region(res->start, resource_size(res));
 
        if (hash_disable_power(device_data, false))
-               dev_err(&pdev->dev, "[%s] hash_disable_power() failed",
-                               __func__);
+               dev_err(&pdev->dev, "%s: hash_disable_power() failed\n",
+                       __func__);
 }
 
 /**
@@ -1922,7 +1893,7 @@ static int ux500_hash_suspend(struct device *dev)
 
        device_data = dev_get_drvdata(dev);
        if (!device_data) {
-               dev_err(dev, "[%s] platform_get_drvdata() failed!", __func__);
+               dev_err(dev, "%s: platform_get_drvdata() failed!\n", __func__);
                return -ENOMEM;
        }
 
@@ -1933,15 +1904,16 @@ static int ux500_hash_suspend(struct device *dev)
 
        if (device_data->current_ctx == ++temp_ctx) {
                if (down_interruptible(&driver_data.device_allocation))
-                       dev_dbg(dev, "[%s]: down_interruptible() failed",
+                       dev_dbg(dev, "%s: down_interruptible() failed\n",
                                __func__);
                ret = hash_disable_power(device_data, false);
 
-       } else
+       } else {
                ret = hash_disable_power(device_data, true);
+       }
 
        if (ret)
-               dev_err(dev, "[%s]: hash_disable_power()", __func__);
+               dev_err(dev, "%s: hash_disable_power()\n", __func__);
 
        return ret;
 }
@@ -1958,7 +1930,7 @@ static int ux500_hash_resume(struct device *dev)
 
        device_data = dev_get_drvdata(dev);
        if (!device_data) {
-               dev_err(dev, "[%s] platform_get_drvdata() failed!", __func__);
+               dev_err(dev, "%s: platform_get_drvdata() failed!\n", __func__);
                return -ENOMEM;
        }
 
@@ -1973,7 +1945,7 @@ static int ux500_hash_resume(struct device *dev)
                ret = hash_enable_power(device_data, true);
 
        if (ret)
-               dev_err(dev, "[%s]: hash_enable_power() failed!", __func__);
+               dev_err(dev, "%s: hash_enable_power() failed!\n", __func__);
 
        return ret;
 }
@@ -1981,8 +1953,8 @@ static int ux500_hash_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(ux500_hash_pm, ux500_hash_suspend, ux500_hash_resume);
 
 static const struct of_device_id ux500_hash_match[] = {
-        { .compatible = "stericsson,ux500-hash" },
-        { },
+       { .compatible = "stericsson,ux500-hash" },
+       { },
 };
 
 static struct platform_driver hash_driver = {
index 5a18f82f732af57a319628190713e6bd054cf8b3..ba7f93225851b56aab32c1ac2c296400308c6256 100644 (file)
@@ -73,7 +73,7 @@ static int acpi_dma_parse_resource_group(const struct acpi_csrt_group *grp,
        if (si->mmio_base_low != mem || si->gsi_interrupt != irq)
                return 0;
 
-       vendor_id = le32_to_cpu(grp->vendor_id);
+       vendor_id = le32_to_cpu((__force __le32)grp->vendor_id);
        dev_dbg(&adev->dev, "matches with %.4s%04X (rev %u)\n",
                (char *)&vendor_id, grp->device_id, grp->revision);
 
index eea479c121736e20c6e52f71059df1b4e14a364b..89eb89f222846e0ff5d20cfc5e14619fc05d6600 100644 (file)
  * which does not support descriptor writeback.
  */
 
+static inline bool is_request_line_unset(struct dw_dma_chan *dwc)
+{
+       return dwc->request_line == (typeof(dwc->request_line))~0;
+}
+
 static inline void dwc_set_masters(struct dw_dma_chan *dwc)
 {
        struct dw_dma *dw = to_dw_dma(dwc->chan.device);
        struct dw_dma_slave *dws = dwc->chan.private;
        unsigned char mmax = dw->nr_masters - 1;
 
-       if (dwc->request_line == ~0) {
-               dwc->src_master = min_t(unsigned char, mmax, dwc_get_sms(dws));
-               dwc->dst_master = min_t(unsigned char, mmax, dwc_get_dms(dws));
-       }
+       if (!is_request_line_unset(dwc))
+               return;
+
+       dwc->src_master = min_t(unsigned char, mmax, dwc_get_sms(dws));
+       dwc->dst_master = min_t(unsigned char, mmax, dwc_get_dms(dws));
 }
 
 #define DWC_DEFAULT_CTLLO(_chan) ({                            \
@@ -644,10 +650,13 @@ static void dw_dma_tasklet(unsigned long data)
 static irqreturn_t dw_dma_interrupt(int irq, void *dev_id)
 {
        struct dw_dma *dw = dev_id;
-       u32 status;
+       u32 status = dma_readl(dw, STATUS_INT);
+
+       dev_vdbg(dw->dma.dev, "%s: status=0x%x\n", __func__, status);
 
-       dev_vdbg(dw->dma.dev, "%s: status=0x%x\n", __func__,
-                       dma_readl(dw, STATUS_INT));
+       /* Check if we have any interrupt from the DMAC */
+       if (!status)
+               return IRQ_NONE;
 
        /*
         * Just disable the interrupts. We'll turn them back on in the
@@ -984,7 +993,7 @@ set_runtime_config(struct dma_chan *chan, struct dma_slave_config *sconfig)
        dwc->direction = sconfig->direction;
 
        /* Take the request line from slave_id member */
-       if (dwc->request_line == ~0)
+       if (is_request_line_unset(dwc))
                dwc->request_line = sconfig->slave_id;
 
        convert_burst(&dwc->dma_sconfig.src_maxburst);
@@ -1089,16 +1098,16 @@ dwc_tx_status(struct dma_chan *chan,
        enum dma_status         ret;
 
        ret = dma_cookie_status(chan, cookie, txstate);
-       if (ret != DMA_SUCCESS) {
-               dwc_scan_descriptors(to_dw_dma(chan->device), dwc);
+       if (ret == DMA_SUCCESS)
+               return ret;
 
-               ret = dma_cookie_status(chan, cookie, txstate);
-       }
+       dwc_scan_descriptors(to_dw_dma(chan->device), dwc);
 
+       ret = dma_cookie_status(chan, cookie, txstate);
        if (ret != DMA_SUCCESS)
                dma_set_residue(txstate, dwc_get_residue(dwc));
 
-       if (dwc->paused)
+       if (dwc->paused && ret == DMA_IN_PROGRESS)
                return DMA_PAUSED;
 
        return ret;
@@ -1560,8 +1569,8 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
        /* Disable BLOCK interrupts as well */
        channel_clear_bit(dw, MASK.BLOCK, dw->all_chan_mask);
 
-       err = devm_request_irq(chip->dev, chip->irq, dw_dma_interrupt, 0,
-                              "dw_dmac", dw);
+       err = devm_request_irq(chip->dev, chip->irq, dw_dma_interrupt,
+                              IRQF_SHARED, "dw_dmac", dw);
        if (err)
                return err;
 
index 6c9449cffae81b90fd20c0ba9f2df7c7166e8f1c..e35d97590311329fe1f7bd93be5cc4b845f3a7c2 100644 (file)
@@ -253,6 +253,7 @@ static const struct acpi_device_id dw_dma_acpi_id_table[] = {
        { "INTL9C60", 0 },
        { }
 };
+MODULE_DEVICE_TABLE(acpi, dw_dma_acpi_id_table);
 #endif
 
 #ifdef CONFIG_PM_SLEEP
index 5f3e532436ee40c5f035b4c9bd6b2b008700b350..4f6d87bcaa0d689a443b20d2b1cea8a059ff19bb 100644 (file)
@@ -502,8 +502,6 @@ static enum dma_status edma_tx_status(struct dma_chan *chan,
        } else if (echan->edesc && echan->edesc->vdesc.tx.cookie == cookie) {
                struct edma_desc *edesc = echan->edesc;
                txstate->residue = edma_desc_size(edesc);
-       } else {
-               txstate->residue = 0;
        }
        spin_unlock_irqrestore(&echan->vchan.lock, flags);
 
index f2bf8c0c46757d0dbd351af10660cc5643f2cfbd..591cd8c63abbcb081a4cd2ca264ed118f7f3d782 100644 (file)
@@ -1313,15 +1313,7 @@ static enum dma_status ep93xx_dma_tx_status(struct dma_chan *chan,
                                            dma_cookie_t cookie,
                                            struct dma_tx_state *state)
 {
-       struct ep93xx_dma_chan *edmac = to_ep93xx_dma_chan(chan);
-       enum dma_status ret;
-       unsigned long flags;
-
-       spin_lock_irqsave(&edmac->lock, flags);
-       ret = dma_cookie_status(chan, cookie, state);
-       spin_unlock_irqrestore(&edmac->lock, flags);
-
-       return ret;
+       return dma_cookie_status(chan, cookie, state);
 }
 
 /**
index 49e8fbdb898388703ac5db7e306e4c5f39d88a19..b3f3e90054f2ab956e8019dd8abe539b85fa0301 100644 (file)
@@ -979,15 +979,7 @@ static enum dma_status fsl_tx_status(struct dma_chan *dchan,
                                        dma_cookie_t cookie,
                                        struct dma_tx_state *txstate)
 {
-       struct fsldma_chan *chan = to_fsl_chan(dchan);
-       enum dma_status ret;
-       unsigned long flags;
-
-       spin_lock_irqsave(&chan->desc_lock, flags);
-       ret = dma_cookie_status(dchan, cookie, txstate);
-       spin_unlock_irqrestore(&chan->desc_lock, flags);
-
-       return ret;
+       return dma_cookie_status(dchan, cookie, txstate);
 }
 
 /*----------------------------------------------------------------------------*/
index 1e44b8cf95dabca6b220c05e8afd33740f8a8455..f45e0928852b9dda3d3092ceebc420299320f3b9 100644 (file)
@@ -1120,15 +1120,12 @@ static int sdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
 }
 
 static enum dma_status sdma_tx_status(struct dma_chan *chan,
-                                           dma_cookie_t cookie,
-                                           struct dma_tx_state *txstate)
+                                     dma_cookie_t cookie,
+                                     struct dma_tx_state *txstate)
 {
        struct sdma_channel *sdmac = to_sdma_chan(chan);
-       dma_cookie_t last_used;
 
-       last_used = chan->cookie;
-
-       dma_set_tx_state(txstate, chan->completed_cookie, last_used,
+       dma_set_tx_state(txstate, chan->completed_cookie, chan->cookie,
                        sdmac->chn_count - sdmac->chn_real_count);
 
        return sdmac->status;
index d39c2cd0795d71437935d22ce90ca636c8fae0aa..608d4a26165487b2da23c1ddbf9148d04ea7dbac 100644 (file)
@@ -1593,10 +1593,7 @@ static void idmac_free_chan_resources(struct dma_chan *chan)
 static enum dma_status idmac_tx_status(struct dma_chan *chan,
                       dma_cookie_t cookie, struct dma_tx_state *txstate)
 {
-       dma_set_tx_state(txstate, chan->completed_cookie, chan->cookie, 0);
-       if (cookie != chan->cookie)
-               return DMA_ERROR;
-       return DMA_SUCCESS;
+       return dma_cookie_status(chan, cookie, txstate);
 }
 
 static int __init ipu_idmac_init(struct ipu *ipu)
index c26699f9c4dfdbcec1c3f0d6ee0cf3d173227294..ad4b0a7167f6cae01e26b268218eb16b8dd2ac11 100644 (file)
@@ -632,15 +632,7 @@ static int mmp_pdma_control(struct dma_chan *dchan, enum dma_ctrl_cmd cmd,
 static enum dma_status mmp_pdma_tx_status(struct dma_chan *dchan,
                        dma_cookie_t cookie, struct dma_tx_state *txstate)
 {
-       struct mmp_pdma_chan *chan = to_mmp_pdma_chan(dchan);
-       enum dma_status ret;
-       unsigned long flags;
-
-       spin_lock_irqsave(&chan->desc_lock, flags);
-       ret = dma_cookie_status(dchan, cookie, txstate);
-       spin_unlock_irqrestore(&chan->desc_lock, flags);
-
-       return ret;
+       return dma_cookie_status(dchan, cookie, txstate);
 }
 
 /**
index 9b9366537d73e87c2e6a81113eaa3f0025ae6330..a9345d0387d8fa478f72dbea65bfcfb717f1b191 100644 (file)
@@ -460,7 +460,8 @@ static enum dma_status mmp_tdma_tx_status(struct dma_chan *chan,
 {
        struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
 
-       dma_set_residue(txstate, tdmac->buf_len - tdmac->pos);
+       dma_set_tx_state(txstate, chan->completed_cookie, chan->cookie,
+                        tdmac->buf_len - tdmac->pos);
 
        return tdmac->status;
 }
index 2d956732aa3d262aa2c5e1c603ff530bab31db78..2fe4353773338234375df48855ec7c941798bb31 100644 (file)
@@ -556,15 +556,7 @@ static enum dma_status
 mpc_dma_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
               struct dma_tx_state *txstate)
 {
-       struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(chan);
-       enum dma_status ret;
-       unsigned long flags;
-
-       spin_lock_irqsave(&mchan->lock, flags);
-       ret = dma_cookie_status(chan, cookie, txstate);
-       spin_unlock_irqrestore(&mchan->lock, flags);
-
-       return ret;
+       return dma_cookie_status(chan, cookie, txstate);
 }
 
 /* Prepare descriptor for memory to memory copy */
index 719593002ab7866051aa9cf7c52633ce60000ba6..6fb4b7bc448ff019ccb23c6688b37b7d09223e51 100644 (file)
@@ -622,10 +622,8 @@ static enum dma_status mxs_dma_tx_status(struct dma_chan *chan,
                        dma_cookie_t cookie, struct dma_tx_state *txstate)
 {
        struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
-       dma_cookie_t last_used;
 
-       last_used = chan->cookie;
-       dma_set_tx_state(txstate, chan->completed_cookie, last_used, 0);
+       dma_set_tx_state(txstate, chan->completed_cookie, chan->cookie, 0);
 
        return mxs_chan->status;
 }
index ce3dc3e9688c86ea30e3be7757094b78749a6ec9..956314de7c44f4fe44cffeec1ab60a35d76f43ea 100644 (file)
@@ -564,14 +564,7 @@ static void pd_free_chan_resources(struct dma_chan *chan)
 static enum dma_status pd_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
                                    struct dma_tx_state *txstate)
 {
-       struct pch_dma_chan *pd_chan = to_pd_chan(chan);
-       enum dma_status ret;
-
-       spin_lock_irq(&pd_chan->lock);
-       ret = dma_cookie_status(chan, cookie, txstate);
-       spin_unlock_irq(&pd_chan->lock);
-
-       return ret;
+       return dma_cookie_status(chan, cookie, txstate);
 }
 
 static void pd_issue_pending(struct dma_chan *chan)
@@ -867,6 +860,7 @@ static int pch_dma_probe(struct pci_dev *pdev,
 
        if (!(pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) {
                dev_err(&pdev->dev, "Cannot find proper base address\n");
+               err = -ENODEV;
                goto err_disable_pdev;
        }
 
index 593827b3fdd4fd8556724da998934a7c191b8d49..4ad13eb8b66149cc3b7aeb0cffbcbb8a406a0e37 100644 (file)
@@ -2505,6 +2505,10 @@ static dma_cookie_t pl330_tx_submit(struct dma_async_tx_descriptor *tx)
        /* Assign cookies to all nodes */
        while (!list_empty(&last->node)) {
                desc = list_entry(last->node.next, struct dma_pl330_desc, node);
+               if (pch->cyclic) {
+                       desc->txd.callback = last->txd.callback;
+                       desc->txd.callback_param = last->txd.callback_param;
+               }
 
                dma_cookie_assign(&desc->txd);
 
@@ -2688,45 +2692,82 @@ static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic(
                size_t period_len, enum dma_transfer_direction direction,
                unsigned long flags, void *context)
 {
-       struct dma_pl330_desc *desc;
+       struct dma_pl330_desc *desc = NULL, *first = NULL;
        struct dma_pl330_chan *pch = to_pchan(chan);
+       struct dma_pl330_dmac *pdmac = pch->dmac;
+       unsigned int i;
        dma_addr_t dst;
        dma_addr_t src;
 
-       desc = pl330_get_desc(pch);
-       if (!desc) {
-               dev_err(pch->dmac->pif.dev, "%s:%d Unable to fetch desc\n",
-                       __func__, __LINE__);
+       if (len % period_len != 0)
                return NULL;
-       }
 
-       switch (direction) {
-       case DMA_MEM_TO_DEV:
-               desc->rqcfg.src_inc = 1;
-               desc->rqcfg.dst_inc = 0;
-               desc->req.rqtype = MEMTODEV;
-               src = dma_addr;
-               dst = pch->fifo_addr;
-               break;
-       case DMA_DEV_TO_MEM:
-               desc->rqcfg.src_inc = 0;
-               desc->rqcfg.dst_inc = 1;
-               desc->req.rqtype = DEVTOMEM;
-               src = pch->fifo_addr;
-               dst = dma_addr;
-               break;
-       default:
+       if (!is_slave_direction(direction)) {
                dev_err(pch->dmac->pif.dev, "%s:%d Invalid dma direction\n",
                __func__, __LINE__);
                return NULL;
        }
 
-       desc->rqcfg.brst_size = pch->burst_sz;
-       desc->rqcfg.brst_len = 1;
+       for (i = 0; i < len / period_len; i++) {
+               desc = pl330_get_desc(pch);
+               if (!desc) {
+                       dev_err(pch->dmac->pif.dev, "%s:%d Unable to fetch desc\n",
+                               __func__, __LINE__);
+
+                       if (!first)
+                               return NULL;
 
-       pch->cyclic = true;
+                       spin_lock_irqsave(&pdmac->pool_lock, flags);
+
+                       while (!list_empty(&first->node)) {
+                               desc = list_entry(first->node.next,
+                                               struct dma_pl330_desc, node);
+                               list_move_tail(&desc->node, &pdmac->desc_pool);
+                       }
+
+                       list_move_tail(&first->node, &pdmac->desc_pool);
+
+                       spin_unlock_irqrestore(&pdmac->pool_lock, flags);
+
+                       return NULL;
+               }
+
+               switch (direction) {
+               case DMA_MEM_TO_DEV:
+                       desc->rqcfg.src_inc = 1;
+                       desc->rqcfg.dst_inc = 0;
+                       desc->req.rqtype = MEMTODEV;
+                       src = dma_addr;
+                       dst = pch->fifo_addr;
+                       break;
+               case DMA_DEV_TO_MEM:
+                       desc->rqcfg.src_inc = 0;
+                       desc->rqcfg.dst_inc = 1;
+                       desc->req.rqtype = DEVTOMEM;
+                       src = pch->fifo_addr;
+                       dst = dma_addr;
+                       break;
+               default:
+                       break;
+               }
 
-       fill_px(&desc->px, dst, src, period_len);
+               desc->rqcfg.brst_size = pch->burst_sz;
+               desc->rqcfg.brst_len = 1;
+               fill_px(&desc->px, dst, src, period_len);
+
+               if (!first)
+                       first = desc;
+               else
+                       list_add_tail(&desc->node, &first->node);
+
+               dma_addr += period_len;
+       }
+
+       if (!desc)
+               return NULL;
+
+       pch->cyclic = true;
+       desc->txd.flags = flags;
 
        return &desc->txd;
 }
@@ -2855,6 +2896,32 @@ static irqreturn_t pl330_irq_handler(int irq, void *data)
                return IRQ_NONE;
 }
 
+#define PL330_DMA_BUSWIDTHS \
+       BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) | \
+       BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
+       BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
+       BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \
+       BIT(DMA_SLAVE_BUSWIDTH_8_BYTES)
+
+static int pl330_dma_device_slave_caps(struct dma_chan *dchan,
+       struct dma_slave_caps *caps)
+{
+       caps->src_addr_widths = PL330_DMA_BUSWIDTHS;
+       caps->dstn_addr_widths = PL330_DMA_BUSWIDTHS;
+       caps->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+       caps->cmd_pause = false;
+       caps->cmd_terminate = true;
+
+       /*
+        * This is the limit for transfers with a buswidth of 1, larger
+        * buswidths will have larger limits.
+        */
+       caps->max_sg_len = 1900800;
+       caps->max_sg_nr = 0;
+
+       return 0;
+}
+
 static int
 pl330_probe(struct amba_device *adev, const struct amba_id *id)
 {
@@ -2959,6 +3026,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
        pd->device_prep_slave_sg = pl330_prep_slave_sg;
        pd->device_control = pl330_control;
        pd->device_issue_pending = pl330_issue_pending;
+       pd->device_slave_caps = pl330_dma_device_slave_caps;
 
        ret = dma_async_device_register(pd);
        if (ret) {
index f137914d7b1650d285ee2c294ae941c12ac124fc..5d4986e5f5fa6b21423084b688bd0a8afbba0c2e 100644 (file)
@@ -767,13 +767,11 @@ static enum dma_status tegra_dma_tx_status(struct dma_chan *dc,
        unsigned long flags;
        unsigned int residual;
 
-       spin_lock_irqsave(&tdc->lock, flags);
-
        ret = dma_cookie_status(dc, cookie, txstate);
-       if (ret == DMA_SUCCESS) {
-               spin_unlock_irqrestore(&tdc->lock, flags);
+       if (ret == DMA_SUCCESS)
                return ret;
-       }
+
+       spin_lock_irqsave(&tdc->lock, flags);
 
        /* Check on wait_ack desc status */
        list_for_each_entry(dma_desc, &tdc->free_dma_desc, node) {
index a59fb4841d4c18283eae911c076c43dc042f0748..59357db62359a96c298e4743ed27d00e74849d9c 100644 (file)
@@ -962,15 +962,14 @@ txx9dmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
        enum dma_status ret;
 
        ret = dma_cookie_status(chan, cookie, txstate);
-       if (ret != DMA_SUCCESS) {
-               spin_lock_bh(&dc->lock);
-               txx9dmac_scan_descriptors(dc);
-               spin_unlock_bh(&dc->lock);
+       if (ret == DMA_SUCCESS)
+               return DMA_SUCCESS;
 
-               ret = dma_cookie_status(chan, cookie, txstate);
-       }
+       spin_lock_bh(&dc->lock);
+       txx9dmac_scan_descriptors(dc);
+       spin_unlock_bh(&dc->lock);
 
-       return ret;
+       return dma_cookie_status(chan, cookie, txstate);
 }
 
 static void txx9dmac_chain_dynamic(struct txx9dmac_chan *dc,
index a0820536b7d9d8edf0905ed04bf913d6fb6f21db..578f915ee195576260266126fd1ff4bba00858f8 100644 (file)
@@ -257,7 +257,6 @@ static void __exit tile_edac_exit(void)
                if (!pdev)
                        continue;
 
-               platform_set_drvdata(pdev, NULL);
                platform_device_unregister(pdev);
        }
        platform_driver_unregister(&tile_edac_mc_driver);
index 7ef316fdc4d964cc8d1f87bd7be0cb9995223612..d7d5c8af92b9754fa79aa632c69d9ffc1fb27420 100644 (file)
@@ -54,6 +54,7 @@
 #define FW_CDEV_KERNEL_VERSION                 5
 #define FW_CDEV_VERSION_EVENT_REQUEST2         4
 #define FW_CDEV_VERSION_ALLOCATE_REGION_END    4
+#define FW_CDEV_VERSION_AUTO_FLUSH_ISO_OVERFLOW        5
 
 struct client {
        u32 version;
@@ -485,7 +486,7 @@ static int ioctl_get_info(struct client *client, union ioctl_arg *arg)
 static int add_client_resource(struct client *client,
                               struct client_resource *resource, gfp_t gfp_mask)
 {
-       bool preload = gfp_mask & __GFP_WAIT;
+       bool preload = !!(gfp_mask & __GFP_WAIT);
        unsigned long flags;
        int ret;
 
@@ -1005,6 +1006,8 @@ static int ioctl_create_iso_context(struct client *client, union ioctl_arg *arg)
                        a->channel, a->speed, a->header_size, cb, client);
        if (IS_ERR(context))
                return PTR_ERR(context);
+       if (client->version < FW_CDEV_VERSION_AUTO_FLUSH_ISO_OVERFLOW)
+               context->drop_overflow_headers = true;
 
        /* We only support one context at this time. */
        spin_lock_irq(&client->lock);
index 28a94c7ec6e5bad3af57ed258e0615266ab7b135..e5af0e3a26ec9345a9a775e77ab76b78db94ba25 100644 (file)
@@ -1262,8 +1262,7 @@ static int __init fw_core_init(void)
 {
        int ret;
 
-       fw_workqueue = alloc_workqueue("firewire",
-                                      WQ_NON_REENTRANT | WQ_MEM_RECLAIM, 0);
+       fw_workqueue = alloc_workqueue("firewire", WQ_MEM_RECLAIM, 0);
        if (!fw_workqueue)
                return -ENOMEM;
 
index 9e1db6490b9a3bb497b7911d94c42d9fc6190be7..afb701ec90cabd50ceb03b1298beba38e97717b4 100644 (file)
@@ -2749,8 +2749,11 @@ static void copy_iso_headers(struct iso_context *ctx, const u32 *dma_hdr)
 {
        u32 *ctx_hdr;
 
-       if (ctx->header_length + ctx->base.header_size > PAGE_SIZE)
+       if (ctx->header_length + ctx->base.header_size > PAGE_SIZE) {
+               if (ctx->base.drop_overflow_headers)
+                       return;
                flush_iso_completions(ctx);
+       }
 
        ctx_hdr = ctx->header + ctx->header_length;
        ctx->last_timestamp = (u16)le32_to_cpu((__force __le32)dma_hdr[0]);
@@ -2910,8 +2913,11 @@ static int handle_it_packet(struct context *context,
 
        sync_it_packet_for_cpu(context, d);
 
-       if (ctx->header_length + 4 > PAGE_SIZE)
+       if (ctx->header_length + 4 > PAGE_SIZE) {
+               if (ctx->base.drop_overflow_headers)
+                       return 1;
                flush_iso_completions(ctx);
+       }
 
        ctx_hdr = ctx->header + ctx->header_length;
        ctx->last_timestamp = le16_to_cpu(last->res_count);
index eb760a218da4292f7c208ddc145deffb833df7ab..232fa8fce26a5d0ffddf5fdc3ee01ed3c63eed7f 100644 (file)
@@ -419,6 +419,13 @@ static void __init dmi_format_ids(char *buf, size_t len)
                            dmi_get_system_info(DMI_BIOS_DATE));
 }
 
+/*
+ * Check for DMI/SMBIOS headers in the system firmware image.  Any
+ * SMBIOS header must start 16 bytes before the DMI header, so take a
+ * 32 byte buffer and check for DMI at offset 16 and SMBIOS at offset
+ * 0.  If the DMI header is present, set dmi_ver accordingly (SMBIOS
+ * takes precedence) and return 0.  Otherwise return 1.
+ */
 static int __init dmi_present(const u8 *buf)
 {
        int smbios_ver;
@@ -506,6 +513,13 @@ void __init dmi_scan_machine(void)
                if (p == NULL)
                        goto error;
 
+               /*
+                * Iterate over all possible DMI header addresses q.
+                * Maintain the 32 bytes around q in buf.  On the
+                * first iteration, substitute zero for the
+                * out-of-range bytes so there is no chance of falsely
+                * detecting an SMBIOS header.
+                */
                memset(buf, 0, 16);
                for (q = p; q < p + 0x10000; q += 16) {
                        memcpy_fromio(buf + 16, q, 16);
index 801bcafa3028b8a04c2b7db7fce10e55c917ea30..d943b94afc90da8cefe4600c3e264fb4b92bb298 100644 (file)
@@ -13,7 +13,7 @@ drm-y       :=        drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \
                drm_crtc.o drm_modes.o drm_edid.o \
                drm_info.o drm_debugfs.o drm_encoder_slave.o \
                drm_trace_points.o drm_global.o drm_prime.o \
-               drm_rect.o
+               drm_rect.o drm_vma_manager.o
 
 drm-$(CONFIG_COMPAT) += drm_ioc32.o
 drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
index f60fd7bd11839f0511bf2a436f1ebc79330f27c4..c195dc2abc09ada4af8e9aaef5d55eb60e300343 100644 (file)
@@ -487,7 +487,7 @@ void ast_gem_free_object(struct drm_gem_object *obj)
 
 static inline u64 ast_bo_mmap_offset(struct ast_bo *bo)
 {
-       return bo->bo.addr_space_offset;
+       return drm_vma_node_offset_addr(&bo->bo.vma_node);
 }
 int
 ast_dumb_mmap_offset(struct drm_file *file,
index 35cbae8277715ad2944a00dcce1c39e4482109b6..3a7a0efe367514b35003765520388d37246b3919 100644 (file)
@@ -294,7 +294,7 @@ void cirrus_gem_free_object(struct drm_gem_object *obj)
 
 static inline u64 cirrus_bo_mmap_offset(struct cirrus_bo *bo)
 {
-       return bo->bo.addr_space_offset;
+       return drm_vma_node_offset_addr(&bo->bo.vma_node);
 }
 
 int
index 5a4dbb410b71591f6f7b61a7d89f6f7609438578..bef4abff8fa3fe04c9f14a22d668507833a2c1f4 100644 (file)
@@ -243,7 +243,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,
                }
                map->handle = vmalloc_user(map->size);
                DRM_DEBUG("%lu %d %p\n",
-                         map->size, drm_order(map->size), map->handle);
+                         map->size, order_base_2(map->size), map->handle);
                if (!map->handle) {
                        kfree(map);
                        return -ENOMEM;
@@ -630,7 +630,7 @@ int drm_addbufs_agp(struct drm_device * dev, struct drm_buf_desc * request)
                return -EINVAL;
 
        count = request->count;
-       order = drm_order(request->size);
+       order = order_base_2(request->size);
        size = 1 << order;
 
        alignment = (request->flags & _DRM_PAGE_ALIGN)
@@ -800,7 +800,7 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request)
                return -EPERM;
 
        count = request->count;
-       order = drm_order(request->size);
+       order = order_base_2(request->size);
        size = 1 << order;
 
        DRM_DEBUG("count=%d, size=%d (%d), order=%d\n",
@@ -1002,7 +1002,7 @@ static int drm_addbufs_sg(struct drm_device * dev, struct drm_buf_desc * request
                return -EPERM;
 
        count = request->count;
-       order = drm_order(request->size);
+       order = order_base_2(request->size);
        size = 1 << order;
 
        alignment = (request->flags & _DRM_PAGE_ALIGN)
@@ -1157,7 +1157,7 @@ static int drm_addbufs_fb(struct drm_device * dev, struct drm_buf_desc * request
                return -EPERM;
 
        count = request->count;
-       order = drm_order(request->size);
+       order = order_base_2(request->size);
        size = 1 << order;
 
        alignment = (request->flags & _DRM_PAGE_ALIGN)
@@ -1435,7 +1435,7 @@ int drm_markbufs(struct drm_device *dev, void *data,
 
        DRM_DEBUG("%d, %d, %d\n",
                  request->size, request->low_mark, request->high_mark);
-       order = drm_order(request->size);
+       order = order_base_2(request->size);
        if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER)
                return -EINVAL;
        entry = &dma->bufs[order];
@@ -1600,25 +1600,16 @@ int drm_mapbufs(struct drm_device *dev, void *data,
        return retcode;
 }
 
-/**
- * Compute size order.  Returns the exponent of the smaller power of two which
- * is greater or equal to given number.
- *
- * \param size size.
- * \return order.
- *
- * \todo Can be made faster.
- */
-int drm_order(unsigned long size)
+struct drm_local_map *drm_getsarea(struct drm_device *dev)
 {
-       int order;
-       unsigned long tmp;
-
-       for (order = 0, tmp = size >> 1; tmp; tmp >>= 1, order++) ;
-
-       if (size & (size - 1))
-               ++order;
+       struct drm_map_list *entry;
 
-       return order;
+       list_for_each_entry(entry, &dev->maplist, head) {
+               if (entry->map && entry->map->type == _DRM_SHM &&
+                   (entry->map->flags & _DRM_CONTAINS_LOCK)) {
+                       return entry->map;
+               }
+       }
+       return NULL;
 }
-EXPORT_SYMBOL(drm_order);
+EXPORT_SYMBOL(drm_getsarea);
index 725968d38976839a962a483eb0ca4477f1d55e7c..224ff965bcf7de624c3b62b6db153bda090ea4a9 100644 (file)
@@ -251,7 +251,6 @@ static int drm_context_switch_complete(struct drm_device *dev,
                                       struct drm_file *file_priv, int new)
 {
        dev->last_context = new;        /* PRE/POST: This is the _only_ writer. */
-       dev->last_switch = jiffies;
 
        if (!_DRM_LOCK_IS_HELD(file_priv->master->lock.hw_lock->lock)) {
                DRM_ERROR("Lock isn't held after context switch\n");
@@ -261,7 +260,6 @@ static int drm_context_switch_complete(struct drm_device *dev,
           when the kernel holds the lock, release
           that lock here. */
        clear_bit(0, &dev->context_flag);
-       wake_up(&dev->context_wait);
 
        return 0;
 }
@@ -342,12 +340,6 @@ int drm_addctx(struct drm_device *dev, void *data,
        return 0;
 }
 
-int drm_modctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
-       /* This does nothing */
-       return 0;
-}
-
 /**
  * Get context.
  *
index 99fcd7c32ea2dea50c652576646446a1fd5cab37..36103d1660d1bb1e467838ab05629b16ece48e18 100644 (file)
@@ -87,7 +87,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
 
        DRM_IOCTL_DEF(DRM_IOCTL_ADD_CTX, drm_addctx, DRM_AUTH|DRM_ROOT_ONLY),
        DRM_IOCTL_DEF(DRM_IOCTL_RM_CTX, drm_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-       DRM_IOCTL_DEF(DRM_IOCTL_MOD_CTX, drm_modctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_MOD_CTX, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
        DRM_IOCTL_DEF(DRM_IOCTL_GET_CTX, drm_getctx, DRM_AUTH),
        DRM_IOCTL_DEF(DRM_IOCTL_SWITCH_CTX, drm_switchctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
        DRM_IOCTL_DEF(DRM_IOCTL_NEW_CTX, drm_newctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
@@ -122,7 +122,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
        DRM_IOCTL_DEF(DRM_IOCTL_AGP_UNBIND, drm_agp_unbind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
 #endif
 
-       DRM_IOCTL_DEF(DRM_IOCTL_SG_ALLOC, drm_sg_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_SG_ALLOC, drm_sg_alloc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
        DRM_IOCTL_DEF(DRM_IOCTL_SG_FREE, drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
 
        DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, DRM_UNLOCKED),
@@ -485,19 +485,4 @@ long drm_ioctl(struct file *filp,
                DRM_DEBUG("ret = %d\n", retcode);
        return retcode;
 }
-
 EXPORT_SYMBOL(drm_ioctl);
-
-struct drm_local_map *drm_getsarea(struct drm_device *dev)
-{
-       struct drm_map_list *entry;
-
-       list_for_each_entry(entry, &dev->maplist, head) {
-               if (entry->map && entry->map->type == _DRM_SHM &&
-                   (entry->map->flags & _DRM_CONTAINS_LOCK)) {
-                       return entry->map;
-               }
-       }
-       return NULL;
-}
-EXPORT_SYMBOL(drm_getsarea);
index 3a24385e03686faebb4fa413809136bce9d60917..72acae908a7dfc9e9d96843431433af0f03788b6 100644 (file)
@@ -76,20 +76,10 @@ static int drm_setup(struct drm_device * dev)
        dev->sigdata.lock = NULL;
 
        dev->context_flag = 0;
-       dev->interrupt_flag = 0;
-       dev->dma_flag = 0;
        dev->last_context = 0;
-       dev->last_switch = 0;
-       dev->last_checked = 0;
-       init_waitqueue_head(&dev->context_wait);
        dev->if_version = 0;
 
-       dev->ctx_start = 0;
-       dev->lck_start = 0;
-
        dev->buf_async = NULL;
-       init_waitqueue_head(&dev->buf_readers);
-       init_waitqueue_head(&dev->buf_writers);
 
        DRM_DEBUG("\n");
 
index 603f256152efed25852072a49f32b11c7ddf16cd..1f7657286f04a9eb9bc884165bcae90de67718f9 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/shmem_fs.h>
 #include <linux/dma-buf.h>
 #include <drm/drmP.h>
+#include <drm/drm_vma_manager.h>
 
 /** @file drm_gem.c
  *
@@ -102,14 +103,9 @@ drm_gem_init(struct drm_device *dev)
        }
 
        dev->mm_private = mm;
-
-       if (drm_ht_create(&mm->offset_hash, 12)) {
-               kfree(mm);
-               return -ENOMEM;
-       }
-
-       drm_mm_init(&mm->offset_manager, DRM_FILE_PAGE_OFFSET_START,
-                   DRM_FILE_PAGE_OFFSET_SIZE);
+       drm_vma_offset_manager_init(&mm->vma_manager,
+                                   DRM_FILE_PAGE_OFFSET_START,
+                                   DRM_FILE_PAGE_OFFSET_SIZE);
 
        return 0;
 }
@@ -119,8 +115,7 @@ drm_gem_destroy(struct drm_device *dev)
 {
        struct drm_gem_mm *mm = dev->mm_private;
 
-       drm_mm_takedown(&mm->offset_manager);
-       drm_ht_remove(&mm->offset_hash);
+       drm_vma_offset_manager_destroy(&mm->vma_manager);
        kfree(mm);
        dev->mm_private = NULL;
 }
@@ -132,16 +127,14 @@ drm_gem_destroy(struct drm_device *dev)
 int drm_gem_object_init(struct drm_device *dev,
                        struct drm_gem_object *obj, size_t size)
 {
-       BUG_ON((size & (PAGE_SIZE - 1)) != 0);
+       struct file *filp;
 
-       obj->dev = dev;
-       obj->filp = shmem_file_setup("drm mm object", size, VM_NORESERVE);
-       if (IS_ERR(obj->filp))
-               return PTR_ERR(obj->filp);
+       filp = shmem_file_setup("drm mm object", size, VM_NORESERVE);
+       if (IS_ERR(filp))
+               return PTR_ERR(filp);
 
-       kref_init(&obj->refcount);
-       atomic_set(&obj->handle_count, 0);
-       obj->size = size;
+       drm_gem_private_object_init(dev, obj, size);
+       obj->filp = filp;
 
        return 0;
 }
@@ -152,8 +145,8 @@ EXPORT_SYMBOL(drm_gem_object_init);
  * no GEM provided backing store. Instead the caller is responsible for
  * backing the object and handling it.
  */
-int drm_gem_private_object_init(struct drm_device *dev,
-                       struct drm_gem_object *obj, size_t size)
+void drm_gem_private_object_init(struct drm_device *dev,
+                                struct drm_gem_object *obj, size_t size)
 {
        BUG_ON((size & (PAGE_SIZE - 1)) != 0);
 
@@ -163,8 +156,6 @@ int drm_gem_private_object_init(struct drm_device *dev,
        kref_init(&obj->refcount);
        atomic_set(&obj->handle_count, 0);
        obj->size = size;
-
-       return 0;
 }
 EXPORT_SYMBOL(drm_gem_private_object_init);
 
@@ -306,12 +297,8 @@ drm_gem_free_mmap_offset(struct drm_gem_object *obj)
 {
        struct drm_device *dev = obj->dev;
        struct drm_gem_mm *mm = dev->mm_private;
-       struct drm_map_list *list = &obj->map_list;
 
-       drm_ht_remove_item(&mm->offset_hash, &list->hash);
-       drm_mm_put_block(list->file_offset_node);
-       kfree(list->map);
-       list->map = NULL;
+       drm_vma_offset_remove(&mm->vma_manager, &obj->vma_node);
 }
 EXPORT_SYMBOL(drm_gem_free_mmap_offset);
 
@@ -331,54 +318,9 @@ drm_gem_create_mmap_offset(struct drm_gem_object *obj)
 {
        struct drm_device *dev = obj->dev;
        struct drm_gem_mm *mm = dev->mm_private;
-       struct drm_map_list *list;
-       struct drm_local_map *map;
-       int ret;
-
-       /* Set the object up for mmap'ing */
-       list = &obj->map_list;
-       list->map = kzalloc(sizeof(struct drm_map_list), GFP_KERNEL);
-       if (!list->map)
-               return -ENOMEM;
 
-       map = list->map;
-       map->type = _DRM_GEM;
-       map->size = obj->size;
-       map->handle = obj;
-
-       /* Get a DRM GEM mmap offset allocated... */
-       list->file_offset_node = drm_mm_search_free(&mm->offset_manager,
-                       obj->size / PAGE_SIZE, 0, false);
-
-       if (!list->file_offset_node) {
-               DRM_ERROR("failed to allocate offset for bo %d\n", obj->name);
-               ret = -ENOSPC;
-               goto out_free_list;
-       }
-
-       list->file_offset_node = drm_mm_get_block(list->file_offset_node,
-                       obj->size / PAGE_SIZE, 0);
-       if (!list->file_offset_node) {
-               ret = -ENOMEM;
-               goto out_free_list;
-       }
-
-       list->hash.key = list->file_offset_node->start;
-       ret = drm_ht_insert_item(&mm->offset_hash, &list->hash);
-       if (ret) {
-               DRM_ERROR("failed to add to map hash\n");
-               goto out_free_mm;
-       }
-
-       return 0;
-
-out_free_mm:
-       drm_mm_put_block(list->file_offset_node);
-out_free_list:
-       kfree(list->map);
-       list->map = NULL;
-
-       return ret;
+       return drm_vma_offset_add(&mm->vma_manager, &obj->vma_node,
+                                 obj->size / PAGE_SIZE);
 }
 EXPORT_SYMBOL(drm_gem_create_mmap_offset);
 
@@ -707,8 +649,8 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
        struct drm_file *priv = filp->private_data;
        struct drm_device *dev = priv->minor->dev;
        struct drm_gem_mm *mm = dev->mm_private;
-       struct drm_local_map *map = NULL;
-       struct drm_hash_item *hash;
+       struct drm_gem_object *obj;
+       struct drm_vma_offset_node *node;
        int ret = 0;
 
        if (drm_device_is_unplugged(dev))
@@ -716,21 +658,16 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
 
        mutex_lock(&dev->struct_mutex);
 
-       if (drm_ht_find_item(&mm->offset_hash, vma->vm_pgoff, &hash)) {
+       node = drm_vma_offset_exact_lookup(&mm->vma_manager, vma->vm_pgoff,
+                                          vma_pages(vma));
+       if (!node) {
                mutex_unlock(&dev->struct_mutex);
                return drm_mmap(filp, vma);
        }
 
-       map = drm_hash_entry(hash, struct drm_map_list, hash)->map;
-       if (!map ||
-           ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) {
-               ret =  -EPERM;
-               goto out_unlock;
-       }
-
-       ret = drm_gem_mmap_obj(map->handle, map->size, vma);
+       obj = container_of(node, struct drm_gem_object, vma_node);
+       ret = drm_gem_mmap_obj(obj, drm_vma_node_size(node) << PAGE_SHIFT, vma);
 
-out_unlock:
        mutex_unlock(&dev->struct_mutex);
 
        return ret;
index ece72a8ac245ed6f3bc8587813f0e51cb1653821..847f091176663a197988629ebf3aec6910cd21f2 100644 (file)
 #include <drm/drmP.h>
 #include <drm/drm.h>
 #include <drm/drm_gem_cma_helper.h>
-
-static unsigned int get_gem_mmap_offset(struct drm_gem_object *obj)
-{
-       return (unsigned int)obj->map_list.hash.key << PAGE_SHIFT;
-}
+#include <drm/drm_vma_manager.h>
 
 /*
  * __drm_gem_cma_create - Create a GEM CMA object without allocating memory
@@ -172,8 +168,7 @@ void drm_gem_cma_free_object(struct drm_gem_object *gem_obj)
 {
        struct drm_gem_cma_object *cma_obj;
 
-       if (gem_obj->map_list.map)
-               drm_gem_free_mmap_offset(gem_obj);
+       drm_gem_free_mmap_offset(gem_obj);
 
        cma_obj = to_drm_gem_cma_obj(gem_obj);
 
@@ -237,7 +232,7 @@ int drm_gem_cma_dumb_map_offset(struct drm_file *file_priv,
                return -EINVAL;
        }
 
-       *offset = get_gem_mmap_offset(gem_obj);
+       *offset = drm_vma_node_offset_addr(&gem_obj->vma_node);
 
        drm_gem_object_unreference(gem_obj);
 
@@ -301,12 +296,11 @@ void drm_gem_cma_describe(struct drm_gem_cma_object *cma_obj, struct seq_file *m
 {
        struct drm_gem_object *obj = &cma_obj->base;
        struct drm_device *dev = obj->dev;
-       uint64_t off = 0;
+       uint64_t off;
 
        WARN_ON(!mutex_is_locked(&dev->struct_mutex));
 
-       if (obj->map_list.map)
-               off = (uint64_t)obj->map_list.hash.key;
+       off = drm_vma_node_start(&obj->vma_node);
 
        seq_printf(m, "%2d (%2d) %08llx %08Zx %p %d",
                        obj->name, obj->refcount.refcount.counter,
index 543b9b3171d32310de903668bc69f30901b12e91..fe304f903b130de19dbd4a11e6a75ea687a40ec4 100644 (file)
@@ -147,33 +147,27 @@ static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
        }
 }
 
-struct drm_mm_node *drm_mm_create_block(struct drm_mm *mm,
-                                       unsigned long start,
-                                       unsigned long size,
-                                       bool atomic)
+int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node)
 {
-       struct drm_mm_node *hole, *node;
-       unsigned long end = start + size;
+       struct drm_mm_node *hole;
+       unsigned long end = node->start + node->size;
        unsigned long hole_start;
        unsigned long hole_end;
 
+       BUG_ON(node == NULL);
+
+       /* Find the relevant hole to add our node to */
        drm_mm_for_each_hole(hole, mm, hole_start, hole_end) {
-               if (hole_start > start || hole_end < end)
+               if (hole_start > node->start || hole_end < end)
                        continue;
 
-               node = drm_mm_kmalloc(mm, atomic);
-               if (unlikely(node == NULL))
-                       return NULL;
-
-               node->start = start;
-               node->size = size;
                node->mm = mm;
                node->allocated = 1;
 
                INIT_LIST_HEAD(&node->hole_stack);
                list_add(&node->node_list, &hole->node_list);
 
-               if (start == hole_start) {
+               if (node->start == hole_start) {
                        hole->hole_follows = 0;
                        list_del_init(&hole->hole_stack);
                }
@@ -184,13 +178,14 @@ struct drm_mm_node *drm_mm_create_block(struct drm_mm *mm,
                        node->hole_follows = 1;
                }
 
-               return node;
+               return 0;
        }
 
-       WARN(1, "no hole found for block 0x%lx + 0x%lx\n", start, size);
-       return NULL;
+       WARN(1, "no hole found for node 0x%lx + 0x%lx\n",
+            node->start, node->size);
+       return -ENOSPC;
 }
-EXPORT_SYMBOL(drm_mm_create_block);
+EXPORT_SYMBOL(drm_mm_reserve_node);
 
 struct drm_mm_node *drm_mm_get_block_generic(struct drm_mm_node *hole_node,
                                             unsigned long size,
index 80c0b2b298017a0e1810c7db27cd97ca4bb87d6d..a7b46ff80b0fb7c64d89a7889728bea19825e271 100644 (file)
 drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, size_t align)
 {
        drm_dma_handle_t *dmah;
-#if 1
        unsigned long addr;
        size_t sz;
-#endif
 
        /* pci_alloc_consistent only guarantees alignment to the smallest
         * PAGE_SIZE order which is greater than or equal to the requested size.
@@ -97,10 +95,8 @@ EXPORT_SYMBOL(drm_pci_alloc);
  */
 void __drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah)
 {
-#if 1
        unsigned long addr;
        size_t sz;
-#endif
 
        if (dmah->vaddr) {
                /* XXX - Is virt_to_page() legal for consistent mem? */
index d87f60bbc3303139b9a27c052a3c939b22ed43f4..a4a076ff17573704a3b0ce75104f6f93e9cccf4d 100644 (file)
@@ -70,8 +70,10 @@ void drm_sg_cleanup(struct drm_sg_mem * entry)
 # define ScatterHandle(x) (unsigned int)(x)
 #endif
 
-int drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather * request)
+int drm_sg_alloc(struct drm_device *dev, void *data,
+                struct drm_file *file_priv)
 {
+       struct drm_scatter_gather *request = data;
        struct drm_sg_mem *entry;
        unsigned long pages, i, j;
 
@@ -181,15 +183,6 @@ int drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather * request)
        return -ENOMEM;
 }
 
-int drm_sg_alloc_ioctl(struct drm_device *dev, void *data,
-                      struct drm_file *file_priv)
-{
-       struct drm_scatter_gather *request = data;
-
-       return drm_sg_alloc(dev, request);
-
-}
-
 int drm_sg_free(struct drm_device *dev, void *data,
                struct drm_file *file_priv)
 {
diff --git a/drivers/gpu/drm/drm_vma_manager.c b/drivers/gpu/drm/drm_vma_manager.c
new file mode 100644 (file)
index 0000000..b966cea
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA
+ * Copyright (c) 2012 David Airlie <airlied@linux.ie>
+ * Copyright (c) 2013 David Herrmann <dh.herrmann@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice 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.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_mm.h>
+#include <drm/drm_vma_manager.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/rbtree.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+/**
+ * DOC: vma offset manager
+ *
+ * The vma-manager is responsible to map arbitrary driver-dependent memory
+ * regions into the linear user address-space. It provides offsets to the
+ * caller which can then be used on the address_space of the drm-device. It
+ * takes care to not overlap regions, size them appropriately and to not
+ * confuse mm-core by inconsistent fake vm_pgoff fields.
+ * Drivers shouldn't use this for object placement in VMEM. This manager should
+ * only be used to manage mappings into linear user-space VMs.
+ *
+ * We use drm_mm as backend to manage object allocations. But it is highly
+ * optimized for alloc/free calls, not lookups. Hence, we use an rb-tree to
+ * speed up offset lookups.
+ *
+ * You must not use multiple offset managers on a single address_space.
+ * Otherwise, mm-core will be unable to tear down memory mappings as the VM will
+ * no longer be linear. Please use VM_NONLINEAR in that case and implement your
+ * own offset managers.
+ *
+ * This offset manager works on page-based addresses. That is, every argument
+ * and return code (with the exception of drm_vma_node_offset_addr()) is given
+ * in number of pages, not number of bytes. That means, object sizes and offsets
+ * must always be page-aligned (as usual).
+ * If you want to get a valid byte-based user-space address for a given offset,
+ * please see drm_vma_node_offset_addr().
+ */
+
+/**
+ * drm_vma_offset_manager_init - Initialize new offset-manager
+ * @mgr: Manager object
+ * @page_offset: Offset of available memory area (page-based)
+ * @size: Size of available address space range (page-based)
+ *
+ * Initialize a new offset-manager. The offset and area size available for the
+ * manager are given as @page_offset and @size. Both are interpreted as
+ * page-numbers, not bytes.
+ *
+ * Adding/removing nodes from the manager is locked internally and protected
+ * against concurrent access. However, node allocation and destruction is left
+ * for the caller. While calling into the vma-manager, a given node must
+ * always be guaranteed to be referenced.
+ */
+void drm_vma_offset_manager_init(struct drm_vma_offset_manager *mgr,
+                                unsigned long page_offset, unsigned long size)
+{
+       rwlock_init(&mgr->vm_lock);
+       mgr->vm_addr_space_rb = RB_ROOT;
+       drm_mm_init(&mgr->vm_addr_space_mm, page_offset, size);
+}
+EXPORT_SYMBOL(drm_vma_offset_manager_init);
+
+/**
+ * drm_vma_offset_manager_destroy() - Destroy offset manager
+ * @mgr: Manager object
+ *
+ * Destroy an object manager which was previously created via
+ * drm_vma_offset_manager_init(). The caller must remove all allocated nodes
+ * before destroying the manager. Otherwise, drm_mm will refuse to free the
+ * requested resources.
+ *
+ * The manager must not be accessed after this function is called.
+ */
+void drm_vma_offset_manager_destroy(struct drm_vma_offset_manager *mgr)
+{
+       /* take the lock to protect against buggy drivers */
+       write_lock(&mgr->vm_lock);
+       drm_mm_takedown(&mgr->vm_addr_space_mm);
+       write_unlock(&mgr->vm_lock);
+}
+EXPORT_SYMBOL(drm_vma_offset_manager_destroy);
+
+/**
+ * drm_vma_offset_lookup() - Find node in offset space
+ * @mgr: Manager object
+ * @start: Start address for object (page-based)
+ * @pages: Size of object (page-based)
+ *
+ * Find a node given a start address and object size. This returns the _best_
+ * match for the given node. That is, @start may point somewhere into a valid
+ * region and the given node will be returned, as long as the node spans the
+ * whole requested area (given the size in number of pages as @pages).
+ *
+ * RETURNS:
+ * Returns NULL if no suitable node can be found. Otherwise, the best match
+ * is returned. It's the caller's responsibility to make sure the node doesn't
+ * get destroyed before the caller can access it.
+ */
+struct drm_vma_offset_node *drm_vma_offset_lookup(struct drm_vma_offset_manager *mgr,
+                                                 unsigned long start,
+                                                 unsigned long pages)
+{
+       struct drm_vma_offset_node *node;
+
+       read_lock(&mgr->vm_lock);
+       node = drm_vma_offset_lookup_locked(mgr, start, pages);
+       read_unlock(&mgr->vm_lock);
+
+       return node;
+}
+EXPORT_SYMBOL(drm_vma_offset_lookup);
+
+/**
+ * drm_vma_offset_lookup_locked() - Find node in offset space
+ * @mgr: Manager object
+ * @start: Start address for object (page-based)
+ * @pages: Size of object (page-based)
+ *
+ * Same as drm_vma_offset_lookup() but requires the caller to lock offset lookup
+ * manually. See drm_vma_offset_lock_lookup() for an example.
+ *
+ * RETURNS:
+ * Returns NULL if no suitable node can be found. Otherwise, the best match
+ * is returned.
+ */
+struct drm_vma_offset_node *drm_vma_offset_lookup_locked(struct drm_vma_offset_manager *mgr,
+                                                        unsigned long start,
+                                                        unsigned long pages)
+{
+       struct drm_vma_offset_node *node, *best;
+       struct rb_node *iter;
+       unsigned long offset;
+
+       iter = mgr->vm_addr_space_rb.rb_node;
+       best = NULL;
+
+       while (likely(iter)) {
+               node = rb_entry(iter, struct drm_vma_offset_node, vm_rb);
+               offset = node->vm_node.start;
+               if (start >= offset) {
+                       iter = iter->rb_right;
+                       best = node;
+                       if (start == offset)
+                               break;
+               } else {
+                       iter = iter->rb_left;
+               }
+       }
+
+       /* verify that the node spans the requested area */
+       if (best) {
+               offset = best->vm_node.start + best->vm_node.size;
+               if (offset < start + pages)
+                       best = NULL;
+       }
+
+       return best;
+}
+EXPORT_SYMBOL(drm_vma_offset_lookup_locked);
+
+/* internal helper to link @node into the rb-tree */
+static void _drm_vma_offset_add_rb(struct drm_vma_offset_manager *mgr,
+                                  struct drm_vma_offset_node *node)
+{
+       struct rb_node **iter = &mgr->vm_addr_space_rb.rb_node;
+       struct rb_node *parent = NULL;
+       struct drm_vma_offset_node *iter_node;
+
+       while (likely(*iter)) {
+               parent = *iter;
+               iter_node = rb_entry(*iter, struct drm_vma_offset_node, vm_rb);
+
+               if (node->vm_node.start < iter_node->vm_node.start)
+                       iter = &(*iter)->rb_left;
+               else if (node->vm_node.start > iter_node->vm_node.start)
+                       iter = &(*iter)->rb_right;
+               else
+                       BUG();
+       }
+
+       rb_link_node(&node->vm_rb, parent, iter);
+       rb_insert_color(&node->vm_rb, &mgr->vm_addr_space_rb);
+}
+
+/**
+ * drm_vma_offset_add() - Add offset node to manager
+ * @mgr: Manager object
+ * @node: Node to be added
+ * @pages: Allocation size visible to user-space (in number of pages)
+ *
+ * Add a node to the offset-manager. If the node was already added, this does
+ * nothing and return 0. @pages is the size of the object given in number of
+ * pages.
+ * After this call succeeds, you can access the offset of the node until it
+ * is removed again.
+ *
+ * If this call fails, it is safe to retry the operation or call
+ * drm_vma_offset_remove(), anyway. However, no cleanup is required in that
+ * case.
+ *
+ * @pages is not required to be the same size as the underlying memory object
+ * that you want to map. It only limits the size that user-space can map into
+ * their address space.
+ *
+ * RETURNS:
+ * 0 on success, negative error code on failure.
+ */
+int drm_vma_offset_add(struct drm_vma_offset_manager *mgr,
+                      struct drm_vma_offset_node *node, unsigned long pages)
+{
+       int ret;
+
+       write_lock(&mgr->vm_lock);
+
+       if (drm_mm_node_allocated(&node->vm_node)) {
+               ret = 0;
+               goto out_unlock;
+       }
+
+       ret = drm_mm_insert_node_generic(&mgr->vm_addr_space_mm,
+                                        &node->vm_node, pages, 0, 0);
+       if (ret)
+               goto out_unlock;
+
+       _drm_vma_offset_add_rb(mgr, node);
+
+out_unlock:
+       write_unlock(&mgr->vm_lock);
+       return ret;
+}
+EXPORT_SYMBOL(drm_vma_offset_add);
+
+/**
+ * drm_vma_offset_remove() - Remove offset node from manager
+ * @mgr: Manager object
+ * @node: Node to be removed
+ *
+ * Remove a node from the offset manager. If the node wasn't added before, this
+ * does nothing. After this call returns, the offset and size will be 0 until a
+ * new offset is allocated via drm_vma_offset_add() again. Helper functions like
+ * drm_vma_node_start() and drm_vma_node_offset_addr() will return 0 if no
+ * offset is allocated.
+ */
+void drm_vma_offset_remove(struct drm_vma_offset_manager *mgr,
+                          struct drm_vma_offset_node *node)
+{
+       write_lock(&mgr->vm_lock);
+
+       if (drm_mm_node_allocated(&node->vm_node)) {
+               rb_erase(&node->vm_rb, &mgr->vm_addr_space_rb);
+               drm_mm_remove_node(&node->vm_node);
+               memset(&node->vm_node, 0, sizeof(node->vm_node));
+       }
+
+       write_unlock(&mgr->vm_lock);
+}
+EXPORT_SYMBOL(drm_vma_offset_remove);
index 95c75edef01a0440303a36f2692ce963fe6a135e..30ef41bcd7b8fa5ed0554adf8bc3332cf19a1320 100644 (file)
@@ -15,7 +15,6 @@
 
 #include <linux/kernel.h>
 #include <linux/i2c.h>
-#include <linux/module.h>
 
 
 #include "exynos_drm_drv.h"
index 61b094f689a72c56666decd1b6b4361d12be6291..6e047bd53e2f00dd8f0d494194be7cda4f02ceda 100644 (file)
@@ -12,7 +12,6 @@
  *
  */
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/mfd/syscon.h>
 #include <linux/regmap.h>
index 3e106beca5b6c132f1dea2407652deac449fcc59..1c263dac3c1c8ddcbee197d13143a428ac4b01a2 100644 (file)
@@ -14,7 +14,6 @@
 #include <drm/drmP.h>
 
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/of_device.h>
@@ -130,7 +129,6 @@ static const struct of_device_id fimd_driver_dt_match[] = {
          .data = &exynos5_fimd_driver_data },
        {},
 };
-MODULE_DEVICE_TABLE(of, fimd_driver_dt_match);
 #endif
 
 static inline struct fimd_driver_data *drm_fimd_get_driver_data(
@@ -1082,7 +1080,6 @@ static struct platform_device_id fimd_driver_ids[] = {
        },
        {},
 };
-MODULE_DEVICE_TABLE(platform, fimd_driver_ids);
 
 static const struct dev_pm_ops fimd_pm_ops = {
        SET_SYSTEM_SLEEP_PM_OPS(fimd_suspend, fimd_resume)
index 42a5a5466075a7d2d25b8ab30fa6155383a0befa..eddea4941483228a68530513e4f04aa94cb0f84e 100644 (file)
@@ -8,7 +8,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/interrupt.h>
@@ -806,9 +805,20 @@ static void g2d_dma_start(struct g2d_data *g2d,
        struct g2d_cmdlist_node *node =
                                list_first_entry(&runqueue_node->run_cmdlist,
                                                struct g2d_cmdlist_node, list);
+       int ret;
+
+       ret = pm_runtime_get_sync(g2d->dev);
+       if (ret < 0) {
+               dev_warn(g2d->dev, "failed pm power on.\n");
+               return;
+       }
 
-       pm_runtime_get_sync(g2d->dev);
-       clk_enable(g2d->gate_clk);
+       ret = clk_prepare_enable(g2d->gate_clk);
+       if (ret < 0) {
+               dev_warn(g2d->dev, "failed to enable clock.\n");
+               pm_runtime_put_sync(g2d->dev);
+               return;
+       }
 
        writel_relaxed(node->dma_addr, g2d->regs + G2D_DMA_SFR_BASE_ADDR);
        writel_relaxed(G2D_DMA_START, g2d->regs + G2D_DMA_COMMAND);
@@ -861,7 +871,7 @@ static void g2d_runqueue_worker(struct work_struct *work)
                                            runqueue_work);
 
        mutex_lock(&g2d->runqueue_mutex);
-       clk_disable(g2d->gate_clk);
+       clk_disable_unprepare(g2d->gate_clk);
        pm_runtime_put_sync(g2d->dev);
 
        complete(&g2d->runqueue_node->complete);
@@ -1521,7 +1531,6 @@ static const struct of_device_id exynos_g2d_match[] = {
        { .compatible = "samsung,exynos5250-g2d" },
        {},
 };
-MODULE_DEVICE_TABLE(of, exynos_g2d_match);
 #endif
 
 struct platform_driver g2d_driver = {
index 24c22a8c3364787da406931aef1f34a607212f04..be32db1ab2906ce9a41cc414f89c5cb4f6253645 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <drm/drmP.h>
+#include <drm/drm_vma_manager.h>
 
 #include <linux/shmem_fs.h>
 #include <drm/exynos_drm.h>
@@ -152,8 +153,7 @@ out:
        exynos_drm_fini_buf(obj->dev, buf);
        exynos_gem_obj->buffer = NULL;
 
-       if (obj->map_list.map)
-               drm_gem_free_mmap_offset(obj);
+       drm_gem_free_mmap_offset(obj);
 
        /* release file pointer to gem object. */
        drm_gem_object_release(obj);
@@ -703,13 +703,11 @@ int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv,
                goto unlock;
        }
 
-       if (!obj->map_list.map) {
-               ret = drm_gem_create_mmap_offset(obj);
-               if (ret)
-                       goto out;
-       }
+       ret = drm_gem_create_mmap_offset(obj);
+       if (ret)
+               goto out;
 
-       *offset = (u64)obj->map_list.hash.key << PAGE_SHIFT;
+       *offset = drm_vma_node_offset_addr(&obj->vma_node);
        DRM_DEBUG_KMS("offset = 0x%lx\n", (unsigned long)*offset);
 
 out:
index 472e3b25e7f2cc6f5e05c1db002e5117bfca8685..90b8a1a5344cef0528b3bad82ab4b0b993002415 100644 (file)
@@ -12,7 +12,6 @@
  *
  */
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/pm_runtime.h>
index aaa550d622f03c047ca2ecf7c19fec8722f52747..8d3bc01d6834f7b8fca2c2320e67b151a4df3d0c 100644 (file)
@@ -15,7 +15,6 @@
 
 #include <linux/kernel.h>
 #include <linux/wait.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 
index b1ef8e7ff9c91fff7ecc11fc21cf25f7f20fbb3b..d2b6ab4def93ab7421d30fea9c9f86880a0b0e10 100644 (file)
@@ -12,7 +12,6 @@
  *
  */
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/types.h>
 #include <linux/clk.h>
@@ -342,10 +341,10 @@ int exynos_drm_ipp_get_property(struct drm_device *drm_dev, void *data,
                 */
                ippdrv = ipp_find_obj(&ctx->ipp_idr, &ctx->ipp_lock,
                                                prop_list->ipp_id);
-               if (!ippdrv) {
+               if (IS_ERR(ippdrv)) {
                        DRM_ERROR("not found ipp%d driver.\n",
                                        prop_list->ipp_id);
-                       return -EINVAL;
+                       return PTR_ERR(ippdrv);
                }
 
                prop_list = ippdrv->prop_list;
@@ -970,9 +969,9 @@ int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, void *data,
        /* find command node */
        c_node = ipp_find_obj(&ctx->prop_idr, &ctx->prop_lock,
                qbuf->prop_id);
-       if (!c_node) {
+       if (IS_ERR(c_node)) {
                DRM_ERROR("failed to get command node.\n");
-               return -EFAULT;
+               return PTR_ERR(c_node);
        }
 
        /* buffer control */
@@ -1106,9 +1105,9 @@ int exynos_drm_ipp_cmd_ctrl(struct drm_device *drm_dev, void *data,
 
        c_node = ipp_find_obj(&ctx->prop_idr, &ctx->prop_lock,
                cmd_ctrl->prop_id);
-       if (!c_node) {
+       if (IS_ERR(c_node)) {
                DRM_ERROR("invalid command node list.\n");
-               return -EINVAL;
+               return PTR_ERR(c_node);
        }
 
        if (!exynos_drm_ipp_check_valid(ippdrv->dev, cmd_ctrl->ctrl,
index 427640aa51481777976391fa51d856f7bbc7512f..49669aa24c4510168d003b4677b3da5548ef2b94 100644 (file)
@@ -10,7 +10,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/err.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
index 41cc74d83e4ec885bab33adf02182402938d27d3..c57c56519adda3d2240d57aa1fe6d90900efe680 100644 (file)
@@ -13,7 +13,6 @@
 #include <drm/drmP.h>
 
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
 
 #include <drm/exynos_drm.h>
index 62ef5971ac3c6c40f2d269251a1d098386e024c4..2f5c6942c968bd7a1f9ed4e16adcb8f4c7a99d35 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/spinlock.h>
 #include <linux/wait.h>
 #include <linux/i2c.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
index ef04255076c7f30bd293aa97f95fdaa7d6c5fdcd..6e320ae9afedc758b4a61282e030c099adf152db 100644 (file)
@@ -15,7 +15,6 @@
 
 #include <linux/kernel.h>
 #include <linux/i2c.h>
-#include <linux/module.h>
 
 #include "exynos_drm_drv.h"
 #include "exynos_hdmi.h"
index 42ffb71c63bca254fd5ac753b1d6dcd84c284371..c9a137caea41108a18b8c179a39110c3d64e6a5b 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/spinlock.h>
 #include <linux/wait.h>
 #include <linux/i2c.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
index 8b1b6d923abe82ab8119ce7134d3a45b681a54f6..362dd2ad286fb57397c91dba8f723038c7ca7035 100644 (file)
@@ -321,10 +321,8 @@ static struct gtt_range *psbfb_alloc(struct drm_device *dev, int aligned_size)
        /* Begin by trying to use stolen memory backing */
        backing = psb_gtt_alloc_range(dev, aligned_size, "fb", 1);
        if (backing) {
-               if (drm_gem_private_object_init(dev,
-                                       &backing->gem, aligned_size) == 0)
-                       return backing;
-               psb_gtt_free_range(dev, backing);
+               drm_gem_private_object_init(dev, &backing->gem, aligned_size);
+               return backing;
        }
        return NULL;
 }
index eefd6cc5b80d3c70abf84bc635fd5b668f504959..2f77bea30b11033904909d2e505546f028ab8158 100644 (file)
@@ -26,6 +26,7 @@
 #include <drm/drmP.h>
 #include <drm/drm.h>
 #include <drm/gma_drm.h>
+#include <drm/drm_vma_manager.h>
 #include "psb_drv.h"
 
 int psb_gem_init_object(struct drm_gem_object *obj)
@@ -38,8 +39,7 @@ void psb_gem_free_object(struct drm_gem_object *obj)
        struct gtt_range *gtt = container_of(obj, struct gtt_range, gem);
 
        /* Remove the list map if one is present */
-       if (obj->map_list.map)
-               drm_gem_free_mmap_offset(obj);
+       drm_gem_free_mmap_offset(obj);
        drm_gem_object_release(obj);
 
        /* This must occur last as it frees up the memory of the GEM object */
@@ -81,13 +81,10 @@ int psb_gem_dumb_map_gtt(struct drm_file *file, struct drm_device *dev,
        /* What validation is needed here ? */
 
        /* Make it mmapable */
-       if (!obj->map_list.map) {
-               ret = drm_gem_create_mmap_offset(obj);
-               if (ret)
-                       goto out;
-       }
-       /* GEM should really work out the hash offsets for us */
-       *offset = (u64)obj->map_list.hash.key << PAGE_SHIFT;
+       ret = drm_gem_create_mmap_offset(obj);
+       if (ret)
+               goto out;
+       *offset = drm_vma_node_offset_addr(&obj->vma_node);
 out:
        drm_gem_object_unreference(obj);
 unlock:
@@ -261,11 +258,12 @@ static int psb_gem_create_stolen(struct drm_file *file, struct drm_device *dev,
        struct gtt_range *gtt = psb_gtt_alloc_range(dev, size, "gem", 1);
        if (gtt == NULL)
                return -ENOMEM;
-       if (drm_gem_private_object_init(dev, &gtt->gem, size) != 0)
-               goto free_gtt;
+
+       drm_gem_private_object_init(dev, &gtt->gem, size);
        if (drm_gem_handle_create(file, &gtt->gem, handle) == 0)
                return 0;
-free_gtt:
+
+       drm_gem_object_release(&gtt->gem);
        psb_gtt_free_range(dev, gtt);
        return -ENOMEM;
 }
index 40034ecefd3b977a435f661f5f8a057392fb9fe0..b8449a84a0dcab83295696322d718c49924d3f4a 100644 (file)
@@ -5,6 +5,7 @@
 ccflags-y := -Iinclude/drm
 i915-y := i915_drv.o i915_dma.o i915_irq.o \
          i915_debugfs.o \
+         i915_gpu_error.o \
           i915_suspend.o \
          i915_gem.o \
          i915_gem_context.o \
@@ -37,6 +38,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o \
          intel_sprite.o \
          intel_opregion.o \
          intel_sideband.o \
+         intel_uncore.o \
          dvo_ch7xxx.o \
          dvo_ch7017.o \
          dvo_ivch.o \
index 757e0fa110430b3eab1d2654b453e5f8f1260060..af42e94f68467534f3879965c930c0c47610690d 100644 (file)
@@ -307,7 +307,7 @@ static void ch7xxx_mode_set(struct intel_dvo_device *dvo,
                idf |= CH7xxx_IDF_HSP;
 
        if (mode->flags & DRM_MODE_FLAG_PVSYNC)
-               idf |= CH7xxx_IDF_HSP;
+               idf |= CH7xxx_IDF_VSP;
 
        ch7xxx_writeb(dvo, CH7xxx_IDF, idf);
 }
index 47d6c748057e446ab70c017d788d8d015c25430c..ed72fe08217c7ce62ae0f7d7642c7d6661dfb5f7 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/debugfs.h>
 #include <linux/slab.h>
 #include <linux/export.h>
-#include <generated/utsrelease.h>
 #include <drm/drmP.h>
 #include "intel_drv.h"
 #include "intel_ringbuffer.h"
@@ -90,16 +89,6 @@ static const char *get_tiling_flag(struct drm_i915_gem_object *obj)
        }
 }
 
-static const char *cache_level_str(int type)
-{
-       switch (type) {
-       case I915_CACHE_NONE: return " uncached";
-       case I915_CACHE_LLC: return " snooped (LLC)";
-       case I915_CACHE_LLC_MLC: return " snooped (LLC+MLC)";
-       default: return "";
-       }
-}
-
 static void
 describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
 {
@@ -113,7 +102,7 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
                   obj->last_read_seqno,
                   obj->last_write_seqno,
                   obj->last_fenced_seqno,
-                  cache_level_str(obj->cache_level),
+                  i915_cache_level_str(obj->cache_level),
                   obj->dirty ? " dirty" : "",
                   obj->madv == I915_MADV_DONTNEED ? " purgeable" : "");
        if (obj->base.name)
@@ -122,9 +111,9 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
                seq_printf(m, " (pinned x %d)", obj->pin_count);
        if (obj->fence_reg != I915_FENCE_REG_NONE)
                seq_printf(m, " (fence: %d)", obj->fence_reg);
-       if (obj->gtt_space != NULL)
-               seq_printf(m, " (gtt offset: %08x, size: %08x)",
-                          obj->gtt_offset, (unsigned int)obj->gtt_space->size);
+       if (i915_gem_obj_ggtt_bound(obj))
+               seq_printf(m, " (gtt offset: %08lx, size: %08x)",
+                          i915_gem_obj_ggtt_offset(obj), (unsigned int)i915_gem_obj_ggtt_size(obj));
        if (obj->stolen)
                seq_printf(m, " (stolen: %08lx)", obj->stolen->start);
        if (obj->pin_mappable || obj->fault_mappable) {
@@ -146,7 +135,8 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data)
        uintptr_t list = (uintptr_t) node->info_ent->data;
        struct list_head *head;
        struct drm_device *dev = node->minor->dev;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct i915_address_space *vm = &dev_priv->gtt.base;
        struct drm_i915_gem_object *obj;
        size_t total_obj_size, total_gtt_size;
        int count, ret;
@@ -157,12 +147,12 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data)
 
        switch (list) {
        case ACTIVE_LIST:
-               seq_printf(m, "Active:\n");
-               head = &dev_priv->mm.active_list;
+               seq_puts(m, "Active:\n");
+               head = &vm->active_list;
                break;
        case INACTIVE_LIST:
-               seq_printf(m, "Inactive:\n");
-               head = &dev_priv->mm.inactive_list;
+               seq_puts(m, "Inactive:\n");
+               head = &vm->inactive_list;
                break;
        default:
                mutex_unlock(&dev->struct_mutex);
@@ -171,11 +161,11 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data)
 
        total_obj_size = total_gtt_size = count = 0;
        list_for_each_entry(obj, head, mm_list) {
-               seq_printf(m, "   ");
+               seq_puts(m, "   ");
                describe_obj(m, obj);
-               seq_printf(m, "\n");
+               seq_putc(m, '\n');
                total_obj_size += obj->base.size;
-               total_gtt_size += obj->gtt_space->size;
+               total_gtt_size += i915_gem_obj_ggtt_size(obj);
                count++;
        }
        mutex_unlock(&dev->struct_mutex);
@@ -187,10 +177,10 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data)
 
 #define count_objects(list, member) do { \
        list_for_each_entry(obj, list, member) { \
-               size += obj->gtt_space->size; \
+               size += i915_gem_obj_ggtt_size(obj); \
                ++count; \
                if (obj->map_and_fenceable) { \
-                       mappable_size += obj->gtt_space->size; \
+                       mappable_size += i915_gem_obj_ggtt_size(obj); \
                        ++mappable_count; \
                } \
        } \
@@ -209,7 +199,7 @@ static int per_file_stats(int id, void *ptr, void *data)
        stats->count++;
        stats->total += obj->base.size;
 
-       if (obj->gtt_space) {
+       if (i915_gem_obj_ggtt_bound(obj)) {
                if (!list_empty(&obj->ring_list))
                        stats->active += obj->base.size;
                else
@@ -222,7 +212,7 @@ static int per_file_stats(int id, void *ptr, void *data)
        return 0;
 }
 
-static int i915_gem_object_info(struct seq_file *m, voiddata)
+static int i915_gem_object_info(struct seq_file *m, void *data)
 {
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_device *dev = node->minor->dev;
@@ -230,6 +220,7 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
        u32 count, mappable_count, purgeable_count;
        size_t size, mappable_size, purgeable_size;
        struct drm_i915_gem_object *obj;
+       struct i915_address_space *vm = &dev_priv->gtt.base;
        struct drm_file *file;
        int ret;
 
@@ -247,12 +238,12 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
                   count, mappable_count, size, mappable_size);
 
        size = count = mappable_size = mappable_count = 0;
-       count_objects(&dev_priv->mm.active_list, mm_list);
+       count_objects(&vm->active_list, mm_list);
        seq_printf(m, "  %u [%u] active objects, %zu [%zu] bytes\n",
                   count, mappable_count, size, mappable_size);
 
        size = count = mappable_size = mappable_count = 0;
-       count_objects(&dev_priv->mm.inactive_list, mm_list);
+       count_objects(&vm->inactive_list, mm_list);
        seq_printf(m, "  %u [%u] inactive objects, %zu [%zu] bytes\n",
                   count, mappable_count, size, mappable_size);
 
@@ -267,11 +258,11 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
        size = count = mappable_size = mappable_count = 0;
        list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
                if (obj->fault_mappable) {
-                       size += obj->gtt_space->size;
+                       size += i915_gem_obj_ggtt_size(obj);
                        ++count;
                }
                if (obj->pin_mappable) {
-                       mappable_size += obj->gtt_space->size;
+                       mappable_size += i915_gem_obj_ggtt_size(obj);
                        ++mappable_count;
                }
                if (obj->madv == I915_MADV_DONTNEED) {
@@ -287,10 +278,10 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
                   count, size);
 
        seq_printf(m, "%zu [%lu] gtt total\n",
-                  dev_priv->gtt.total,
-                  dev_priv->gtt.mappable_end - dev_priv->gtt.start);
+                  dev_priv->gtt.base.total,
+                  dev_priv->gtt.mappable_end - dev_priv->gtt.base.start);
 
-       seq_printf(m, "\n");
+       seq_putc(m, '\n');
        list_for_each_entry_reverse(file, &dev->filelist, lhead) {
                struct file_stats stats;
 
@@ -310,7 +301,7 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
        return 0;
 }
 
-static int i915_gem_gtt_info(struct seq_file *m, voiddata)
+static int i915_gem_gtt_info(struct seq_file *m, void *data)
 {
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_device *dev = node->minor->dev;
@@ -329,11 +320,11 @@ static int i915_gem_gtt_info(struct seq_file *m, void* data)
                if (list == PINNED_LIST && obj->pin_count == 0)
                        continue;
 
-               seq_printf(m, "   ");
+               seq_puts(m, "   ");
                describe_obj(m, obj);
-               seq_printf(m, "\n");
+               seq_putc(m, '\n');
                total_obj_size += obj->base.size;
-               total_gtt_size += obj->gtt_space->size;
+               total_gtt_size += i915_gem_obj_ggtt_size(obj);
                count++;
        }
 
@@ -371,20 +362,22 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
                                           pipe, plane);
                        }
                        if (work->enable_stall_check)
-                               seq_printf(m, "Stall check enabled, ");
+                               seq_puts(m, "Stall check enabled, ");
                        else
-                               seq_printf(m, "Stall check waiting for page flip ioctl, ");
+                               seq_puts(m, "Stall check waiting for page flip ioctl, ");
                        seq_printf(m, "%d prepares\n", atomic_read(&work->pending));
 
                        if (work->old_fb_obj) {
                                struct drm_i915_gem_object *obj = work->old_fb_obj;
                                if (obj)
-                                       seq_printf(m, "Old framebuffer gtt_offset 0x%08x\n", obj->gtt_offset);
+                                       seq_printf(m, "Old framebuffer gtt_offset 0x%08lx\n",
+                                                  i915_gem_obj_ggtt_offset(obj));
                        }
                        if (work->pending_flip_obj) {
                                struct drm_i915_gem_object *obj = work->pending_flip_obj;
                                if (obj)
-                                       seq_printf(m, "New framebuffer gtt_offset 0x%08x\n", obj->gtt_offset);
+                                       seq_printf(m, "New framebuffer gtt_offset 0x%08lx\n",
+                                                  i915_gem_obj_ggtt_offset(obj));
                        }
                }
                spin_unlock_irqrestore(&dev->event_lock, flags);
@@ -424,7 +417,7 @@ static int i915_gem_request_info(struct seq_file *m, void *data)
        mutex_unlock(&dev->struct_mutex);
 
        if (count == 0)
-               seq_printf(m, "No requests\n");
+               seq_puts(m, "No requests\n");
 
        return 0;
 }
@@ -574,10 +567,10 @@ static int i915_gem_fence_regs_info(struct seq_file *m, void *data)
                seq_printf(m, "Fence %d, pin count = %d, object = ",
                           i, dev_priv->fence_regs[i].pin_count);
                if (obj == NULL)
-                       seq_printf(m, "unused");
+                       seq_puts(m, "unused");
                else
                        describe_obj(m, obj);
-               seq_printf(m, "\n");
+               seq_putc(m, '\n');
        }
 
        mutex_unlock(&dev->struct_mutex);
@@ -606,361 +599,6 @@ static int i915_hws_info(struct seq_file *m, void *data)
        return 0;
 }
 
-static const char *ring_str(int ring)
-{
-       switch (ring) {
-       case RCS: return "render";
-       case VCS: return "bsd";
-       case BCS: return "blt";
-       case VECS: return "vebox";
-       default: return "";
-       }
-}
-
-static const char *pin_flag(int pinned)
-{
-       if (pinned > 0)
-               return " P";
-       else if (pinned < 0)
-               return " p";
-       else
-               return "";
-}
-
-static const char *tiling_flag(int tiling)
-{
-       switch (tiling) {
-       default:
-       case I915_TILING_NONE: return "";
-       case I915_TILING_X: return " X";
-       case I915_TILING_Y: return " Y";
-       }
-}
-
-static const char *dirty_flag(int dirty)
-{
-       return dirty ? " dirty" : "";
-}
-
-static const char *purgeable_flag(int purgeable)
-{
-       return purgeable ? " purgeable" : "";
-}
-
-static bool __i915_error_ok(struct drm_i915_error_state_buf *e)
-{
-
-       if (!e->err && WARN(e->bytes > (e->size - 1), "overflow")) {
-               e->err = -ENOSPC;
-               return false;
-       }
-
-       if (e->bytes == e->size - 1 || e->err)
-               return false;
-
-       return true;
-}
-
-static bool __i915_error_seek(struct drm_i915_error_state_buf *e,
-                             unsigned len)
-{
-       if (e->pos + len <= e->start) {
-               e->pos += len;
-               return false;
-       }
-
-       /* First vsnprintf needs to fit in its entirety for memmove */
-       if (len >= e->size) {
-               e->err = -EIO;
-               return false;
-       }
-
-       return true;
-}
-
-static void __i915_error_advance(struct drm_i915_error_state_buf *e,
-                                unsigned len)
-{
-       /* If this is first printf in this window, adjust it so that
-        * start position matches start of the buffer
-        */
-
-       if (e->pos < e->start) {
-               const size_t off = e->start - e->pos;
-
-               /* Should not happen but be paranoid */
-               if (off > len || e->bytes) {
-                       e->err = -EIO;
-                       return;
-               }
-
-               memmove(e->buf, e->buf + off, len - off);
-               e->bytes = len - off;
-               e->pos = e->start;
-               return;
-       }
-
-       e->bytes += len;
-       e->pos += len;
-}
-
-static void i915_error_vprintf(struct drm_i915_error_state_buf *e,
-                              const char *f, va_list args)
-{
-       unsigned len;
-
-       if (!__i915_error_ok(e))
-               return;
-
-       /* Seek the first printf which is hits start position */
-       if (e->pos < e->start) {
-               len = vsnprintf(NULL, 0, f, args);
-               if (!__i915_error_seek(e, len))
-                       return;
-       }
-
-       len = vsnprintf(e->buf + e->bytes, e->size - e->bytes, f, args);
-       if (len >= e->size - e->bytes)
-               len = e->size - e->bytes - 1;
-
-       __i915_error_advance(e, len);
-}
-
-static void i915_error_puts(struct drm_i915_error_state_buf *e,
-                           const char *str)
-{
-       unsigned len;
-
-       if (!__i915_error_ok(e))
-               return;
-
-       len = strlen(str);
-
-       /* Seek the first printf which is hits start position */
-       if (e->pos < e->start) {
-               if (!__i915_error_seek(e, len))
-                       return;
-       }
-
-       if (len >= e->size - e->bytes)
-               len = e->size - e->bytes - 1;
-       memcpy(e->buf + e->bytes, str, len);
-
-       __i915_error_advance(e, len);
-}
-
-void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...)
-{
-       va_list args;
-
-       va_start(args, f);
-       i915_error_vprintf(e, f, args);
-       va_end(args);
-}
-
-#define err_printf(e, ...) i915_error_printf(e, __VA_ARGS__)
-#define err_puts(e, s) i915_error_puts(e, s)
-
-static void print_error_buffers(struct drm_i915_error_state_buf *m,
-                               const char *name,
-                               struct drm_i915_error_buffer *err,
-                               int count)
-{
-       err_printf(m, "%s [%d]:\n", name, count);
-
-       while (count--) {
-               err_printf(m, "  %08x %8u %02x %02x %x %x",
-                          err->gtt_offset,
-                          err->size,
-                          err->read_domains,
-                          err->write_domain,
-                          err->rseqno, err->wseqno);
-               err_puts(m, pin_flag(err->pinned));
-               err_puts(m, tiling_flag(err->tiling));
-               err_puts(m, dirty_flag(err->dirty));
-               err_puts(m, purgeable_flag(err->purgeable));
-               err_puts(m, err->ring != -1 ? " " : "");
-               err_puts(m, ring_str(err->ring));
-               err_puts(m, cache_level_str(err->cache_level));
-
-               if (err->name)
-                       err_printf(m, " (name: %d)", err->name);
-               if (err->fence_reg != I915_FENCE_REG_NONE)
-                       err_printf(m, " (fence: %d)", err->fence_reg);
-
-               err_puts(m, "\n");
-               err++;
-       }
-}
-
-static void i915_ring_error_state(struct drm_i915_error_state_buf *m,
-                                 struct drm_device *dev,
-                                 struct drm_i915_error_state *error,
-                                 unsigned ring)
-{
-       BUG_ON(ring >= I915_NUM_RINGS); /* shut up confused gcc */
-       err_printf(m, "%s command stream:\n", ring_str(ring));
-       err_printf(m, "  HEAD: 0x%08x\n", error->head[ring]);
-       err_printf(m, "  TAIL: 0x%08x\n", error->tail[ring]);
-       err_printf(m, "  CTL: 0x%08x\n", error->ctl[ring]);
-       err_printf(m, "  ACTHD: 0x%08x\n", error->acthd[ring]);
-       err_printf(m, "  IPEIR: 0x%08x\n", error->ipeir[ring]);
-       err_printf(m, "  IPEHR: 0x%08x\n", error->ipehr[ring]);
-       err_printf(m, "  INSTDONE: 0x%08x\n", error->instdone[ring]);
-       if (ring == RCS && INTEL_INFO(dev)->gen >= 4)
-               err_printf(m, "  BBADDR: 0x%08llx\n", error->bbaddr);
-
-       if (INTEL_INFO(dev)->gen >= 4)
-               err_printf(m, "  INSTPS: 0x%08x\n", error->instps[ring]);
-       err_printf(m, "  INSTPM: 0x%08x\n", error->instpm[ring]);
-       err_printf(m, "  FADDR: 0x%08x\n", error->faddr[ring]);
-       if (INTEL_INFO(dev)->gen >= 6) {
-               err_printf(m, "  RC PSMI: 0x%08x\n", error->rc_psmi[ring]);
-               err_printf(m, "  FAULT_REG: 0x%08x\n", error->fault_reg[ring]);
-               err_printf(m, "  SYNC_0: 0x%08x [last synced 0x%08x]\n",
-                          error->semaphore_mboxes[ring][0],
-                          error->semaphore_seqno[ring][0]);
-               err_printf(m, "  SYNC_1: 0x%08x [last synced 0x%08x]\n",
-                          error->semaphore_mboxes[ring][1],
-                          error->semaphore_seqno[ring][1]);
-       }
-       err_printf(m, "  seqno: 0x%08x\n", error->seqno[ring]);
-       err_printf(m, "  waiting: %s\n", yesno(error->waiting[ring]));
-       err_printf(m, "  ring->head: 0x%08x\n", error->cpu_ring_head[ring]);
-       err_printf(m, "  ring->tail: 0x%08x\n", error->cpu_ring_tail[ring]);
-}
-
-struct i915_error_state_file_priv {
-       struct drm_device *dev;
-       struct drm_i915_error_state *error;
-};
-
-
-static int i915_error_state(struct i915_error_state_file_priv *error_priv,
-                           struct drm_i915_error_state_buf *m)
-
-{
-       struct drm_device *dev = error_priv->dev;
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       struct drm_i915_error_state *error = error_priv->error;
-       struct intel_ring_buffer *ring;
-       int i, j, page, offset, elt;
-
-       if (!error) {
-               err_printf(m, "no error state collected\n");
-               return 0;
-       }
-
-       err_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec,
-                  error->time.tv_usec);
-       err_printf(m, "Kernel: " UTS_RELEASE "\n");
-       err_printf(m, "PCI ID: 0x%04x\n", dev->pci_device);
-       err_printf(m, "EIR: 0x%08x\n", error->eir);
-       err_printf(m, "IER: 0x%08x\n", error->ier);
-       err_printf(m, "PGTBL_ER: 0x%08x\n", error->pgtbl_er);
-       err_printf(m, "FORCEWAKE: 0x%08x\n", error->forcewake);
-       err_printf(m, "DERRMR: 0x%08x\n", error->derrmr);
-       err_printf(m, "CCID: 0x%08x\n", error->ccid);
-
-       for (i = 0; i < dev_priv->num_fence_regs; i++)
-               err_printf(m, "  fence[%d] = %08llx\n", i, error->fence[i]);
-
-       for (i = 0; i < ARRAY_SIZE(error->extra_instdone); i++)
-               err_printf(m, "  INSTDONE_%d: 0x%08x\n", i,
-                          error->extra_instdone[i]);
-
-       if (INTEL_INFO(dev)->gen >= 6) {
-               err_printf(m, "ERROR: 0x%08x\n", error->error);
-               err_printf(m, "DONE_REG: 0x%08x\n", error->done_reg);
-       }
-
-       if (INTEL_INFO(dev)->gen == 7)
-               err_printf(m, "ERR_INT: 0x%08x\n", error->err_int);
-
-       for_each_ring(ring, dev_priv, i)
-               i915_ring_error_state(m, dev, error, i);
-
-       if (error->active_bo)
-               print_error_buffers(m, "Active",
-                                   error->active_bo,
-                                   error->active_bo_count);
-
-       if (error->pinned_bo)
-               print_error_buffers(m, "Pinned",
-                                   error->pinned_bo,
-                                   error->pinned_bo_count);
-
-       for (i = 0; i < ARRAY_SIZE(error->ring); i++) {
-               struct drm_i915_error_object *obj;
-
-               if ((obj = error->ring[i].batchbuffer)) {
-                       err_printf(m, "%s --- gtt_offset = 0x%08x\n",
-                                  dev_priv->ring[i].name,
-                                  obj->gtt_offset);
-                       offset = 0;
-                       for (page = 0; page < obj->page_count; page++) {
-                               for (elt = 0; elt < PAGE_SIZE/4; elt++) {
-                                       err_printf(m, "%08x :  %08x\n", offset,
-                                                  obj->pages[page][elt]);
-                                       offset += 4;
-                               }
-                       }
-               }
-
-               if (error->ring[i].num_requests) {
-                       err_printf(m, "%s --- %d requests\n",
-                                  dev_priv->ring[i].name,
-                                  error->ring[i].num_requests);
-                       for (j = 0; j < error->ring[i].num_requests; j++) {
-                               err_printf(m, "  seqno 0x%08x, emitted %ld, tail 0x%08x\n",
-                                          error->ring[i].requests[j].seqno,
-                                          error->ring[i].requests[j].jiffies,
-                                          error->ring[i].requests[j].tail);
-                       }
-               }
-
-               if ((obj = error->ring[i].ringbuffer)) {
-                       err_printf(m, "%s --- ringbuffer = 0x%08x\n",
-                                  dev_priv->ring[i].name,
-                                  obj->gtt_offset);
-                       offset = 0;
-                       for (page = 0; page < obj->page_count; page++) {
-                               for (elt = 0; elt < PAGE_SIZE/4; elt++) {
-                                       err_printf(m, "%08x :  %08x\n",
-                                                  offset,
-                                                  obj->pages[page][elt]);
-                                       offset += 4;
-                               }
-                       }
-               }
-
-               obj = error->ring[i].ctx;
-               if (obj) {
-                       err_printf(m, "%s --- HW Context = 0x%08x\n",
-                                  dev_priv->ring[i].name,
-                                  obj->gtt_offset);
-                       offset = 0;
-                       for (elt = 0; elt < PAGE_SIZE/16; elt += 4) {
-                               err_printf(m, "[%04x] %08x %08x %08x %08x\n",
-                                          offset,
-                                          obj->pages[0][elt],
-                                          obj->pages[0][elt+1],
-                                          obj->pages[0][elt+2],
-                                          obj->pages[0][elt+3]);
-                                       offset += 16;
-                       }
-               }
-       }
-
-       if (error->overlay)
-               intel_overlay_print_error_state(m, error->overlay);
-
-       if (error->display)
-               intel_display_print_error_state(m, dev, error->display);
-
-       return 0;
-}
-
 static ssize_t
 i915_error_state_write(struct file *filp,
                       const char __user *ubuf,
@@ -986,9 +624,7 @@ i915_error_state_write(struct file *filp,
 static int i915_error_state_open(struct inode *inode, struct file *file)
 {
        struct drm_device *dev = inode->i_private;
-       drm_i915_private_t *dev_priv = dev->dev_private;
        struct i915_error_state_file_priv *error_priv;
-       unsigned long flags;
 
        error_priv = kzalloc(sizeof(*error_priv), GFP_KERNEL);
        if (!error_priv)
@@ -996,11 +632,7 @@ static int i915_error_state_open(struct inode *inode, struct file *file)
 
        error_priv->dev = dev;
 
-       spin_lock_irqsave(&dev_priv->gpu_error.lock, flags);
-       error_priv->error = dev_priv->gpu_error.first_error;
-       if (error_priv->error)
-               kref_get(&error_priv->error->ref);
-       spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags);
+       i915_error_state_get(dev, error_priv);
 
        file->private_data = error_priv;
 
@@ -1011,8 +643,7 @@ static int i915_error_state_release(struct inode *inode, struct file *file)
 {
        struct i915_error_state_file_priv *error_priv = file->private_data;
 
-       if (error_priv->error)
-               kref_put(&error_priv->error->ref, i915_error_state_free);
+       i915_error_state_put(error_priv);
        kfree(error_priv);
 
        return 0;
@@ -1025,40 +656,15 @@ static ssize_t i915_error_state_read(struct file *file, char __user *userbuf,
        struct drm_i915_error_state_buf error_str;
        loff_t tmp_pos = 0;
        ssize_t ret_count = 0;
-       int ret = 0;
-
-       memset(&error_str, 0, sizeof(error_str));
-
-       /* We need to have enough room to store any i915_error_state printf
-        * so that we can move it to start position.
-        */
-       error_str.size = count + 1 > PAGE_SIZE ? count + 1 : PAGE_SIZE;
-       error_str.buf = kmalloc(error_str.size,
-                               GFP_TEMPORARY | __GFP_NORETRY | __GFP_NOWARN);
-
-       if (error_str.buf == NULL) {
-               error_str.size = PAGE_SIZE;
-               error_str.buf = kmalloc(error_str.size, GFP_TEMPORARY);
-       }
-
-       if (error_str.buf == NULL) {
-               error_str.size = 128;
-               error_str.buf = kmalloc(error_str.size, GFP_TEMPORARY);
-       }
-
-       if (error_str.buf == NULL)
-               return -ENOMEM;
-
-       error_str.start = *pos;
+       int ret;
 
-       ret = i915_error_state(error_priv, &error_str);
+       ret = i915_error_state_buf_init(&error_str, count, *pos);
        if (ret)
-               goto out;
+               return ret;
 
-       if (error_str.bytes == 0 && error_str.err) {
-               ret = error_str.err;
+       ret = i915_error_state_to_str(&error_str, error_priv);
+       if (ret)
                goto out;
-       }
 
        ret_count = simple_read_from_buffer(userbuf, count, &tmp_pos,
                                            error_str.buf,
@@ -1069,7 +675,7 @@ static ssize_t i915_error_state_read(struct file *file, char __user *userbuf,
        else
                *pos = error_str.start + ret_count;
 out:
-       kfree(error_str.buf);
+       i915_error_state_buf_release(&error_str);
        return ret ?: ret_count;
 }
 
@@ -1246,7 +852,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
                                        (freq_sts >> 8) & 0xff));
                mutex_unlock(&dev_priv->rps.hw_lock);
        } else {
-               seq_printf(m, "no P-state info available\n");
+               seq_puts(m, "no P-state info available\n");
        }
 
        return 0;
@@ -1341,28 +947,28 @@ static int ironlake_drpc_info(struct seq_file *m)
        seq_printf(m, "RS2 VID: %d\n", ((crstandvid >> 8) & 0x3f));
        seq_printf(m, "Render standby enabled: %s\n",
                   (rstdbyctl & RCX_SW_EXIT) ? "no" : "yes");
-       seq_printf(m, "Current RS state: ");
+       seq_puts(m, "Current RS state: ");
        switch (rstdbyctl & RSX_STATUS_MASK) {
        case RSX_STATUS_ON:
-               seq_printf(m, "on\n");
+               seq_puts(m, "on\n");
                break;
        case RSX_STATUS_RC1:
-               seq_printf(m, "RC1\n");
+               seq_puts(m, "RC1\n");
                break;
        case RSX_STATUS_RC1E:
-               seq_printf(m, "RC1E\n");
+               seq_puts(m, "RC1E\n");
                break;
        case RSX_STATUS_RS1:
-               seq_printf(m, "RS1\n");
+               seq_puts(m, "RS1\n");
                break;
        case RSX_STATUS_RS2:
-               seq_printf(m, "RS2 (RC6)\n");
+               seq_puts(m, "RS2 (RC6)\n");
                break;
        case RSX_STATUS_RS3:
-               seq_printf(m, "RC3 (RC6+)\n");
+               seq_puts(m, "RC3 (RC6+)\n");
                break;
        default:
-               seq_printf(m, "unknown\n");
+               seq_puts(m, "unknown\n");
                break;
        }
 
@@ -1377,20 +983,19 @@ static int gen6_drpc_info(struct seq_file *m)
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 rpmodectl1, gt_core_status, rcctl1, rc6vids = 0;
        unsigned forcewake_count;
-       int count=0, ret;
-
+       int count = 0, ret;
 
        ret = mutex_lock_interruptible(&dev->struct_mutex);
        if (ret)
                return ret;
 
-       spin_lock_irq(&dev_priv->gt_lock);
-       forcewake_count = dev_priv->forcewake_count;
-       spin_unlock_irq(&dev_priv->gt_lock);
+       spin_lock_irq(&dev_priv->uncore.lock);
+       forcewake_count = dev_priv->uncore.forcewake_count;
+       spin_unlock_irq(&dev_priv->uncore.lock);
 
        if (forcewake_count) {
-               seq_printf(m, "RC information inaccurate because somebody "
-                             "holds a forcewake reference \n");
+               seq_puts(m, "RC information inaccurate because somebody "
+                           "holds a forcewake reference \n");
        } else {
                /* NB: we cannot use forcewake, else we read the wrong values */
                while (count++ < 50 && (I915_READ_NOTRACE(FORCEWAKE_ACK) & 1))
@@ -1399,7 +1004,7 @@ static int gen6_drpc_info(struct seq_file *m)
        }
 
        gt_core_status = readl(dev_priv->regs + GEN6_GT_CORE_STATUS);
-       trace_i915_reg_rw(false, GEN6_GT_CORE_STATUS, gt_core_status, 4);
+       trace_i915_reg_rw(false, GEN6_GT_CORE_STATUS, gt_core_status, 4, true);
 
        rpmodectl1 = I915_READ(GEN6_RP_CONTROL);
        rcctl1 = I915_READ(GEN6_RC_CONTROL);
@@ -1423,25 +1028,25 @@ static int gen6_drpc_info(struct seq_file *m)
                   yesno(rcctl1 & GEN6_RC_CTL_RC6p_ENABLE));
        seq_printf(m, "Deepest RC6 Enabled: %s\n",
                   yesno(rcctl1 & GEN6_RC_CTL_RC6pp_ENABLE));
-       seq_printf(m, "Current RC state: ");
+       seq_puts(m, "Current RC state: ");
        switch (gt_core_status & GEN6_RCn_MASK) {
        case GEN6_RC0:
                if (gt_core_status & GEN6_CORE_CPD_STATE_MASK)
-                       seq_printf(m, "Core Power Down\n");
+                       seq_puts(m, "Core Power Down\n");
                else
-                       seq_printf(m, "on\n");
+                       seq_puts(m, "on\n");
                break;
        case GEN6_RC3:
-               seq_printf(m, "RC3\n");
+               seq_puts(m, "RC3\n");
                break;
        case GEN6_RC6:
-               seq_printf(m, "RC6\n");
+               seq_puts(m, "RC6\n");
                break;
        case GEN6_RC7:
-               seq_printf(m, "RC7\n");
+               seq_puts(m, "RC7\n");
                break;
        default:
-               seq_printf(m, "Unknown\n");
+               seq_puts(m, "Unknown\n");
                break;
        }
 
@@ -1485,43 +1090,46 @@ static int i915_fbc_status(struct seq_file *m, void *unused)
        drm_i915_private_t *dev_priv = dev->dev_private;
 
        if (!I915_HAS_FBC(dev)) {
-               seq_printf(m, "FBC unsupported on this chipset\n");
+               seq_puts(m, "FBC unsupported on this chipset\n");
                return 0;
        }
 
        if (intel_fbc_enabled(dev)) {
-               seq_printf(m, "FBC enabled\n");
+               seq_puts(m, "FBC enabled\n");
        } else {
-               seq_printf(m, "FBC disabled: ");
-               switch (dev_priv->no_fbc_reason) {
+               seq_puts(m, "FBC disabled: ");
+               switch (dev_priv->fbc.no_fbc_reason) {
                case FBC_NO_OUTPUT:
-                       seq_printf(m, "no outputs");
+                       seq_puts(m, "no outputs");
                        break;
                case FBC_STOLEN_TOO_SMALL:
-                       seq_printf(m, "not enough stolen memory");
+                       seq_puts(m, "not enough stolen memory");
                        break;
                case FBC_UNSUPPORTED_MODE:
-                       seq_printf(m, "mode not supported");
+                       seq_puts(m, "mode not supported");
                        break;
                case FBC_MODE_TOO_LARGE:
-                       seq_printf(m, "mode too large");
+                       seq_puts(m, "mode too large");
                        break;
                case FBC_BAD_PLANE:
-                       seq_printf(m, "FBC unsupported on plane");
+                       seq_puts(m, "FBC unsupported on plane");
                        break;
                case FBC_NOT_TILED:
-                       seq_printf(m, "scanout buffer not tiled");
+                       seq_puts(m, "scanout buffer not tiled");
                        break;
                case FBC_MULTIPLE_PIPES:
-                       seq_printf(m, "multiple pipes are enabled");
+                       seq_puts(m, "multiple pipes are enabled");
                        break;
                case FBC_MODULE_PARAM:
-                       seq_printf(m, "disabled per module param (default off)");
+                       seq_puts(m, "disabled per module param (default off)");
+                       break;
+               case FBC_CHIP_DEFAULT:
+                       seq_puts(m, "disabled per chip default");
                        break;
                default:
-                       seq_printf(m, "unknown reason");
+                       seq_puts(m, "unknown reason");
                }
-               seq_printf(m, "\n");
+               seq_putc(m, '\n');
        }
        return 0;
 }
@@ -1604,7 +1212,7 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused)
        int gpu_freq, ia_freq;
 
        if (!(IS_GEN6(dev) || IS_GEN7(dev))) {
-               seq_printf(m, "unsupported on this chipset\n");
+               seq_puts(m, "unsupported on this chipset\n");
                return 0;
        }
 
@@ -1612,7 +1220,7 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused)
        if (ret)
                return ret;
 
-       seq_printf(m, "GPU freq (MHz)\tEffective CPU freq (MHz)\tEffective Ring freq (MHz)\n");
+       seq_puts(m, "GPU freq (MHz)\tEffective CPU freq (MHz)\tEffective Ring freq (MHz)\n");
 
        for (gpu_freq = dev_priv->rps.min_delay;
             gpu_freq <= dev_priv->rps.max_delay;
@@ -1701,7 +1309,7 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
                   fb->base.bits_per_pixel,
                   atomic_read(&fb->base.refcount.refcount));
        describe_obj(m, fb->obj);
-       seq_printf(m, "\n");
+       seq_putc(m, '\n');
        mutex_unlock(&dev->mode_config.mutex);
 
        mutex_lock(&dev->mode_config.fb_lock);
@@ -1716,7 +1324,7 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
                           fb->base.bits_per_pixel,
                           atomic_read(&fb->base.refcount.refcount));
                describe_obj(m, fb->obj);
-               seq_printf(m, "\n");
+               seq_putc(m, '\n');
        }
        mutex_unlock(&dev->mode_config.fb_lock);
 
@@ -1736,22 +1344,22 @@ static int i915_context_status(struct seq_file *m, void *unused)
                return ret;
 
        if (dev_priv->ips.pwrctx) {
-               seq_printf(m, "power context ");
+               seq_puts(m, "power context ");
                describe_obj(m, dev_priv->ips.pwrctx);
-               seq_printf(m, "\n");
+               seq_putc(m, '\n');
        }
 
        if (dev_priv->ips.renderctx) {
-               seq_printf(m, "render context ");
+               seq_puts(m, "render context ");
                describe_obj(m, dev_priv->ips.renderctx);
-               seq_printf(m, "\n");
+               seq_putc(m, '\n');
        }
 
        for_each_ring(ring, dev_priv, i) {
                if (ring->default_context) {
                        seq_printf(m, "HW default context %s ring ", ring->name);
                        describe_obj(m, ring->default_context->obj);
-                       seq_printf(m, "\n");
+                       seq_putc(m, '\n');
                }
        }
 
@@ -1767,9 +1375,9 @@ static int i915_gen6_forcewake_count_info(struct seq_file *m, void *data)
        struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned forcewake_count;
 
-       spin_lock_irq(&dev_priv->gt_lock);
-       forcewake_count = dev_priv->forcewake_count;
-       spin_unlock_irq(&dev_priv->gt_lock);
+       spin_lock_irq(&dev_priv->uncore.lock);
+       forcewake_count = dev_priv->uncore.forcewake_count;
+       spin_unlock_irq(&dev_priv->uncore.lock);
 
        seq_printf(m, "forcewake count = %u\n", forcewake_count);
 
@@ -1778,7 +1386,7 @@ static int i915_gen6_forcewake_count_info(struct seq_file *m, void *data)
 
 static const char *swizzle_string(unsigned swizzle)
 {
-       switch(swizzle) {
+       switch (swizzle) {
        case I915_BIT_6_SWIZZLE_NONE:
                return "none";
        case I915_BIT_6_SWIZZLE_9:
@@ -1868,7 +1476,7 @@ static int i915_ppgtt_info(struct seq_file *m, void *data)
        if (dev_priv->mm.aliasing_ppgtt) {
                struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
 
-               seq_printf(m, "aliasing PPGTT:\n");
+               seq_puts(m, "aliasing PPGTT:\n");
                seq_printf(m, "pd gtt offset: 0x%08x\n", ppgtt->pd_offset);
        }
        seq_printf(m, "ECOCHK: 0x%08x\n", I915_READ(GAM_ECOCHK));
@@ -1886,7 +1494,7 @@ static int i915_dpio_info(struct seq_file *m, void *data)
 
 
        if (!IS_VALLEYVIEW(dev)) {
-               seq_printf(m, "unsupported\n");
+               seq_puts(m, "unsupported\n");
                return 0;
        }
 
@@ -1924,6 +1532,148 @@ static int i915_dpio_info(struct seq_file *m, void *data)
        return 0;
 }
 
+static int i915_llc(struct seq_file *m, void *data)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       /* Size calculation for LLC is a bit of a pain. Ignore for now. */
+       seq_printf(m, "LLC: %s\n", yesno(HAS_LLC(dev)));
+       seq_printf(m, "eLLC: %zuMB\n", dev_priv->ellc_size);
+
+       return 0;
+}
+
+static int i915_edp_psr_status(struct seq_file *m, void *data)
+{
+       struct drm_info_node *node = m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 psrstat, psrperf;
+
+       if (!IS_HASWELL(dev)) {
+               seq_puts(m, "PSR not supported on this platform\n");
+       } else if (IS_HASWELL(dev) && I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE) {
+               seq_puts(m, "PSR enabled\n");
+       } else {
+               seq_puts(m, "PSR disabled: ");
+               switch (dev_priv->no_psr_reason) {
+               case PSR_NO_SOURCE:
+                       seq_puts(m, "not supported on this platform");
+                       break;
+               case PSR_NO_SINK:
+                       seq_puts(m, "not supported by panel");
+                       break;
+               case PSR_MODULE_PARAM:
+                       seq_puts(m, "disabled by flag");
+                       break;
+               case PSR_CRTC_NOT_ACTIVE:
+                       seq_puts(m, "crtc not active");
+                       break;
+               case PSR_PWR_WELL_ENABLED:
+                       seq_puts(m, "power well enabled");
+                       break;
+               case PSR_NOT_TILED:
+                       seq_puts(m, "not tiled");
+                       break;
+               case PSR_SPRITE_ENABLED:
+                       seq_puts(m, "sprite enabled");
+                       break;
+               case PSR_S3D_ENABLED:
+                       seq_puts(m, "stereo 3d enabled");
+                       break;
+               case PSR_INTERLACED_ENABLED:
+                       seq_puts(m, "interlaced enabled");
+                       break;
+               case PSR_HSW_NOT_DDIA:
+                       seq_puts(m, "HSW ties PSR to DDI A (eDP)");
+                       break;
+               default:
+                       seq_puts(m, "unknown reason");
+               }
+               seq_puts(m, "\n");
+               return 0;
+       }
+
+       psrstat = I915_READ(EDP_PSR_STATUS_CTL);
+
+       seq_puts(m, "PSR Current State: ");
+       switch (psrstat & EDP_PSR_STATUS_STATE_MASK) {
+       case EDP_PSR_STATUS_STATE_IDLE:
+               seq_puts(m, "Reset state\n");
+               break;
+       case EDP_PSR_STATUS_STATE_SRDONACK:
+               seq_puts(m, "Wait for TG/Stream to send on frame of data after SRD conditions are met\n");
+               break;
+       case EDP_PSR_STATUS_STATE_SRDENT:
+               seq_puts(m, "SRD entry\n");
+               break;
+       case EDP_PSR_STATUS_STATE_BUFOFF:
+               seq_puts(m, "Wait for buffer turn off\n");
+               break;
+       case EDP_PSR_STATUS_STATE_BUFON:
+               seq_puts(m, "Wait for buffer turn on\n");
+               break;
+       case EDP_PSR_STATUS_STATE_AUXACK:
+               seq_puts(m, "Wait for AUX to acknowledge on SRD exit\n");
+               break;
+       case EDP_PSR_STATUS_STATE_SRDOFFACK:
+               seq_puts(m, "Wait for TG/Stream to acknowledge the SRD VDM exit\n");
+               break;
+       default:
+               seq_puts(m, "Unknown\n");
+               break;
+       }
+
+       seq_puts(m, "Link Status: ");
+       switch (psrstat & EDP_PSR_STATUS_LINK_MASK) {
+       case EDP_PSR_STATUS_LINK_FULL_OFF:
+               seq_puts(m, "Link is fully off\n");
+               break;
+       case EDP_PSR_STATUS_LINK_FULL_ON:
+               seq_puts(m, "Link is fully on\n");
+               break;
+       case EDP_PSR_STATUS_LINK_STANDBY:
+               seq_puts(m, "Link is in standby\n");
+               break;
+       default:
+               seq_puts(m, "Unknown\n");
+               break;
+       }
+
+       seq_printf(m, "PSR Entry Count: %u\n",
+                  psrstat >> EDP_PSR_STATUS_COUNT_SHIFT &
+                  EDP_PSR_STATUS_COUNT_MASK);
+
+       seq_printf(m, "Max Sleep Timer Counter: %u\n",
+                  psrstat >> EDP_PSR_STATUS_MAX_SLEEP_TIMER_SHIFT &
+                  EDP_PSR_STATUS_MAX_SLEEP_TIMER_MASK);
+
+       seq_printf(m, "Had AUX error: %s\n",
+                  yesno(psrstat & EDP_PSR_STATUS_AUX_ERROR));
+
+       seq_printf(m, "Sending AUX: %s\n",
+                  yesno(psrstat & EDP_PSR_STATUS_AUX_SENDING));
+
+       seq_printf(m, "Sending Idle: %s\n",
+                  yesno(psrstat & EDP_PSR_STATUS_SENDING_IDLE));
+
+       seq_printf(m, "Sending TP2 TP3: %s\n",
+                  yesno(psrstat & EDP_PSR_STATUS_SENDING_TP2_TP3));
+
+       seq_printf(m, "Sending TP1: %s\n",
+                  yesno(psrstat & EDP_PSR_STATUS_SENDING_TP1));
+
+       seq_printf(m, "Idle Count: %u\n",
+                  psrstat & EDP_PSR_STATUS_IDLE_MASK);
+
+       psrperf = (I915_READ(EDP_PSR_PERF_CNT)) & EDP_PSR_PERF_CNT_MASK;
+       seq_printf(m, "Performance Counter: %u\n", psrperf);
+
+       return 0;
+}
+
 static int
 i915_wedged_get(void *data, u64 *val)
 {
@@ -2006,6 +1756,7 @@ i915_drop_caches_set(void *data, u64 val)
        struct drm_device *dev = data;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj, *next;
+       struct i915_address_space *vm = &dev_priv->gtt.base;
        int ret;
 
        DRM_DEBUG_DRIVER("Dropping caches: 0x%08llx\n", val);
@@ -2026,7 +1777,8 @@ i915_drop_caches_set(void *data, u64 val)
                i915_gem_retire_requests(dev);
 
        if (val & DROP_BOUND) {
-               list_for_each_entry_safe(obj, next, &dev_priv->mm.inactive_list, mm_list)
+               list_for_each_entry_safe(obj, next, &vm->inactive_list,
+                                        mm_list)
                        if (obj->pin_count == 0) {
                                ret = i915_gem_object_unbind(obj);
                                if (ret)
@@ -2353,64 +2105,40 @@ static struct drm_info_list i915_debugfs_list[] = {
        {"i915_swizzle_info", i915_swizzle_info, 0},
        {"i915_ppgtt_info", i915_ppgtt_info, 0},
        {"i915_dpio", i915_dpio_info, 0},
+       {"i915_llc", i915_llc, 0},
+       {"i915_edp_psr_status", i915_edp_psr_status, 0},
 };
 #define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
 
+struct i915_debugfs_files {
+       const char *name;
+       const struct file_operations *fops;
+} i915_debugfs_files[] = {
+       {"i915_wedged", &i915_wedged_fops},
+       {"i915_max_freq", &i915_max_freq_fops},
+       {"i915_min_freq", &i915_min_freq_fops},
+       {"i915_cache_sharing", &i915_cache_sharing_fops},
+       {"i915_ring_stop", &i915_ring_stop_fops},
+       {"i915_gem_drop_caches", &i915_drop_caches_fops},
+       {"i915_error_state", &i915_error_state_fops},
+       {"i915_next_seqno", &i915_next_seqno_fops},
+};
+
 int i915_debugfs_init(struct drm_minor *minor)
 {
-       int ret;
-
-       ret = i915_debugfs_create(minor->debugfs_root, minor,
-                                 "i915_wedged",
-                                 &i915_wedged_fops);
-       if (ret)
-               return ret;
+       int ret, i;
 
        ret = i915_forcewake_create(minor->debugfs_root, minor);
        if (ret)
                return ret;
 
-       ret = i915_debugfs_create(minor->debugfs_root, minor,
-                                 "i915_max_freq",
-                                 &i915_max_freq_fops);
-       if (ret)
-               return ret;
-
-       ret = i915_debugfs_create(minor->debugfs_root, minor,
-                                 "i915_min_freq",
-                                 &i915_min_freq_fops);
-       if (ret)
-               return ret;
-
-       ret = i915_debugfs_create(minor->debugfs_root, minor,
-                                 "i915_cache_sharing",
-                                 &i915_cache_sharing_fops);
-       if (ret)
-               return ret;
-
-       ret = i915_debugfs_create(minor->debugfs_root, minor,
-                                 "i915_ring_stop",
-                                 &i915_ring_stop_fops);
-       if (ret)
-               return ret;
-
-       ret = i915_debugfs_create(minor->debugfs_root, minor,
-                                 "i915_gem_drop_caches",
-                                 &i915_drop_caches_fops);
-       if (ret)
-               return ret;
-
-       ret = i915_debugfs_create(minor->debugfs_root, minor,
-                                 "i915_error_state",
-                                 &i915_error_state_fops);
-       if (ret)
-               return ret;
-
-       ret = i915_debugfs_create(minor->debugfs_root, minor,
-                                "i915_next_seqno",
-                                &i915_next_seqno_fops);
-       if (ret)
-               return ret;
+       for (i = 0; i < ARRAY_SIZE(i915_debugfs_files); i++) {
+               ret = i915_debugfs_create(minor->debugfs_root, minor,
+                                         i915_debugfs_files[i].name,
+                                         i915_debugfs_files[i].fops);
+               if (ret)
+                       return ret;
+       }
 
        return drm_debugfs_create_files(i915_debugfs_list,
                                        I915_DEBUGFS_ENTRIES,
@@ -2419,26 +2147,18 @@ int i915_debugfs_init(struct drm_minor *minor)
 
 void i915_debugfs_cleanup(struct drm_minor *minor)
 {
+       int i;
+
        drm_debugfs_remove_files(i915_debugfs_list,
                                 I915_DEBUGFS_ENTRIES, minor);
        drm_debugfs_remove_files((struct drm_info_list *) &i915_forcewake_fops,
                                 1, minor);
-       drm_debugfs_remove_files((struct drm_info_list *) &i915_wedged_fops,
-                                1, minor);
-       drm_debugfs_remove_files((struct drm_info_list *) &i915_max_freq_fops,
-                                1, minor);
-       drm_debugfs_remove_files((struct drm_info_list *) &i915_min_freq_fops,
-                                1, minor);
-       drm_debugfs_remove_files((struct drm_info_list *) &i915_cache_sharing_fops,
-                                1, minor);
-       drm_debugfs_remove_files((struct drm_info_list *) &i915_drop_caches_fops,
-                                1, minor);
-       drm_debugfs_remove_files((struct drm_info_list *) &i915_ring_stop_fops,
-                                1, minor);
-       drm_debugfs_remove_files((struct drm_info_list *) &i915_error_state_fops,
-                                1, minor);
-       drm_debugfs_remove_files((struct drm_info_list *) &i915_next_seqno_fops,
-                                1, minor);
+       for (i = 0; i < ARRAY_SIZE(i915_debugfs_files); i++) {
+               struct drm_info_list *info_list =
+                       (struct drm_info_list *) i915_debugfs_files[i].fops;
+
+               drm_debugfs_remove_files(info_list, 1, minor);
+       }
 }
 
 #endif /* CONFIG_DEBUG_FS */
index 66c63808fa35e5834a876e59dd49735fdb6f82ac..de611f64bb1668ecbf1001eeec5af8a8d945df5b 100644 (file)
@@ -1323,10 +1323,8 @@ static int i915_load_modeset_init(struct drm_device *dev)
        /* Always safe in the mode setting case. */
        /* FIXME: do pre/post-mode set stuff in core KMS code */
        dev->vblank_disable_allowed = 1;
-       if (INTEL_INFO(dev)->num_pipes == 0) {
-               dev_priv->mm.suspended = 0;
+       if (INTEL_INFO(dev)->num_pipes == 0)
                return 0;
-       }
 
        ret = intel_fbdev_init(dev);
        if (ret)
@@ -1352,9 +1350,6 @@ static int i915_load_modeset_init(struct drm_device *dev)
 
        drm_kms_helper_poll_init(dev);
 
-       /* We're off and running w/KMS */
-       dev_priv->mm.suspended = 0;
-
        return 0;
 
 cleanup_gem:
@@ -1363,7 +1358,7 @@ cleanup_gem:
        i915_gem_context_fini(dev);
        mutex_unlock(&dev->struct_mutex);
        i915_gem_cleanup_aliasing_ppgtt(dev);
-       drm_mm_takedown(&dev_priv->mm.gtt_space);
+       drm_mm_takedown(&dev_priv->gtt.base.mm);
 cleanup_irq:
        drm_irq_uninstall(dev);
 cleanup_gem_stolen:
@@ -1440,22 +1435,6 @@ static void i915_dump_device_info(struct drm_i915_private *dev_priv)
 #undef SEP_COMMA
 }
 
-/**
- * intel_early_sanitize_regs - clean up BIOS state
- * @dev: DRM device
- *
- * This function must be called before we do any I915_READ or I915_WRITE. Its
- * purpose is to clean up any state left by the BIOS that may affect us when
- * reading and/or writing registers.
- */
-static void intel_early_sanitize_regs(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       if (HAS_FPGA_DBG_UNCLAIMED(dev))
-               I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
-}
-
 /**
  * i915_driver_load - setup chip and create an initial config
  * @dev: DRM device
@@ -1497,15 +1476,19 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
 
        spin_lock_init(&dev_priv->irq_lock);
        spin_lock_init(&dev_priv->gpu_error.lock);
-       spin_lock_init(&dev_priv->rps.lock);
-       spin_lock_init(&dev_priv->gt_lock);
        spin_lock_init(&dev_priv->backlight.lock);
+       spin_lock_init(&dev_priv->uncore.lock);
+       spin_lock_init(&dev_priv->mm.object_stat_lock);
        mutex_init(&dev_priv->dpio_lock);
        mutex_init(&dev_priv->rps.hw_lock);
        mutex_init(&dev_priv->modeset_restore_lock);
 
        i915_dump_device_info(dev_priv);
 
+       INIT_LIST_HEAD(&dev_priv->vm_list);
+       INIT_LIST_HEAD(&dev_priv->gtt.base.global_link);
+       list_add(&dev_priv->gtt.base.global_link, &dev_priv->vm_list);
+
        if (i915_get_bridge_dev(dev)) {
                ret = -EIO;
                goto free_priv;
@@ -1531,7 +1514,17 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
                goto put_bridge;
        }
 
-       intel_early_sanitize_regs(dev);
+       intel_uncore_early_sanitize(dev);
+
+       if (IS_HASWELL(dev) && (I915_READ(HSW_EDRAM_PRESENT) == 1)) {
+               /* The docs do not explain exactly how the calculation can be
+                * made. It is somewhat guessable, but for now, it's always
+                * 128MB.
+                * NB: We can't write IDICR yet because we do not have gt funcs
+                * set up */
+               dev_priv->ellc_size = 128;
+               DRM_INFO("Found %zuMB of eLLC\n", dev_priv->ellc_size);
+       }
 
        ret = i915_gem_gtt_init(dev);
        if (ret)
@@ -1567,8 +1560,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
                goto out_rmmap;
        }
 
-       dev_priv->mm.gtt_mtrr = arch_phys_wc_add(dev_priv->gtt.mappable_base,
-                                                aperture_size);
+       dev_priv->gtt.mtrr = arch_phys_wc_add(dev_priv->gtt.mappable_base,
+                                             aperture_size);
 
        /* The i915 workqueue is primarily used for batched retirement of
         * requests (and thus managing bo) once the task has been completed
@@ -1594,8 +1587,9 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        intel_detect_pch(dev);
 
        intel_irq_init(dev);
-       intel_gt_sanitize(dev);
-       intel_gt_init(dev);
+       intel_pm_init(dev);
+       intel_uncore_sanitize(dev);
+       intel_uncore_init(dev);
 
        /* Try to make sure MCHBAR is enabled before poking at it */
        intel_setup_mchbar(dev);
@@ -1630,9 +1624,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
                        goto out_gem_unload;
        }
 
-       /* Start out suspended */
-       dev_priv->mm.suspended = 1;
-
        if (HAS_POWER_WELL(dev))
                i915_init_power_well(dev);
 
@@ -1642,6 +1633,9 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
                        DRM_ERROR("failed to init modeset\n");
                        goto out_gem_unload;
                }
+       } else {
+               /* Start out suspended in ums mode. */
+               dev_priv->ums.mm_suspended = 1;
        }
 
        i915_setup_sysfs(dev);
@@ -1668,9 +1662,9 @@ out_gem_unload:
        intel_teardown_mchbar(dev);
        destroy_workqueue(dev_priv->wq);
 out_mtrrfree:
-       arch_phys_wc_del(dev_priv->mm.gtt_mtrr);
+       arch_phys_wc_del(dev_priv->gtt.mtrr);
        io_mapping_free(dev_priv->gtt.mappable);
-       dev_priv->gtt.gtt_remove(dev);
+       dev_priv->gtt.base.cleanup(&dev_priv->gtt.base);
 out_rmmap:
        pci_iounmap(dev->pdev, dev_priv->regs);
 put_bridge:
@@ -1706,7 +1700,7 @@ int i915_driver_unload(struct drm_device *dev)
        cancel_delayed_work_sync(&dev_priv->mm.retire_work);
 
        io_mapping_free(dev_priv->gtt.mappable);
-       arch_phys_wc_del(dev_priv->mm.gtt_mtrr);
+       arch_phys_wc_del(dev_priv->gtt.mtrr);
 
        acpi_video_unregister();
 
@@ -1755,7 +1749,9 @@ int i915_driver_unload(struct drm_device *dev)
                        i915_free_hws(dev);
        }
 
-       drm_mm_takedown(&dev_priv->mm.gtt_space);
+       list_del(&dev_priv->gtt.base.global_link);
+       WARN_ON(!list_empty(&dev_priv->vm_list));
+       drm_mm_takedown(&dev_priv->gtt.base.mm);
        if (dev_priv->regs != NULL)
                pci_iounmap(dev->pdev, dev_priv->regs);
 
@@ -1765,7 +1761,7 @@ int i915_driver_unload(struct drm_device *dev)
        destroy_workqueue(dev_priv->wq);
        pm_qos_remove_request(&dev_priv->pm_qos);
 
-       dev_priv->gtt.gtt_remove(dev);
+       dev_priv->gtt.base.cleanup(&dev_priv->gtt.base);
 
        if (dev_priv->slab)
                kmem_cache_destroy(dev_priv->slab);
index 45b3c030f48393b6921e66406e48f92e2f1d643e..01d63a0435fbbd15a99dd2d6bb71127e53a767cd 100644 (file)
@@ -118,6 +118,10 @@ module_param_named(i915_enable_ppgtt, i915_enable_ppgtt, int, 0600);
 MODULE_PARM_DESC(i915_enable_ppgtt,
                "Enable PPGTT (default: true)");
 
+int i915_enable_psr __read_mostly = 0;
+module_param_named(enable_psr, i915_enable_psr, int, 0600);
+MODULE_PARM_DESC(enable_psr, "Enable PSR (default: false)");
+
 unsigned int i915_preliminary_hw_support __read_mostly = 0;
 module_param_named(preliminary_hw_support, i915_preliminary_hw_support, int, 0600);
 MODULE_PARM_DESC(preliminary_hw_support,
@@ -132,6 +136,16 @@ int i915_enable_ips __read_mostly = 1;
 module_param_named(enable_ips, i915_enable_ips, int, 0600);
 MODULE_PARM_DESC(enable_ips, "Enable IPS (default: true)");
 
+bool i915_fastboot __read_mostly = 0;
+module_param_named(fastboot, i915_fastboot, bool, 0600);
+MODULE_PARM_DESC(fastboot, "Try to skip unnecessary mode sets at boot time "
+                "(default: false)");
+
+bool i915_prefault_disable __read_mostly;
+module_param_named(prefault_disable, i915_prefault_disable, bool, 0600);
+MODULE_PARM_DESC(prefault_disable,
+               "Disable page prefaulting for pread/pwrite/reloc (default:false). For developers only.");
+
 static struct drm_driver driver;
 extern int intel_agp_enabled;
 
@@ -551,7 +565,11 @@ static int i915_drm_freeze(struct drm_device *dev)
 
        /* If KMS is active, we do the leavevt stuff here */
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
-               int error = i915_gem_idle(dev);
+               int error;
+
+               mutex_lock(&dev->struct_mutex);
+               error = i915_gem_idle(dev);
+               mutex_unlock(&dev->struct_mutex);
                if (error) {
                        dev_err(&dev->pdev->dev,
                                "GEM idle failed, resume might fail\n");
@@ -656,7 +674,6 @@ static int __i915_drm_thaw(struct drm_device *dev)
                intel_init_pch_refclk(dev);
 
                mutex_lock(&dev->struct_mutex);
-               dev_priv->mm.suspended = 0;
 
                error = i915_gem_init_hw(dev);
                mutex_unlock(&dev->struct_mutex);
@@ -706,7 +723,7 @@ static int i915_drm_thaw(struct drm_device *dev)
 {
        int error = 0;
 
-       intel_gt_sanitize(dev);
+       intel_uncore_sanitize(dev);
 
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
                mutex_lock(&dev->struct_mutex);
@@ -732,7 +749,7 @@ int i915_resume(struct drm_device *dev)
 
        pci_set_master(dev->pdev);
 
-       intel_gt_sanitize(dev);
+       intel_uncore_sanitize(dev);
 
        /*
         * Platforms with opregion should have sane BIOS, older ones (gen3 and
@@ -753,139 +770,6 @@ int i915_resume(struct drm_device *dev)
        return 0;
 }
 
-static int i8xx_do_reset(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       if (IS_I85X(dev))
-               return -ENODEV;
-
-       I915_WRITE(D_STATE, I915_READ(D_STATE) | DSTATE_GFX_RESET_I830);
-       POSTING_READ(D_STATE);
-
-       if (IS_I830(dev) || IS_845G(dev)) {
-               I915_WRITE(DEBUG_RESET_I830,
-                          DEBUG_RESET_DISPLAY |
-                          DEBUG_RESET_RENDER |
-                          DEBUG_RESET_FULL);
-               POSTING_READ(DEBUG_RESET_I830);
-               msleep(1);
-
-               I915_WRITE(DEBUG_RESET_I830, 0);
-               POSTING_READ(DEBUG_RESET_I830);
-       }
-
-       msleep(1);
-
-       I915_WRITE(D_STATE, I915_READ(D_STATE) & ~DSTATE_GFX_RESET_I830);
-       POSTING_READ(D_STATE);
-
-       return 0;
-}
-
-static int i965_reset_complete(struct drm_device *dev)
-{
-       u8 gdrst;
-       pci_read_config_byte(dev->pdev, I965_GDRST, &gdrst);
-       return (gdrst & GRDOM_RESET_ENABLE) == 0;
-}
-
-static int i965_do_reset(struct drm_device *dev)
-{
-       int ret;
-       u8 gdrst;
-
-       /*
-        * Set the domains we want to reset (GRDOM/bits 2 and 3) as
-        * well as the reset bit (GR/bit 0).  Setting the GR bit
-        * triggers the reset; when done, the hardware will clear it.
-        */
-       pci_read_config_byte(dev->pdev, I965_GDRST, &gdrst);
-       pci_write_config_byte(dev->pdev, I965_GDRST,
-                             gdrst | GRDOM_RENDER |
-                             GRDOM_RESET_ENABLE);
-       ret =  wait_for(i965_reset_complete(dev), 500);
-       if (ret)
-               return ret;
-
-       /* We can't reset render&media without also resetting display ... */
-       pci_read_config_byte(dev->pdev, I965_GDRST, &gdrst);
-       pci_write_config_byte(dev->pdev, I965_GDRST,
-                             gdrst | GRDOM_MEDIA |
-                             GRDOM_RESET_ENABLE);
-
-       return wait_for(i965_reset_complete(dev), 500);
-}
-
-static int ironlake_do_reset(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 gdrst;
-       int ret;
-
-       gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR);
-       gdrst &= ~GRDOM_MASK;
-       I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR,
-                  gdrst | GRDOM_RENDER | GRDOM_RESET_ENABLE);
-       ret = wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500);
-       if (ret)
-               return ret;
-
-       /* We can't reset render&media without also resetting display ... */
-       gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR);
-       gdrst &= ~GRDOM_MASK;
-       I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR,
-                  gdrst | GRDOM_MEDIA | GRDOM_RESET_ENABLE);
-       return wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500);
-}
-
-static int gen6_do_reset(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int     ret;
-       unsigned long irqflags;
-
-       /* Hold gt_lock across reset to prevent any register access
-        * with forcewake not set correctly
-        */
-       spin_lock_irqsave(&dev_priv->gt_lock, irqflags);
-
-       /* Reset the chip */
-
-       /* GEN6_GDRST is not in the gt power well, no need to check
-        * for fifo space for the write or forcewake the chip for
-        * the read
-        */
-       I915_WRITE_NOTRACE(GEN6_GDRST, GEN6_GRDOM_FULL);
-
-       /* Spin waiting for the device to ack the reset request */
-       ret = wait_for((I915_READ_NOTRACE(GEN6_GDRST) & GEN6_GRDOM_FULL) == 0, 500);
-
-       /* If reset with a user forcewake, try to restore, otherwise turn it off */
-       if (dev_priv->forcewake_count)
-               dev_priv->gt.force_wake_get(dev_priv);
-       else
-               dev_priv->gt.force_wake_put(dev_priv);
-
-       /* Restore fifo count */
-       dev_priv->gt_fifo_count = I915_READ_NOTRACE(GT_FIFO_FREE_ENTRIES);
-
-       spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags);
-       return ret;
-}
-
-int intel_gpu_reset(struct drm_device *dev)
-{
-       switch (INTEL_INFO(dev)->gen) {
-       case 7:
-       case 6: return gen6_do_reset(dev);
-       case 5: return ironlake_do_reset(dev);
-       case 4: return i965_do_reset(dev);
-       case 2: return i8xx_do_reset(dev);
-       default: return -ENODEV;
-       }
-}
-
 /**
  * i915_reset - reset chip after a hang
  * @dev: drm device to reset
@@ -955,11 +839,11 @@ int i915_reset(struct drm_device *dev)
         * switched away).
         */
        if (drm_core_check_feature(dev, DRIVER_MODESET) ||
-                       !dev_priv->mm.suspended) {
+                       !dev_priv->ums.mm_suspended) {
                struct intel_ring_buffer *ring;
                int i;
 
-               dev_priv->mm.suspended = 0;
+               dev_priv->ums.mm_suspended = 0;
 
                i915_gem_init_swizzling(dev);
 
@@ -1215,136 +1099,3 @@ module_exit(i915_exit);
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL and additional rights");
-
-/* We give fast paths for the really cool registers */
-#define NEEDS_FORCE_WAKE(dev_priv, reg) \
-       ((HAS_FORCE_WAKE((dev_priv)->dev)) && \
-        ((reg) < 0x40000) &&            \
-        ((reg) != FORCEWAKE))
-static void
-ilk_dummy_write(struct drm_i915_private *dev_priv)
-{
-       /* WaIssueDummyWriteToWakeupFromRC6:ilk Issue a dummy write to wake up
-        * the chip from rc6 before touching it for real. MI_MODE is masked,
-        * hence harmless to write 0 into. */
-       I915_WRITE_NOTRACE(MI_MODE, 0);
-}
-
-static void
-hsw_unclaimed_reg_clear(struct drm_i915_private *dev_priv, u32 reg)
-{
-       if (HAS_FPGA_DBG_UNCLAIMED(dev_priv->dev) &&
-           (I915_READ_NOTRACE(FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) {
-               DRM_ERROR("Unknown unclaimed register before writing to %x\n",
-                         reg);
-               I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
-       }
-}
-
-static void
-hsw_unclaimed_reg_check(struct drm_i915_private *dev_priv, u32 reg)
-{
-       if (HAS_FPGA_DBG_UNCLAIMED(dev_priv->dev) &&
-           (I915_READ_NOTRACE(FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) {
-               DRM_ERROR("Unclaimed write to %x\n", reg);
-               I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
-       }
-}
-
-#define __i915_read(x, y) \
-u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \
-       unsigned long irqflags; \
-       u##x val = 0; \
-       spin_lock_irqsave(&dev_priv->gt_lock, irqflags); \
-       if (IS_GEN5(dev_priv->dev)) \
-               ilk_dummy_write(dev_priv); \
-       if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
-               if (dev_priv->forcewake_count == 0) \
-                       dev_priv->gt.force_wake_get(dev_priv); \
-               val = read##y(dev_priv->regs + reg); \
-               if (dev_priv->forcewake_count == 0) \
-                       dev_priv->gt.force_wake_put(dev_priv); \
-       } else { \
-               val = read##y(dev_priv->regs + reg); \
-       } \
-       spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags); \
-       trace_i915_reg_rw(false, reg, val, sizeof(val)); \
-       return val; \
-}
-
-__i915_read(8, b)
-__i915_read(16, w)
-__i915_read(32, l)
-__i915_read(64, q)
-#undef __i915_read
-
-#define __i915_write(x, y) \
-void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \
-       unsigned long irqflags; \
-       u32 __fifo_ret = 0; \
-       trace_i915_reg_rw(true, reg, val, sizeof(val)); \
-       spin_lock_irqsave(&dev_priv->gt_lock, irqflags); \
-       if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
-               __fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \
-       } \
-       if (IS_GEN5(dev_priv->dev)) \
-               ilk_dummy_write(dev_priv); \
-       hsw_unclaimed_reg_clear(dev_priv, reg); \
-       write##y(val, dev_priv->regs + reg); \
-       if (unlikely(__fifo_ret)) { \
-               gen6_gt_check_fifodbg(dev_priv); \
-       } \
-       hsw_unclaimed_reg_check(dev_priv, reg); \
-       spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags); \
-}
-__i915_write(8, b)
-__i915_write(16, w)
-__i915_write(32, l)
-__i915_write(64, q)
-#undef __i915_write
-
-static const struct register_whitelist {
-       uint64_t offset;
-       uint32_t size;
-       uint32_t gen_bitmask; /* support gens, 0x10 for 4, 0x30 for 4 and 5, etc. */
-} whitelist[] = {
-       { RING_TIMESTAMP(RENDER_RING_BASE), 8, 0xF0 },
-};
-
-int i915_reg_read_ioctl(struct drm_device *dev,
-                       void *data, struct drm_file *file)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_i915_reg_read *reg = data;
-       struct register_whitelist const *entry = whitelist;
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(whitelist); i++, entry++) {
-               if (entry->offset == reg->offset &&
-                   (1 << INTEL_INFO(dev)->gen & entry->gen_bitmask))
-                       break;
-       }
-
-       if (i == ARRAY_SIZE(whitelist))
-               return -EINVAL;
-
-       switch (entry->size) {
-       case 8:
-               reg->val = I915_READ64(reg->offset);
-               break;
-       case 4:
-               reg->val = I915_READ(reg->offset);
-               break;
-       case 2:
-               reg->val = I915_READ16(reg->offset);
-               break;
-       case 1:
-               reg->val = I915_READ8(reg->offset);
-               break;
-       default:
-               WARN_ON(1);
-               return -EINVAL;
-       }
-
-       return 0;
-}
index d2ee3343c9439cbcf306ce443b9fbe57e53e534a..f31a1b0adbda96c4218b16d8823eab13b620a344 100644 (file)
@@ -144,6 +144,7 @@ enum intel_dpll_id {
 
 struct intel_dpll_hw_state {
        uint32_t dpll;
+       uint32_t dpll_md;
        uint32_t fp0;
        uint32_t fp1;
 };
@@ -156,6 +157,8 @@ struct intel_shared_dpll {
        /* should match the index in the dev_priv->shared_dplls array */
        enum intel_dpll_id id;
        struct intel_dpll_hw_state hw_state;
+       void (*mode_set)(struct drm_i915_private *dev_priv,
+                        struct intel_shared_dpll *pll);
        void (*enable)(struct drm_i915_private *dev_priv,
                       struct intel_shared_dpll *pll);
        void (*disable)(struct drm_i915_private *dev_priv,
@@ -364,6 +367,7 @@ struct drm_i915_display_funcs {
         * fills out the pipe-config with the hw state. */
        bool (*get_pipe_config)(struct intel_crtc *,
                                struct intel_crtc_config *);
+       void (*get_clock)(struct intel_crtc *, struct intel_crtc_config *);
        int (*crtc_mode_set)(struct drm_crtc *crtc,
                             int x, int y,
                             struct drm_framebuffer *old_fb);
@@ -387,11 +391,20 @@ struct drm_i915_display_funcs {
        /* pll clock increase/decrease */
 };
 
-struct drm_i915_gt_funcs {
+struct intel_uncore_funcs {
        void (*force_wake_get)(struct drm_i915_private *dev_priv);
        void (*force_wake_put)(struct drm_i915_private *dev_priv);
 };
 
+struct intel_uncore {
+       spinlock_t lock; /** lock is also taken in irq contexts. */
+
+       struct intel_uncore_funcs funcs;
+
+       unsigned fifo_count;
+       unsigned forcewake_count;
+};
+
 #define DEV_INFO_FOR_EACH_FLAG(func, sep) \
        func(is_mobile) sep \
        func(is_i85x) sep \
@@ -442,6 +455,54 @@ enum i915_cache_level {
 
 typedef uint32_t gen6_gtt_pte_t;
 
+struct i915_address_space {
+       struct drm_mm mm;
+       struct drm_device *dev;
+       struct list_head global_link;
+       unsigned long start;            /* Start offset always 0 for dri2 */
+       size_t total;           /* size addr space maps (ex. 2GB for ggtt) */
+
+       struct {
+               dma_addr_t addr;
+               struct page *page;
+       } scratch;
+
+       /**
+        * List of objects currently involved in rendering.
+        *
+        * Includes buffers having the contents of their GPU caches
+        * flushed, not necessarily primitives.  last_rendering_seqno
+        * represents when the rendering involved will be completed.
+        *
+        * A reference is held on the buffer while on this list.
+        */
+       struct list_head active_list;
+
+       /**
+        * LRU list of objects which are not in the ringbuffer and
+        * are ready to unbind, but are still in the GTT.
+        *
+        * last_rendering_seqno is 0 while an object is in this list.
+        *
+        * A reference is not held on the buffer while on this list,
+        * as merely being GTT-bound shouldn't prevent its being
+        * freed, and we'll pull it off the list in the free path.
+        */
+       struct list_head inactive_list;
+
+       /* FIXME: Need a more generic return type */
+       gen6_gtt_pte_t (*pte_encode)(dma_addr_t addr,
+                                    enum i915_cache_level level);
+       void (*clear_range)(struct i915_address_space *vm,
+                           unsigned int first_entry,
+                           unsigned int num_entries);
+       void (*insert_entries)(struct i915_address_space *vm,
+                              struct sg_table *st,
+                              unsigned int first_entry,
+                              enum i915_cache_level cache_level);
+       void (*cleanup)(struct i915_address_space *vm);
+};
+
 /* The Graphics Translation Table is the way in which GEN hardware translates a
  * Graphics Virtual Address into a Physical Address. In addition to the normal
  * collateral associated with any va->pa translations GEN hardware also has a
@@ -450,8 +511,7 @@ typedef uint32_t gen6_gtt_pte_t;
  * the spec.
  */
 struct i915_gtt {
-       unsigned long start;            /* Start offset of used GTT */
-       size_t total;                   /* Total size GTT can map */
+       struct i915_address_space base;
        size_t stolen_size;             /* Total size of stolen memory */
 
        unsigned long mappable_end;     /* End offset that we can CPU map */
@@ -462,50 +522,35 @@ struct i915_gtt {
        void __iomem *gsm;
 
        bool do_idle_maps;
-       dma_addr_t scratch_page_dma;
-       struct page *scratch_page;
+
+       int mtrr;
 
        /* global gtt ops */
        int (*gtt_probe)(struct drm_device *dev, size_t *gtt_total,
                          size_t *stolen, phys_addr_t *mappable_base,
                          unsigned long *mappable_end);
-       void (*gtt_remove)(struct drm_device *dev);
-       void (*gtt_clear_range)(struct drm_device *dev,
-                               unsigned int first_entry,
-                               unsigned int num_entries);
-       void (*gtt_insert_entries)(struct drm_device *dev,
-                                  struct sg_table *st,
-                                  unsigned int pg_start,
-                                  enum i915_cache_level cache_level);
-       gen6_gtt_pte_t (*pte_encode)(struct drm_device *dev,
-                                    dma_addr_t addr,
-                                    enum i915_cache_level level);
 };
-#define gtt_total_entries(gtt) ((gtt).total >> PAGE_SHIFT)
+#define gtt_total_entries(gtt) ((gtt).base.total >> PAGE_SHIFT)
 
-#define I915_PPGTT_PD_ENTRIES 512
-#define I915_PPGTT_PT_ENTRIES 1024
 struct i915_hw_ppgtt {
-       struct drm_device *dev;
+       struct i915_address_space base;
        unsigned num_pd_entries;
        struct page **pt_pages;
        uint32_t pd_offset;
        dma_addr_t *pt_dma_addr;
-       dma_addr_t scratch_page_dma_addr;
 
-       /* pte functions, mirroring the interface of the global gtt. */
-       void (*clear_range)(struct i915_hw_ppgtt *ppgtt,
-                           unsigned int first_entry,
-                           unsigned int num_entries);
-       void (*insert_entries)(struct i915_hw_ppgtt *ppgtt,
-                              struct sg_table *st,
-                              unsigned int pg_start,
-                              enum i915_cache_level cache_level);
-       gen6_gtt_pte_t (*pte_encode)(struct drm_device *dev,
-                                    dma_addr_t addr,
-                                    enum i915_cache_level level);
        int (*enable)(struct drm_device *dev);
-       void (*cleanup)(struct i915_hw_ppgtt *ppgtt);
+};
+
+/* To make things as simple as possible (ie. no refcounting), a VMA's lifetime
+ * will always be <= an objects lifetime. So object refcounting should cover us.
+ */
+struct i915_vma {
+       struct drm_mm_node node;
+       struct drm_i915_gem_object *obj;
+       struct i915_address_space *vm;
+
+       struct list_head vma_link; /* Link in the object's VMA list */
 };
 
 struct i915_ctx_hang_stats {
@@ -528,15 +573,46 @@ struct i915_hw_context {
        struct i915_ctx_hang_stats hang_stats;
 };
 
-enum no_fbc_reason {
-       FBC_NO_OUTPUT, /* no outputs enabled to compress */
-       FBC_STOLEN_TOO_SMALL, /* not enough space to hold compressed buffers */
-       FBC_UNSUPPORTED_MODE, /* interlace or doublescanned mode */
-       FBC_MODE_TOO_LARGE, /* mode too large for compression */
-       FBC_BAD_PLANE, /* fbc not supported on plane */
-       FBC_NOT_TILED, /* buffer not tiled */
-       FBC_MULTIPLE_PIPES, /* more than one pipe active */
-       FBC_MODULE_PARAM,
+struct i915_fbc {
+       unsigned long size;
+       unsigned int fb_id;
+       enum plane plane;
+       int y;
+
+       struct drm_mm_node *compressed_fb;
+       struct drm_mm_node *compressed_llb;
+
+       struct intel_fbc_work {
+               struct delayed_work work;
+               struct drm_crtc *crtc;
+               struct drm_framebuffer *fb;
+               int interval;
+       } *fbc_work;
+
+       enum {
+               FBC_NO_OUTPUT, /* no outputs enabled to compress */
+               FBC_STOLEN_TOO_SMALL, /* not enough space for buffers */
+               FBC_UNSUPPORTED_MODE, /* interlace or doublescanned mode */
+               FBC_MODE_TOO_LARGE, /* mode too large for compression */
+               FBC_BAD_PLANE, /* fbc not supported on plane */
+               FBC_NOT_TILED, /* buffer not tiled */
+               FBC_MULTIPLE_PIPES, /* more than one pipe active */
+               FBC_MODULE_PARAM,
+               FBC_CHIP_DEFAULT, /* disabled by default on this chip */
+       } no_fbc_reason;
+};
+
+enum no_psr_reason {
+       PSR_NO_SOURCE, /* Not supported on platform */
+       PSR_NO_SINK, /* Not supported by panel */
+       PSR_MODULE_PARAM,
+       PSR_CRTC_NOT_ACTIVE,
+       PSR_PWR_WELL_ENABLED,
+       PSR_NOT_TILED,
+       PSR_SPRITE_ENABLED,
+       PSR_S3D_ENABLED,
+       PSR_INTERLACED_ENABLED,
+       PSR_HSW_NOT_DDIA,
 };
 
 enum intel_pch {
@@ -722,12 +798,12 @@ struct i915_suspend_saved_registers {
 };
 
 struct intel_gen6_power_mgmt {
+       /* work and pm_iir are protected by dev_priv->irq_lock */
        struct work_struct work;
-       struct delayed_work vlv_work;
        u32 pm_iir;
-       /* lock - irqsave spinlock that protectects the work_struct and
-        * pm_iir. */
-       spinlock_t lock;
+
+       /* On vlv we need to manually drop to Vmin with a delayed work. */
+       struct delayed_work vlv_work;
 
        /* The below variables an all the rps hw state are protected by
         * dev->struct mutext. */
@@ -793,6 +869,18 @@ struct i915_dri1_state {
        uint32_t counter;
 };
 
+struct i915_ums_state {
+       /**
+        * Flag if the X Server, and thus DRM, is not currently in
+        * control of the device.
+        *
+        * This is set between LeaveVT and EnterVT.  It needs to be
+        * replaced with a semaphore.  It also needs to be
+        * transitioned away from for kernel modesetting.
+        */
+       int mm_suspended;
+};
+
 struct intel_l3_parity {
        u32 *remap_info;
        struct work_struct error_work;
@@ -801,8 +889,6 @@ struct intel_l3_parity {
 struct i915_gem_mm {
        /** Memory allocator for GTT stolen memory */
        struct drm_mm stolen;
-       /** Memory allocator for GTT */
-       struct drm_mm gtt_space;
        /** List of all objects in gtt_space. Used to restore gtt
         * mappings on resume */
        struct list_head bound_list;
@@ -816,37 +902,12 @@ struct i915_gem_mm {
        /** Usable portion of the GTT for GEM */
        unsigned long stolen_base; /* limited to low memory (32-bit) */
 
-       int gtt_mtrr;
-
        /** PPGTT used for aliasing the PPGTT with the GTT */
        struct i915_hw_ppgtt *aliasing_ppgtt;
 
        struct shrinker inactive_shrinker;
        bool shrinker_no_lock_stealing;
 
-       /**
-        * List of objects currently involved in rendering.
-        *
-        * Includes buffers having the contents of their GPU caches
-        * flushed, not necessarily primitives.  last_rendering_seqno
-        * represents when the rendering involved will be completed.
-        *
-        * A reference is held on the buffer while on this list.
-        */
-       struct list_head active_list;
-
-       /**
-        * LRU list of objects which are not in the ringbuffer and
-        * are ready to unbind, but are still in the GTT.
-        *
-        * last_rendering_seqno is 0 while an object is in this list.
-        *
-        * A reference is not held on the buffer while on this list,
-        * as merely being GTT-bound shouldn't prevent its being
-        * freed, and we'll pull it off the list in the free path.
-        */
-       struct list_head inactive_list;
-
        /** LRU list of objects with fence regs on them. */
        struct list_head fence_list;
 
@@ -865,16 +926,6 @@ struct i915_gem_mm {
         */
        bool interruptible;
 
-       /**
-        * Flag if the X Server, and thus DRM, is not currently in
-        * control of the device.
-        *
-        * This is set between LeaveVT and EnterVT.  It needs to be
-        * replaced with a semaphore.  It also needs to be
-        * transitioned away from for kernel modesetting.
-        */
-       int suspended;
-
        /** Bit 6 swizzling required for X tiling */
        uint32_t bit_6_swizzle_x;
        /** Bit 6 swizzling required for Y tiling */
@@ -884,6 +935,7 @@ struct i915_gem_mm {
        struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT];
 
        /* accounting, useful for userland debugging */
+       spinlock_t object_stat_lock;
        size_t object_memory;
        u32 object_count;
 };
@@ -897,6 +949,11 @@ struct drm_i915_error_state_buf {
        loff_t pos;
 };
 
+struct i915_error_state_file_priv {
+       struct drm_device *dev;
+       struct drm_i915_error_state *error;
+};
+
 struct i915_gpu_error {
        /* For hangcheck timer */
 #define DRM_I915_HANGCHECK_PERIOD 1500 /* in ms */
@@ -998,14 +1055,7 @@ typedef struct drm_i915_private {
 
        void __iomem *regs;
 
-       struct drm_i915_gt_funcs gt;
-       /** gt_fifo_count and the subsequent register write are synchronized
-        * with dev->struct_mutex. */
-       unsigned gt_fifo_count;
-       /** forcewake_count is protected by gt_lock */
-       unsigned forcewake_count;
-       /** gt_lock is also taken in irq contexts. */
-       spinlock_t gt_lock;
+       struct intel_uncore uncore;
 
        struct intel_gmbus gmbus[GMBUS_NUM_PORTS];
 
@@ -1059,12 +1109,7 @@ typedef struct drm_i915_private {
 
        int num_plane;
 
-       unsigned long cfb_size;
-       unsigned int cfb_fb;
-       enum plane cfb_plane;
-       int cfb_y;
-       struct intel_fbc_work *fbc_work;
-
+       struct i915_fbc fbc;
        struct intel_opregion opregion;
        struct intel_vbt_data vbt;
 
@@ -1081,8 +1126,6 @@ typedef struct drm_i915_private {
        } backlight;
 
        /* LVDS info */
-       struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */
-       struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */
        bool no_aux_handshake;
 
        struct drm_i915_fence_reg fence_regs[I915_MAX_NUM_FENCES]; /* assume 965 */
@@ -1105,7 +1148,8 @@ typedef struct drm_i915_private {
        enum modeset_restore modeset_restore;
        struct mutex modeset_restore_lock;
 
-       struct i915_gtt gtt;
+       struct list_head vm_list; /* Global list of all address spaces */
+       struct i915_gtt gtt; /* VMA representing the global address space */
 
        struct i915_gem_mm mm;
 
@@ -1132,6 +1176,9 @@ typedef struct drm_i915_private {
 
        struct intel_l3_parity l3_parity;
 
+       /* Cannot be determined by PCIID. You must always read a register. */
+       size_t ellc_size;
+
        /* gen6+ rps state */
        struct intel_gen6_power_mgmt rps;
 
@@ -1142,10 +1189,7 @@ typedef struct drm_i915_private {
        /* Haswell power well */
        struct i915_power_well power_well;
 
-       enum no_fbc_reason no_fbc_reason;
-
-       struct drm_mm_node *compressed_fb;
-       struct drm_mm_node *compressed_llb;
+       enum no_psr_reason no_psr_reason;
 
        struct i915_gpu_error gpu_error;
 
@@ -1173,6 +1217,8 @@ typedef struct drm_i915_private {
        /* Old dri1 support infrastructure, beware the dragons ya fools entering
         * here! */
        struct i915_dri1_state dri1;
+       /* Old ums support infrastructure, same warning applies. */
+       struct i915_ums_state ums;
 } drm_i915_private_t;
 
 /* Iterate over initialised rings */
@@ -1187,7 +1233,7 @@ enum hdmi_force_audio {
        HDMI_AUDIO_ON,                  /* force turn on HDMI audio */
 };
 
-#define I915_GTT_RESERVED ((struct drm_mm_node *)0x1)
+#define I915_GTT_OFFSET_NONE ((u32)-1)
 
 struct drm_i915_gem_object_ops {
        /* Interface between the GEM object and its backing storage.
@@ -1212,8 +1258,9 @@ struct drm_i915_gem_object {
 
        const struct drm_i915_gem_object_ops *ops;
 
-       /** Current space allocated to this object in the GTT, if any. */
-       struct drm_mm_node *gtt_space;
+       /** List of VMAs backed by this object */
+       struct list_head vma_list;
+
        /** Stolen memory for this object, instead of being backed by shmem. */
        struct drm_mm_node *stolen;
        struct list_head global_list;
@@ -1314,13 +1361,6 @@ struct drm_i915_gem_object {
        unsigned long exec_handle;
        struct drm_i915_gem_exec_object2 *exec_entry;
 
-       /**
-        * Current offset of the object in GTT space.
-        *
-        * This is the same as gtt_space->start
-        */
-       uint32_t gtt_offset;
-
        struct intel_ring_buffer *ring;
 
        /** Breadcrumb of last rendering to the buffer. */
@@ -1346,6 +1386,52 @@ struct drm_i915_gem_object {
 
 #define to_intel_bo(x) container_of(x, struct drm_i915_gem_object, base)
 
+/* This is a temporary define to help transition us to real VMAs. If you see
+ * this, you're either reviewing code, or bisecting it. */
+static inline struct i915_vma *
+__i915_gem_obj_to_vma(struct drm_i915_gem_object *obj)
+{
+       if (list_empty(&obj->vma_list))
+               return NULL;
+       return list_first_entry(&obj->vma_list, struct i915_vma, vma_link);
+}
+
+/* Whether or not this object is currently mapped by the translation tables */
+static inline bool
+i915_gem_obj_ggtt_bound(struct drm_i915_gem_object *o)
+{
+       struct i915_vma *vma = __i915_gem_obj_to_vma(o);
+       if (vma == NULL)
+               return false;
+       return drm_mm_node_allocated(&vma->node);
+}
+
+/* Offset of the first PTE pointing to this object */
+static inline unsigned long
+i915_gem_obj_ggtt_offset(struct drm_i915_gem_object *o)
+{
+       BUG_ON(list_empty(&o->vma_list));
+       return __i915_gem_obj_to_vma(o)->node.start;
+}
+
+/* The size used in the translation tables may be larger than the actual size of
+ * the object on GEN2/GEN3 because of the way tiling is handled. See
+ * i915_gem_get_gtt_size() for more details.
+ */
+static inline unsigned long
+i915_gem_obj_ggtt_size(struct drm_i915_gem_object *o)
+{
+       BUG_ON(list_empty(&o->vma_list));
+       return __i915_gem_obj_to_vma(o)->node.size;
+}
+
+static inline void
+i915_gem_obj_ggtt_set_color(struct drm_i915_gem_object *o,
+                           enum i915_cache_level color)
+{
+       __i915_gem_obj_to_vma(o)->node.color = color;
+}
+
 /**
  * Request queue structure.
  *
@@ -1540,9 +1626,12 @@ extern int i915_enable_rc6 __read_mostly;
 extern int i915_enable_fbc __read_mostly;
 extern bool i915_enable_hangcheck __read_mostly;
 extern int i915_enable_ppgtt __read_mostly;
+extern int i915_enable_psr __read_mostly;
 extern unsigned int i915_preliminary_hw_support __read_mostly;
 extern int i915_disable_power_well __read_mostly;
 extern int i915_enable_ips __read_mostly;
+extern bool i915_fastboot __read_mostly;
+extern bool i915_prefault_disable __read_mostly;
 
 extern int i915_suspend(struct drm_device *dev, pm_message_t state);
 extern int i915_resume(struct drm_device *dev);
@@ -1578,15 +1667,21 @@ extern void i915_update_gfx_val(struct drm_i915_private *dev_priv);
 extern void intel_console_resume(struct work_struct *work);
 
 /* i915_irq.c */
+void i915_queue_hangcheck(struct drm_device *dev);
 void i915_hangcheck_elapsed(unsigned long data);
 void i915_handle_error(struct drm_device *dev, bool wedged);
 
 extern void intel_irq_init(struct drm_device *dev);
+extern void intel_pm_init(struct drm_device *dev);
 extern void intel_hpd_init(struct drm_device *dev);
-extern void intel_gt_init(struct drm_device *dev);
-extern void intel_gt_sanitize(struct drm_device *dev);
+extern void intel_pm_init(struct drm_device *dev);
 
-void i915_error_state_free(struct kref *error_ref);
+extern void intel_uncore_sanitize(struct drm_device *dev);
+extern void intel_uncore_early_sanitize(struct drm_device *dev);
+extern void intel_uncore_init(struct drm_device *dev);
+extern void intel_uncore_reset(struct drm_device *dev);
+extern void intel_uncore_clear_errors(struct drm_device *dev);
+extern void intel_uncore_check_errors(struct drm_device *dev);
 
 void
 i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask);
@@ -1594,13 +1689,6 @@ i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask);
 void
 i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask);
 
-#ifdef CONFIG_DEBUG_FS
-extern void i915_destroy_error_state(struct drm_device *dev);
-#else
-#define i915_destroy_error_state(x)
-#endif
-
-
 /* i915_gem.c */
 int i915_gem_init_ioctl(struct drm_device *dev, void *data,
                        struct drm_file *file_priv);
@@ -1657,6 +1745,9 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj,
 struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev,
                                                  size_t size);
 void i915_gem_free_object(struct drm_gem_object *obj);
+struct i915_vma *i915_gem_vma_create(struct drm_i915_gem_object *obj,
+                                    struct i915_address_space *vm);
+void i915_gem_vma_destroy(struct i915_vma *vma);
 
 int __must_check i915_gem_object_pin(struct drm_i915_gem_object *obj,
                                     uint32_t alignment,
@@ -1827,7 +1918,7 @@ static inline void i915_gem_context_unreference(struct i915_hw_context *ctx)
 }
 
 struct i915_ctx_hang_stats * __must_check
-i915_gem_context_get_hang_stats(struct intel_ring_buffer *ring,
+i915_gem_context_get_hang_stats(struct drm_device *dev,
                                struct drm_file *file,
                                u32 id);
 int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
@@ -1911,8 +2002,27 @@ void i915_gem_dump_object(struct drm_i915_gem_object *obj, int len,
 /* i915_debugfs.c */
 int i915_debugfs_init(struct drm_minor *minor);
 void i915_debugfs_cleanup(struct drm_minor *minor);
+
+/* i915_gpu_error.c */
 __printf(2, 3)
 void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...);
+int i915_error_state_to_str(struct drm_i915_error_state_buf *estr,
+                           const struct i915_error_state_file_priv *error);
+int i915_error_state_buf_init(struct drm_i915_error_state_buf *eb,
+                             size_t count, loff_t pos);
+static inline void i915_error_state_buf_release(
+       struct drm_i915_error_state_buf *eb)
+{
+       kfree(eb->buf);
+}
+void i915_capture_error_state(struct drm_device *dev);
+void i915_error_state_get(struct drm_device *dev,
+                         struct i915_error_state_file_priv *error_priv);
+void i915_error_state_put(struct i915_error_state_file_priv *error_priv);
+void i915_destroy_error_state(struct drm_device *dev);
+
+void i915_get_extra_instdone(struct drm_device *dev, uint32_t *instdone);
+const char *i915_cache_level_str(int type);
 
 /* i915_suspend.c */
 extern int i915_save_state(struct drm_device *dev);
@@ -1992,7 +2102,6 @@ int i915_reg_read_ioctl(struct drm_device *dev, void *data,
                        struct drm_file *file);
 
 /* overlay */
-#ifdef CONFIG_DEBUG_FS
 extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev);
 extern void intel_overlay_print_error_state(struct drm_i915_error_state_buf *e,
                                            struct intel_overlay_error_state *error);
@@ -2001,7 +2110,6 @@ extern struct intel_display_error_state *intel_display_capture_error_state(struc
 extern void intel_display_print_error_state(struct drm_i915_error_state_buf *e,
                                            struct drm_device *dev,
                                            struct intel_display_error_state *error);
-#endif
 
 /* On SNB platform, before reading ring registers forcewake bit
  * must be set to prevent GT core from power down and stale values being
@@ -2009,7 +2117,6 @@ extern void intel_display_print_error_state(struct drm_i915_error_state_buf *e,
  */
 void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv);
 void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv);
-int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv);
 
 int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u8 mbox, u32 *val);
 int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val);
@@ -2028,39 +2135,37 @@ void intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value,
 int vlv_gpu_freq(int ddr_freq, int val);
 int vlv_freq_opcode(int ddr_freq, int val);
 
-#define __i915_read(x, y) \
-       u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg);
-
-__i915_read(8, b)
-__i915_read(16, w)
-__i915_read(32, l)
-__i915_read(64, q)
+#define __i915_read(x) \
+       u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg, bool trace);
+__i915_read(8)
+__i915_read(16)
+__i915_read(32)
+__i915_read(64)
 #undef __i915_read
 
-#define __i915_write(x, y) \
-       void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val);
-
-__i915_write(8, b)
-__i915_write(16, w)
-__i915_write(32, l)
-__i915_write(64, q)
+#define __i915_write(x) \
+       void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val, bool trace);
+__i915_write(8)
+__i915_write(16)
+__i915_write(32)
+__i915_write(64)
 #undef __i915_write
 
-#define I915_READ8(reg)                i915_read8(dev_priv, (reg))
-#define I915_WRITE8(reg, val)  i915_write8(dev_priv, (reg), (val))
+#define I915_READ8(reg)                i915_read8(dev_priv, (reg), true)
+#define I915_WRITE8(reg, val)  i915_write8(dev_priv, (reg), (val), true)
 
-#define I915_READ16(reg)       i915_read16(dev_priv, (reg))
-#define I915_WRITE16(reg, val) i915_write16(dev_priv, (reg), (val))
-#define I915_READ16_NOTRACE(reg)       readw(dev_priv->regs + (reg))
-#define I915_WRITE16_NOTRACE(reg, val) writew(val, dev_priv->regs + (reg))
+#define I915_READ16(reg)       i915_read16(dev_priv, (reg), true)
+#define I915_WRITE16(reg, val) i915_write16(dev_priv, (reg), (val), true)
+#define I915_READ16_NOTRACE(reg)       i915_read16(dev_priv, (reg), false)
+#define I915_WRITE16_NOTRACE(reg, val) i915_write16(dev_priv, (reg), (val), false)
 
-#define I915_READ(reg)         i915_read32(dev_priv, (reg))
-#define I915_WRITE(reg, val)   i915_write32(dev_priv, (reg), (val))
-#define I915_READ_NOTRACE(reg)         readl(dev_priv->regs + (reg))
-#define I915_WRITE_NOTRACE(reg, val)   writel(val, dev_priv->regs + (reg))
+#define I915_READ(reg)         i915_read32(dev_priv, (reg), true)
+#define I915_WRITE(reg, val)   i915_write32(dev_priv, (reg), (val), true)
+#define I915_READ_NOTRACE(reg)         i915_read32(dev_priv, (reg), false)
+#define I915_WRITE_NOTRACE(reg, val)   i915_write32(dev_priv, (reg), (val), false)
 
-#define I915_WRITE64(reg, val) i915_write64(dev_priv, (reg), (val))
-#define I915_READ64(reg)       i915_read64(dev_priv, (reg))
+#define I915_WRITE64(reg, val) i915_write64(dev_priv, (reg), (val), true)
+#define I915_READ64(reg)       i915_read64(dev_priv, (reg), true)
 
 #define POSTING_READ(reg)      (void)I915_READ_NOTRACE(reg)
 #define POSTING_READ16(reg)    (void)I915_READ16_NOTRACE(reg)
index d9e2208cfe98f2fdcb3957bf4ee13f0497e06dfb..3a5d4baa4c536b2cf285adc1ced00198992b3eca 100644 (file)
@@ -26,6 +26,7 @@
  */
 
 #include <drm/drmP.h>
+#include <drm/drm_vma_manager.h>
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
 #include "i915_trace.h"
@@ -75,15 +76,19 @@ static inline void i915_gem_object_fence_lost(struct drm_i915_gem_object *obj)
 static void i915_gem_info_add_obj(struct drm_i915_private *dev_priv,
                                  size_t size)
 {
+       spin_lock(&dev_priv->mm.object_stat_lock);
        dev_priv->mm.object_count++;
        dev_priv->mm.object_memory += size;
+       spin_unlock(&dev_priv->mm.object_stat_lock);
 }
 
 static void i915_gem_info_remove_obj(struct drm_i915_private *dev_priv,
                                     size_t size)
 {
+       spin_lock(&dev_priv->mm.object_stat_lock);
        dev_priv->mm.object_count--;
        dev_priv->mm.object_memory -= size;
+       spin_unlock(&dev_priv->mm.object_stat_lock);
 }
 
 static int
@@ -135,7 +140,7 @@ int i915_mutex_lock_interruptible(struct drm_device *dev)
 static inline bool
 i915_gem_object_is_inactive(struct drm_i915_gem_object *obj)
 {
-       return obj->gtt_space && !obj->active;
+       return i915_gem_obj_ggtt_bound(obj) && !obj->active;
 }
 
 int
@@ -178,10 +183,10 @@ i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
        mutex_lock(&dev->struct_mutex);
        list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list)
                if (obj->pin_count)
-                       pinned += obj->gtt_space->size;
+                       pinned += i915_gem_obj_ggtt_size(obj);
        mutex_unlock(&dev->struct_mutex);
 
-       args->aper_size = dev_priv->gtt.total;
+       args->aper_size = dev_priv->gtt.base.total;
        args->aper_available_size = args->aper_size - pinned;
 
        return 0;
@@ -219,16 +224,10 @@ i915_gem_create(struct drm_file *file,
                return -ENOMEM;
 
        ret = drm_gem_handle_create(file, &obj->base, &handle);
-       if (ret) {
-               drm_gem_object_release(&obj->base);
-               i915_gem_info_remove_obj(dev->dev_private, obj->base.size);
-               i915_gem_object_free(obj);
-               return ret;
-       }
-
        /* drop reference from allocate - handle holds it now */
-       drm_gem_object_unreference(&obj->base);
-       trace_i915_gem_object_create(obj);
+       drm_gem_object_unreference_unlocked(&obj->base);
+       if (ret)
+               return ret;
 
        *handle_p = handle;
        return 0;
@@ -422,7 +421,7 @@ i915_gem_shmem_pread(struct drm_device *dev,
                 * anyway again before the next pread happens. */
                if (obj->cache_level == I915_CACHE_NONE)
                        needs_clflush = 1;
-               if (obj->gtt_space) {
+               if (i915_gem_obj_ggtt_bound(obj)) {
                        ret = i915_gem_object_set_to_gtt_domain(obj, false);
                        if (ret)
                                return ret;
@@ -465,7 +464,7 @@ i915_gem_shmem_pread(struct drm_device *dev,
 
                mutex_unlock(&dev->struct_mutex);
 
-               if (!prefaulted) {
+               if (likely(!i915_prefault_disable) && !prefaulted) {
                        ret = fault_in_multipages_writeable(user_data, remain);
                        /* Userspace is tricking us, but we've already clobbered
                         * its pages with the prefault and promised to write the
@@ -609,7 +608,7 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev,
        user_data = to_user_ptr(args->data_ptr);
        remain = args->size;
 
-       offset = obj->gtt_offset + args->offset;
+       offset = i915_gem_obj_ggtt_offset(obj) + args->offset;
 
        while (remain > 0) {
                /* Operation in this page
@@ -739,7 +738,7 @@ i915_gem_shmem_pwrite(struct drm_device *dev,
                 * right away and we therefore have to clflush anyway. */
                if (obj->cache_level == I915_CACHE_NONE)
                        needs_clflush_after = 1;
-               if (obj->gtt_space) {
+               if (i915_gem_obj_ggtt_bound(obj)) {
                        ret = i915_gem_object_set_to_gtt_domain(obj, true);
                        if (ret)
                                return ret;
@@ -860,10 +859,12 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
                       args->size))
                return -EFAULT;
 
-       ret = fault_in_multipages_readable(to_user_ptr(args->data_ptr),
-                                          args->size);
-       if (ret)
-               return -EFAULT;
+       if (likely(!i915_prefault_disable)) {
+               ret = fault_in_multipages_readable(to_user_ptr(args->data_ptr),
+                                                  args->size);
+               if (ret)
+                       return -EFAULT;
+       }
 
        ret = i915_mutex_lock_interruptible(dev);
        if (ret)
@@ -1360,8 +1361,9 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 
        obj->fault_mappable = true;
 
-       pfn = ((dev_priv->gtt.mappable_base + obj->gtt_offset) >> PAGE_SHIFT) +
-               page_offset;
+       pfn = dev_priv->gtt.mappable_base + i915_gem_obj_ggtt_offset(obj);
+       pfn >>= PAGE_SHIFT;
+       pfn += page_offset;
 
        /* Finally, remap it using the new GTT offset */
        ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn);
@@ -1425,11 +1427,7 @@ i915_gem_release_mmap(struct drm_i915_gem_object *obj)
        if (!obj->fault_mappable)
                return;
 
-       if (obj->base.dev->dev_mapping)
-               unmap_mapping_range(obj->base.dev->dev_mapping,
-                                   (loff_t)obj->base.map_list.hash.key<<PAGE_SHIFT,
-                                   obj->base.size, 1);
-
+       drm_vma_node_unmap(&obj->base.vma_node, obj->base.dev->dev_mapping);
        obj->fault_mappable = false;
 }
 
@@ -1485,7 +1483,7 @@ static int i915_gem_object_create_mmap_offset(struct drm_i915_gem_object *obj)
        struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
        int ret;
 
-       if (obj->base.map_list.map)
+       if (drm_vma_node_has_offset(&obj->base.vma_node))
                return 0;
 
        dev_priv->mm.shrinker_no_lock_stealing = true;
@@ -1516,9 +1514,6 @@ out:
 
 static void i915_gem_object_free_mmap_offset(struct drm_i915_gem_object *obj)
 {
-       if (!obj->base.map_list.map)
-               return;
-
        drm_gem_free_mmap_offset(&obj->base);
 }
 
@@ -1557,7 +1552,7 @@ i915_gem_mmap_gtt(struct drm_file *file,
        if (ret)
                goto out;
 
-       *offset = (u64)obj->base.map_list.hash.key << PAGE_SHIFT;
+       *offset = drm_vma_node_offset_addr(&obj->base.vma_node);
 
 out:
        drm_gem_object_unreference(&obj->base);
@@ -1667,7 +1662,7 @@ i915_gem_object_put_pages(struct drm_i915_gem_object *obj)
        if (obj->pages == NULL)
                return 0;
 
-       BUG_ON(obj->gtt_space);
+       BUG_ON(i915_gem_obj_ggtt_bound(obj));
 
        if (obj->pages_pin_count)
                return -EBUSY;
@@ -1691,6 +1686,7 @@ __i915_gem_shrink(struct drm_i915_private *dev_priv, long target,
                  bool purgeable_only)
 {
        struct drm_i915_gem_object *obj, *next;
+       struct i915_address_space *vm = &dev_priv->gtt.base;
        long count = 0;
 
        list_for_each_entry_safe(obj, next,
@@ -1704,9 +1700,7 @@ __i915_gem_shrink(struct drm_i915_private *dev_priv, long target,
                }
        }
 
-       list_for_each_entry_safe(obj, next,
-                                &dev_priv->mm.inactive_list,
-                                mm_list) {
+       list_for_each_entry_safe(obj, next, &vm->inactive_list, mm_list) {
                if ((i915_gem_object_is_purgeable(obj) || !purgeable_only) &&
                    i915_gem_object_unbind(obj) == 0 &&
                    i915_gem_object_put_pages(obj) == 0) {
@@ -1877,6 +1871,7 @@ i915_gem_object_move_to_active(struct drm_i915_gem_object *obj,
 {
        struct drm_device *dev = obj->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       struct i915_address_space *vm = &dev_priv->gtt.base;
        u32 seqno = intel_ring_get_seqno(ring);
 
        BUG_ON(ring == NULL);
@@ -1893,7 +1888,7 @@ i915_gem_object_move_to_active(struct drm_i915_gem_object *obj,
        }
 
        /* Move from whatever list we were on to the tail of execution. */
-       list_move_tail(&obj->mm_list, &dev_priv->mm.active_list);
+       list_move_tail(&obj->mm_list, &vm->active_list);
        list_move_tail(&obj->ring_list, &ring->active_list);
 
        obj->last_read_seqno = seqno;
@@ -1917,11 +1912,12 @@ i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj)
 {
        struct drm_device *dev = obj->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       struct i915_address_space *vm = &dev_priv->gtt.base;
 
        BUG_ON(obj->base.write_domain & ~I915_GEM_GPU_DOMAINS);
        BUG_ON(!obj->active);
 
-       list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list);
+       list_move_tail(&obj->mm_list, &vm->inactive_list);
 
        list_del_init(&obj->ring_list);
        obj->ring = NULL;
@@ -2085,11 +2081,9 @@ int __i915_add_request(struct intel_ring_buffer *ring,
        trace_i915_gem_request_add(ring, request->seqno);
        ring->outstanding_lazy_request = 0;
 
-       if (!dev_priv->mm.suspended) {
-               if (i915_enable_hangcheck) {
-                       mod_timer(&dev_priv->gpu_error.hangcheck_timer,
-                                 round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES));
-               }
+       if (!dev_priv->ums.mm_suspended) {
+               i915_queue_hangcheck(ring->dev);
+
                if (was_empty) {
                        queue_delayed_work(dev_priv->wq,
                                           &dev_priv->mm.retire_work,
@@ -2121,8 +2115,8 @@ i915_gem_request_remove_from_client(struct drm_i915_gem_request *request)
 
 static bool i915_head_inside_object(u32 acthd, struct drm_i915_gem_object *obj)
 {
-       if (acthd >= obj->gtt_offset &&
-           acthd < obj->gtt_offset + obj->base.size)
+       if (acthd >= i915_gem_obj_ggtt_offset(obj) &&
+           acthd < i915_gem_obj_ggtt_offset(obj) + obj->base.size)
                return true;
 
        return false;
@@ -2180,11 +2174,11 @@ static void i915_set_reset_status(struct intel_ring_buffer *ring,
 
        if (ring->hangcheck.action != wait &&
            i915_request_guilty(request, acthd, &inside)) {
-               DRM_ERROR("%s hung %s bo (0x%x ctx %d) at 0x%x\n",
+               DRM_ERROR("%s hung %s bo (0x%lx ctx %d) at 0x%x\n",
                          ring->name,
                          inside ? "inside" : "flushing",
                          request->batch_obj ?
-                         request->batch_obj->gtt_offset : 0,
+                         i915_gem_obj_ggtt_offset(request->batch_obj) : 0,
                          request->ctx ? request->ctx->id : 0,
                          acthd);
 
@@ -2275,6 +2269,7 @@ void i915_gem_restore_fences(struct drm_device *dev)
 void i915_gem_reset(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       struct i915_address_space *vm = &dev_priv->gtt.base;
        struct drm_i915_gem_object *obj;
        struct intel_ring_buffer *ring;
        int i;
@@ -2285,12 +2280,8 @@ void i915_gem_reset(struct drm_device *dev)
        /* Move everything out of the GPU domains to ensure we do any
         * necessary invalidation upon reuse.
         */
-       list_for_each_entry(obj,
-                           &dev_priv->mm.inactive_list,
-                           mm_list)
-       {
+       list_for_each_entry(obj, &vm->inactive_list, mm_list)
                obj->base.read_domains &= ~I915_GEM_GPU_DOMAINS;
-       }
 
        i915_gem_restore_fences(dev);
 }
@@ -2400,7 +2391,7 @@ i915_gem_retire_work_handler(struct work_struct *work)
                idle &= list_empty(&ring->request_list);
        }
 
-       if (!dev_priv->mm.suspended && !idle)
+       if (!dev_priv->ums.mm_suspended && !idle)
                queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work,
                                   round_jiffies_up_relative(HZ));
        if (idle)
@@ -2593,9 +2584,10 @@ int
 i915_gem_object_unbind(struct drm_i915_gem_object *obj)
 {
        drm_i915_private_t *dev_priv = obj->base.dev->dev_private;
+       struct i915_vma *vma;
        int ret;
 
-       if (obj->gtt_space == NULL)
+       if (!i915_gem_obj_ggtt_bound(obj))
                return 0;
 
        if (obj->pin_count)
@@ -2630,13 +2622,20 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj)
        i915_gem_object_unpin_pages(obj);
 
        list_del(&obj->mm_list);
-       list_move_tail(&obj->global_list, &dev_priv->mm.unbound_list);
        /* Avoid an unnecessary call to unbind on rebind. */
        obj->map_and_fenceable = true;
 
-       drm_mm_put_block(obj->gtt_space);
-       obj->gtt_space = NULL;
-       obj->gtt_offset = 0;
+       vma = __i915_gem_obj_to_vma(obj);
+       list_del(&vma->vma_link);
+       drm_mm_remove_node(&vma->node);
+       i915_gem_vma_destroy(vma);
+
+       /* Since the unbound list is global, only move to that list if
+        * no more VMAs exist.
+        * NB: Until we have real VMAs there will only ever be one */
+       WARN_ON(!list_empty(&obj->vma_list));
+       if (list_empty(&obj->vma_list))
+               list_move_tail(&obj->global_list, &dev_priv->mm.unbound_list);
 
        return 0;
 }
@@ -2691,12 +2690,12 @@ static void i965_write_fence_reg(struct drm_device *dev, int reg,
        POSTING_READ(fence_reg);
 
        if (obj) {
-               u32 size = obj->gtt_space->size;
+               u32 size = i915_gem_obj_ggtt_size(obj);
                uint64_t val;
 
-               val = (uint64_t)((obj->gtt_offset + size - 4096) &
+               val = (uint64_t)((i915_gem_obj_ggtt_offset(obj) + size - 4096) &
                                 0xfffff000) << 32;
-               val |= obj->gtt_offset & 0xfffff000;
+               val |= i915_gem_obj_ggtt_offset(obj) & 0xfffff000;
                val |= (uint64_t)((obj->stride / 128) - 1) << fence_pitch_shift;
                if (obj->tiling_mode == I915_TILING_Y)
                        val |= 1 << I965_FENCE_TILING_Y_SHIFT;
@@ -2720,15 +2719,15 @@ static void i915_write_fence_reg(struct drm_device *dev, int reg,
        u32 val;
 
        if (obj) {
-               u32 size = obj->gtt_space->size;
+               u32 size = i915_gem_obj_ggtt_size(obj);
                int pitch_val;
                int tile_width;
 
-               WARN((obj->gtt_offset & ~I915_FENCE_START_MASK) ||
+               WARN((i915_gem_obj_ggtt_offset(obj) & ~I915_FENCE_START_MASK) ||
                     (size & -size) != size ||
-                    (obj->gtt_offset & (size - 1)),
-                    "object 0x%08x [fenceable? %d] not 1M or pot-size (0x%08x) aligned\n",
-                    obj->gtt_offset, obj->map_and_fenceable, size);
+                    (i915_gem_obj_ggtt_offset(obj) & (size - 1)),
+                    "object 0x%08lx [fenceable? %d] not 1M or pot-size (0x%08x) aligned\n",
+                    i915_gem_obj_ggtt_offset(obj), obj->map_and_fenceable, size);
 
                if (obj->tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev))
                        tile_width = 128;
@@ -2739,7 +2738,7 @@ static void i915_write_fence_reg(struct drm_device *dev, int reg,
                pitch_val = obj->stride / tile_width;
                pitch_val = ffs(pitch_val) - 1;
 
-               val = obj->gtt_offset;
+               val = i915_gem_obj_ggtt_offset(obj);
                if (obj->tiling_mode == I915_TILING_Y)
                        val |= 1 << I830_FENCE_TILING_Y_SHIFT;
                val |= I915_FENCE_SIZE_BITS(size);
@@ -2764,19 +2763,19 @@ static void i830_write_fence_reg(struct drm_device *dev, int reg,
        uint32_t val;
 
        if (obj) {
-               u32 size = obj->gtt_space->size;
+               u32 size = i915_gem_obj_ggtt_size(obj);
                uint32_t pitch_val;
 
-               WARN((obj->gtt_offset & ~I830_FENCE_START_MASK) ||
+               WARN((i915_gem_obj_ggtt_offset(obj) & ~I830_FENCE_START_MASK) ||
                     (size & -size) != size ||
-                    (obj->gtt_offset & (size - 1)),
-                    "object 0x%08x not 512K or pot-size 0x%08x aligned\n",
-                    obj->gtt_offset, size);
+                    (i915_gem_obj_ggtt_offset(obj) & (size - 1)),
+                    "object 0x%08lx not 512K or pot-size 0x%08x aligned\n",
+                    i915_gem_obj_ggtt_offset(obj), size);
 
                pitch_val = obj->stride / 128;
                pitch_val = ffs(pitch_val) - 1;
 
-               val = obj->gtt_offset;
+               val = i915_gem_obj_ggtt_offset(obj);
                if (obj->tiling_mode == I915_TILING_Y)
                        val |= 1 << I830_FENCE_TILING_Y_SHIFT;
                val |= I830_FENCE_SIZE_BITS(size);
@@ -2997,7 +2996,7 @@ static bool i915_gem_valid_gtt_space(struct drm_device *dev,
        if (HAS_LLC(dev))
                return true;
 
-       if (gtt_space == NULL)
+       if (!drm_mm_node_allocated(gtt_space))
                return true;
 
        if (list_empty(&gtt_space->node_list))
@@ -3030,8 +3029,8 @@ static void i915_gem_verify_gtt(struct drm_device *dev)
 
                if (obj->cache_level != obj->gtt_space->color) {
                        printk(KERN_ERR "object reserved space [%08lx, %08lx] with wrong color, cache_level=%x, color=%lx\n",
-                              obj->gtt_space->start,
-                              obj->gtt_space->start + obj->gtt_space->size,
+                              i915_gem_obj_ggtt_offset(obj),
+                              i915_gem_obj_ggtt_offset(obj) + i915_gem_obj_ggtt_size(obj),
                               obj->cache_level,
                               obj->gtt_space->color);
                        err++;
@@ -3042,8 +3041,8 @@ static void i915_gem_verify_gtt(struct drm_device *dev)
                                              obj->gtt_space,
                                              obj->cache_level)) {
                        printk(KERN_ERR "invalid GTT space found at [%08lx, %08lx] - color=%x\n",
-                              obj->gtt_space->start,
-                              obj->gtt_space->start + obj->gtt_space->size,
+                              i915_gem_obj_ggtt_offset(obj),
+                              i915_gem_obj_ggtt_offset(obj) + i915_gem_obj_ggtt_size(obj),
                               obj->cache_level);
                        err++;
                        continue;
@@ -3065,13 +3064,17 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
 {
        struct drm_device *dev = obj->base.dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       struct drm_mm_node *node;
+       struct i915_address_space *vm = &dev_priv->gtt.base;
        u32 size, fence_size, fence_alignment, unfenced_alignment;
        bool mappable, fenceable;
        size_t gtt_max = map_and_fenceable ?
-               dev_priv->gtt.mappable_end : dev_priv->gtt.total;
+               dev_priv->gtt.mappable_end : dev_priv->gtt.base.total;
+       struct i915_vma *vma;
        int ret;
 
+       if (WARN_ON(!list_empty(&obj->vma_list)))
+               return -EBUSY;
+
        fence_size = i915_gem_get_gtt_size(dev,
                                           obj->base.size,
                                           obj->tiling_mode);
@@ -3110,14 +3113,15 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
 
        i915_gem_object_pin_pages(obj);
 
-       node = kzalloc(sizeof(*node), GFP_KERNEL);
-       if (node == NULL) {
-               i915_gem_object_unpin_pages(obj);
-               return -ENOMEM;
+       vma = i915_gem_vma_create(obj, &dev_priv->gtt.base);
+       if (IS_ERR(vma)) {
+               ret = PTR_ERR(vma);
+               goto err_unpin;
        }
 
 search_free:
-       ret = drm_mm_insert_node_in_range_generic(&dev_priv->mm.gtt_space, node,
+       ret = drm_mm_insert_node_in_range_generic(&dev_priv->gtt.base.mm,
+                                                 &vma->node,
                                                  size, alignment,
                                                  obj->cache_level, 0, gtt_max);
        if (ret) {
@@ -3128,41 +3132,42 @@ search_free:
                if (ret == 0)
                        goto search_free;
 
-               i915_gem_object_unpin_pages(obj);
-               kfree(node);
-               return ret;
+               goto err_free_vma;
        }
-       if (WARN_ON(!i915_gem_valid_gtt_space(dev, node, obj->cache_level))) {
-               i915_gem_object_unpin_pages(obj);
-               drm_mm_put_block(node);
-               return -EINVAL;
+       if (WARN_ON(!i915_gem_valid_gtt_space(dev, &vma->node,
+                                             obj->cache_level))) {
+               ret = -EINVAL;
+               goto err_remove_node;
        }
 
        ret = i915_gem_gtt_prepare_object(obj);
-       if (ret) {
-               i915_gem_object_unpin_pages(obj);
-               drm_mm_put_block(node);
-               return ret;
-       }
+       if (ret)
+               goto err_remove_node;
 
        list_move_tail(&obj->global_list, &dev_priv->mm.bound_list);
-       list_add_tail(&obj->mm_list, &dev_priv->mm.inactive_list);
-
-       obj->gtt_space = node;
-       obj->gtt_offset = node->start;
+       list_add_tail(&obj->mm_list, &vm->inactive_list);
+       list_add(&vma->vma_link, &obj->vma_list);
 
        fenceable =
-               node->size == fence_size &&
-               (node->start & (fence_alignment - 1)) == 0;
+               i915_gem_obj_ggtt_size(obj) == fence_size &&
+               (i915_gem_obj_ggtt_offset(obj) & (fence_alignment - 1)) == 0;
 
-       mappable =
-               obj->gtt_offset + obj->base.size <= dev_priv->gtt.mappable_end;
+       mappable = i915_gem_obj_ggtt_offset(obj) + obj->base.size <=
+               dev_priv->gtt.mappable_end;
 
        obj->map_and_fenceable = mappable && fenceable;
 
        trace_i915_gem_object_bind(obj, map_and_fenceable);
        i915_gem_verify_gtt(dev);
        return 0;
+
+err_remove_node:
+       drm_mm_remove_node(&vma->node);
+err_free_vma:
+       i915_gem_vma_destroy(vma);
+err_unpin:
+       i915_gem_object_unpin_pages(obj);
+       return ret;
 }
 
 void
@@ -3258,7 +3263,7 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write)
        int ret;
 
        /* Not valid to be called on unbound objects. */
-       if (obj->gtt_space == NULL)
+       if (!i915_gem_obj_ggtt_bound(obj))
                return -EINVAL;
 
        if (obj->base.write_domain == I915_GEM_DOMAIN_GTT)
@@ -3297,7 +3302,8 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write)
 
        /* And bump the LRU for this access */
        if (i915_gem_object_is_inactive(obj))
-               list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list);
+               list_move_tail(&obj->mm_list,
+                              &dev_priv->gtt.base.inactive_list);
 
        return 0;
 }
@@ -3307,6 +3313,7 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
 {
        struct drm_device *dev = obj->base.dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
+       struct i915_vma *vma = __i915_gem_obj_to_vma(obj);
        int ret;
 
        if (obj->cache_level == cache_level)
@@ -3317,13 +3324,13 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
                return -EBUSY;
        }
 
-       if (!i915_gem_valid_gtt_space(dev, obj->gtt_space, cache_level)) {
+       if (vma && !i915_gem_valid_gtt_space(dev, &vma->node, cache_level)) {
                ret = i915_gem_object_unbind(obj);
                if (ret)
                        return ret;
        }
 
-       if (obj->gtt_space) {
+       if (i915_gem_obj_ggtt_bound(obj)) {
                ret = i915_gem_object_finish_gpu(obj);
                if (ret)
                        return ret;
@@ -3346,7 +3353,7 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
                        i915_ppgtt_bind_object(dev_priv->mm.aliasing_ppgtt,
                                               obj, cache_level);
 
-               obj->gtt_space->color = cache_level;
+               i915_gem_obj_ggtt_set_color(obj, cache_level);
        }
 
        if (cache_level == I915_CACHE_NONE) {
@@ -3627,14 +3634,14 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj,
        if (WARN_ON(obj->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT))
                return -EBUSY;
 
-       if (obj->gtt_space != NULL) {
-               if ((alignment && obj->gtt_offset & (alignment - 1)) ||
+       if (i915_gem_obj_ggtt_bound(obj)) {
+               if ((alignment && i915_gem_obj_ggtt_offset(obj) & (alignment - 1)) ||
                    (map_and_fenceable && !obj->map_and_fenceable)) {
                        WARN(obj->pin_count,
                             "bo is already pinned with incorrect alignment:"
-                            " offset=%x, req.alignment=%x, req.map_and_fenceable=%d,"
+                            " offset=%lx, req.alignment=%x, req.map_and_fenceable=%d,"
                             " obj->map_and_fenceable=%d\n",
-                            obj->gtt_offset, alignment,
+                            i915_gem_obj_ggtt_offset(obj), alignment,
                             map_and_fenceable,
                             obj->map_and_fenceable);
                        ret = i915_gem_object_unbind(obj);
@@ -3643,7 +3650,7 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj,
                }
        }
 
-       if (obj->gtt_space == NULL) {
+       if (!i915_gem_obj_ggtt_bound(obj)) {
                struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
 
                ret = i915_gem_object_bind_to_gtt(obj, alignment,
@@ -3669,7 +3676,7 @@ void
 i915_gem_object_unpin(struct drm_i915_gem_object *obj)
 {
        BUG_ON(obj->pin_count == 0);
-       BUG_ON(obj->gtt_space == NULL);
+       BUG_ON(!i915_gem_obj_ggtt_bound(obj));
 
        if (--obj->pin_count == 0)
                obj->pin_mappable = false;
@@ -3719,7 +3726,7 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data,
         * as the X server doesn't manage domains yet
         */
        i915_gem_object_flush_cpu_write_domain(obj);
-       args->offset = obj->gtt_offset;
+       args->offset = i915_gem_obj_ggtt_offset(obj);
 out:
        drm_gem_object_unreference(&obj->base);
 unlock:
@@ -3862,6 +3869,7 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj,
        INIT_LIST_HEAD(&obj->global_list);
        INIT_LIST_HEAD(&obj->ring_list);
        INIT_LIST_HEAD(&obj->exec_list);
+       INIT_LIST_HEAD(&obj->vma_list);
 
        obj->ops = ops;
 
@@ -3926,6 +3934,8 @@ struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev,
        } else
                obj->cache_level = I915_CACHE_NONE;
 
+       trace_i915_gem_object_create(obj);
+
        return obj;
 }
 
@@ -3982,15 +3992,33 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj)
        i915_gem_object_free(obj);
 }
 
+struct i915_vma *i915_gem_vma_create(struct drm_i915_gem_object *obj,
+                                    struct i915_address_space *vm)
+{
+       struct i915_vma *vma = kzalloc(sizeof(*vma), GFP_KERNEL);
+       if (vma == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       INIT_LIST_HEAD(&vma->vma_link);
+       vma->vm = vm;
+       vma->obj = obj;
+
+       return vma;
+}
+
+void i915_gem_vma_destroy(struct i915_vma *vma)
+{
+       WARN_ON(vma->node.allocated);
+       kfree(vma);
+}
+
 int
 i915_gem_idle(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        int ret;
 
-       mutex_lock(&dev->struct_mutex);
-
-       if (dev_priv->mm.suspended) {
+       if (dev_priv->ums.mm_suspended) {
                mutex_unlock(&dev->struct_mutex);
                return 0;
        }
@@ -4006,18 +4034,11 @@ i915_gem_idle(struct drm_device *dev)
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                i915_gem_evict_everything(dev);
 
-       /* Hack!  Don't let anybody do execbuf while we don't control the chip.
-        * We need to replace this with a semaphore, or something.
-        * And not confound mm.suspended!
-        */
-       dev_priv->mm.suspended = 1;
        del_timer_sync(&dev_priv->gpu_error.hangcheck_timer);
 
        i915_kernel_lost_context(dev);
        i915_gem_cleanup_ringbuffer(dev);
 
-       mutex_unlock(&dev->struct_mutex);
-
        /* Cancel the retire work handler, which should be idle now. */
        cancel_delayed_work_sync(&dev_priv->mm.retire_work);
 
@@ -4150,8 +4171,8 @@ i915_gem_init_hw(struct drm_device *dev)
        if (INTEL_INFO(dev)->gen < 6 && !intel_enable_gtt())
                return -EIO;
 
-       if (IS_HASWELL(dev) && (I915_READ(0x120010) == 1))
-               I915_WRITE(0x9008, I915_READ(0x9008) | 0xf0000);
+       if (dev_priv->ellc_size)
+               I915_WRITE(HSW_IDICR, I915_READ(HSW_IDICR) | IDIHASHMSK(0xf));
 
        if (HAS_PCH_NOP(dev)) {
                u32 temp = I915_READ(GEN7_MSG_CTL);
@@ -4227,7 +4248,7 @@ int
 i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
                       struct drm_file *file_priv)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
 
        if (drm_core_check_feature(dev, DRIVER_MODESET))
@@ -4239,7 +4260,7 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
        }
 
        mutex_lock(&dev->struct_mutex);
-       dev_priv->mm.suspended = 0;
+       dev_priv->ums.mm_suspended = 0;
 
        ret = i915_gem_init_hw(dev);
        if (ret != 0) {
@@ -4247,7 +4268,7 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
                return ret;
        }
 
-       BUG_ON(!list_empty(&dev_priv->mm.active_list));
+       BUG_ON(!list_empty(&dev_priv->gtt.base.active_list));
        mutex_unlock(&dev->struct_mutex);
 
        ret = drm_irq_install(dev);
@@ -4259,7 +4280,7 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
 cleanup_ringbuffer:
        mutex_lock(&dev->struct_mutex);
        i915_gem_cleanup_ringbuffer(dev);
-       dev_priv->mm.suspended = 1;
+       dev_priv->ums.mm_suspended = 1;
        mutex_unlock(&dev->struct_mutex);
 
        return ret;
@@ -4269,11 +4290,26 @@ int
 i915_gem_leavevt_ioctl(struct drm_device *dev, void *data,
                       struct drm_file *file_priv)
 {
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret;
+
        if (drm_core_check_feature(dev, DRIVER_MODESET))
                return 0;
 
        drm_irq_uninstall(dev);
-       return i915_gem_idle(dev);
+
+       mutex_lock(&dev->struct_mutex);
+       ret =  i915_gem_idle(dev);
+
+       /* Hack!  Don't let anybody do execbuf while we don't control the chip.
+        * We need to replace this with a semaphore, or something.
+        * And not confound ums.mm_suspended!
+        */
+       if (ret != 0)
+               dev_priv->ums.mm_suspended = 1;
+       mutex_unlock(&dev->struct_mutex);
+
+       return ret;
 }
 
 void
@@ -4284,9 +4320,11 @@ i915_gem_lastclose(struct drm_device *dev)
        if (drm_core_check_feature(dev, DRIVER_MODESET))
                return;
 
+       mutex_lock(&dev->struct_mutex);
        ret = i915_gem_idle(dev);
        if (ret)
                DRM_ERROR("failed to idle hardware: %d\n", ret);
+       mutex_unlock(&dev->struct_mutex);
 }
 
 static void
@@ -4308,8 +4346,8 @@ i915_gem_load(struct drm_device *dev)
                                  SLAB_HWCACHE_ALIGN,
                                  NULL);
 
-       INIT_LIST_HEAD(&dev_priv->mm.active_list);
-       INIT_LIST_HEAD(&dev_priv->mm.inactive_list);
+       INIT_LIST_HEAD(&dev_priv->gtt.base.active_list);
+       INIT_LIST_HEAD(&dev_priv->gtt.base.inactive_list);
        INIT_LIST_HEAD(&dev_priv->mm.unbound_list);
        INIT_LIST_HEAD(&dev_priv->mm.bound_list);
        INIT_LIST_HEAD(&dev_priv->mm.fence_list);
@@ -4580,6 +4618,7 @@ i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc)
                             struct drm_i915_private,
                             mm.inactive_shrinker);
        struct drm_device *dev = dev_priv->dev;
+       struct i915_address_space *vm = &dev_priv->gtt.base;
        struct drm_i915_gem_object *obj;
        int nr_to_scan = sc->nr_to_scan;
        bool unlock = true;
@@ -4608,7 +4647,7 @@ i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc)
        list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_list)
                if (obj->pages_pin_count == 0)
                        cnt += obj->base.size >> PAGE_SHIFT;
-       list_for_each_entry(obj, &dev_priv->mm.inactive_list, mm_list)
+       list_for_each_entry(obj, &vm->inactive_list, mm_list)
                if (obj->pin_count == 0 && obj->pages_pin_count == 0)
                        cnt += obj->base.size >> PAGE_SHIFT;
 
index 51b7a2171caee8a9b8c7a3c6f51edb5c5487dd25..2470206a4d07490979ac66e2f2597eebbdf3aa32 100644 (file)
@@ -304,31 +304,24 @@ static int context_idr_cleanup(int id, void *p, void *data)
 }
 
 struct i915_ctx_hang_stats *
-i915_gem_context_get_hang_stats(struct intel_ring_buffer *ring,
+i915_gem_context_get_hang_stats(struct drm_device *dev,
                                struct drm_file *file,
                                u32 id)
 {
-       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_file_private *file_priv = file->driver_priv;
-       struct i915_hw_context *to;
-
-       if (dev_priv->hw_contexts_disabled)
-               return ERR_PTR(-ENOENT);
-
-       if (ring->id != RCS)
-               return ERR_PTR(-EINVAL);
-
-       if (file == NULL)
-               return ERR_PTR(-EINVAL);
+       struct i915_hw_context *ctx;
 
        if (id == DEFAULT_CONTEXT_ID)
                return &file_priv->hang_stats;
 
-       to = i915_gem_context_get(file->driver_priv, id);
-       if (to == NULL)
+       ctx = NULL;
+       if (!dev_priv->hw_contexts_disabled)
+               ctx = i915_gem_context_get(file->driver_priv, id);
+       if (ctx == NULL)
                return ERR_PTR(-ENOENT);
 
-       return &to->hang_stats;
+       return &ctx->hang_stats;
 }
 
 void i915_gem_context_close(struct drm_device *dev, struct drm_file *file)
@@ -377,7 +370,7 @@ mi_set_context(struct intel_ring_buffer *ring,
 
        intel_ring_emit(ring, MI_NOOP);
        intel_ring_emit(ring, MI_SET_CONTEXT);
-       intel_ring_emit(ring, new_context->obj->gtt_offset |
+       intel_ring_emit(ring, i915_gem_obj_ggtt_offset(new_context->obj) |
                        MI_MM_SPACE_GTT |
                        MI_SAVE_EXT_STATE_EN |
                        MI_RESTORE_EXT_STATE_EN |
index 582e6a5f3dac6e4d464440ebab84f3604cc5f62e..bf945a39fbb1dedba155a76e9483795c19e6932c 100644 (file)
@@ -97,7 +97,7 @@ i915_verify_lists(struct drm_device *dev)
                }
        }
 
-       list_for_each_entry(obj, &dev_priv->mm.inactive_list, list) {
+       list_for_each_entry(obj, &i915_gtt_vm->inactive_list, list) {
                if (obj->base.dev != dev ||
                    !atomic_read(&obj->base.refcount.refcount)) {
                        DRM_ERROR("freed inactive %p\n", obj);
index dc53a527126b0569800ff2df3a8a36ebbf904855..f2e185c9038f8c24dc71c3505f18fb46092d697f 100644 (file)
@@ -289,12 +289,7 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
                goto fail_detach;
        }
 
-       ret = drm_gem_private_object_init(dev, &obj->base, dma_buf->size);
-       if (ret) {
-               i915_gem_object_free(obj);
-               goto fail_detach;
-       }
-
+       drm_gem_private_object_init(dev, &obj->base, dma_buf->size);
        i915_gem_object_init(obj, &i915_gem_object_dmabuf_ops);
        obj->base.import_attach = attach;
 
index c86d5d9356fd086b756b9dc207b6d7c9e824f630..df61f338dea184c1486fea791294ab388cbffbaf 100644 (file)
 static bool
 mark_free(struct drm_i915_gem_object *obj, struct list_head *unwind)
 {
+       struct i915_vma *vma = __i915_gem_obj_to_vma(obj);
+
        if (obj->pin_count)
                return false;
 
        list_add(&obj->exec_list, unwind);
-       return drm_mm_scan_add_block(obj->gtt_space);
+       return drm_mm_scan_add_block(&vma->node);
 }
 
 int
@@ -47,7 +49,9 @@ i915_gem_evict_something(struct drm_device *dev, int min_size,
                         bool mappable, bool nonblocking)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
+       struct i915_address_space *vm = &dev_priv->gtt.base;
        struct list_head eviction_list, unwind_list;
+       struct i915_vma *vma;
        struct drm_i915_gem_object *obj;
        int ret = 0;
 
@@ -78,15 +82,14 @@ i915_gem_evict_something(struct drm_device *dev, int min_size,
 
        INIT_LIST_HEAD(&unwind_list);
        if (mappable)
-               drm_mm_init_scan_with_range(&dev_priv->mm.gtt_space,
-                                           min_size, alignment, cache_level,
-                                           0, dev_priv->gtt.mappable_end);
+               drm_mm_init_scan_with_range(&vm->mm, min_size,
+                                           alignment, cache_level, 0,
+                                           dev_priv->gtt.mappable_end);
        else
-               drm_mm_init_scan(&dev_priv->mm.gtt_space,
-                                min_size, alignment, cache_level);
+               drm_mm_init_scan(&vm->mm, min_size, alignment, cache_level);
 
        /* First see if there is a large enough contiguous idle region... */
-       list_for_each_entry(obj, &dev_priv->mm.inactive_list, mm_list) {
+       list_for_each_entry(obj, &vm->inactive_list, mm_list) {
                if (mark_free(obj, &unwind_list))
                        goto found;
        }
@@ -95,7 +98,7 @@ i915_gem_evict_something(struct drm_device *dev, int min_size,
                goto none;
 
        /* Now merge in the soon-to-be-expired objects... */
-       list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) {
+       list_for_each_entry(obj, &vm->active_list, mm_list) {
                if (mark_free(obj, &unwind_list))
                        goto found;
        }
@@ -106,8 +109,8 @@ none:
                obj = list_first_entry(&unwind_list,
                                       struct drm_i915_gem_object,
                                       exec_list);
-
-               ret = drm_mm_scan_remove_block(obj->gtt_space);
+               vma = __i915_gem_obj_to_vma(obj);
+               ret = drm_mm_scan_remove_block(&vma->node);
                BUG_ON(ret);
 
                list_del_init(&obj->exec_list);
@@ -127,7 +130,8 @@ found:
                obj = list_first_entry(&unwind_list,
                                       struct drm_i915_gem_object,
                                       exec_list);
-               if (drm_mm_scan_remove_block(obj->gtt_space)) {
+               vma = __i915_gem_obj_to_vma(obj);
+               if (drm_mm_scan_remove_block(&vma->node)) {
                        list_move(&obj->exec_list, &eviction_list);
                        drm_gem_object_reference(&obj->base);
                        continue;
@@ -154,12 +158,13 @@ int
 i915_gem_evict_everything(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
+       struct i915_address_space *vm = &dev_priv->gtt.base;
        struct drm_i915_gem_object *obj, *next;
        bool lists_empty;
        int ret;
 
-       lists_empty = (list_empty(&dev_priv->mm.inactive_list) &&
-                      list_empty(&dev_priv->mm.active_list));
+       lists_empty = (list_empty(&vm->inactive_list) &&
+                      list_empty(&vm->active_list));
        if (lists_empty)
                return -ENOSPC;
 
@@ -176,8 +181,7 @@ i915_gem_evict_everything(struct drm_device *dev)
        i915_gem_retire_requests(dev);
 
        /* Having flushed everything, unbind() should never raise an error */
-       list_for_each_entry_safe(obj, next,
-                                &dev_priv->mm.inactive_list, mm_list)
+       list_for_each_entry_safe(obj, next, &vm->inactive_list, mm_list)
                if (obj->pin_count == 0)
                        WARN_ON(i915_gem_object_unbind(obj));
 
index 87a3227e51795ef44ba03933be925a49e1409504..5b6d764e9bb2dee30bf3ad7ee177f6dcbd4b0020 100644 (file)
@@ -188,7 +188,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
                return -ENOENT;
 
        target_i915_obj = to_intel_bo(target_obj);
-       target_offset = target_i915_obj->gtt_offset;
+       target_offset = i915_gem_obj_ggtt_offset(target_i915_obj);
 
        /* Sandybridge PPGTT errata: We need a global gtt mapping for MI and
         * pipe_control writes because the gpu doesn't properly redirect them
@@ -255,7 +255,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
 
        reloc->delta += target_offset;
        if (use_cpu_reloc(obj)) {
-               uint32_t page_offset = reloc->offset & ~PAGE_MASK;
+               uint32_t page_offset = offset_in_page(reloc->offset);
                char *vaddr;
 
                ret = i915_gem_object_set_to_cpu_domain(obj, 1);
@@ -280,11 +280,11 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
                        return ret;
 
                /* Map the page containing the relocation we're going to perform.  */
-               reloc->offset += obj->gtt_offset;
+               reloc->offset += i915_gem_obj_ggtt_offset(obj);
                reloc_page = io_mapping_map_atomic_wc(dev_priv->gtt.mappable,
                                                      reloc->offset & PAGE_MASK);
                reloc_entry = (uint32_t __iomem *)
-                       (reloc_page + (reloc->offset & ~PAGE_MASK));
+                       (reloc_page + offset_in_page(reloc->offset));
                iowrite32(reloc->delta, reloc_entry);
                io_mapping_unmap_atomic(reloc_page);
        }
@@ -436,8 +436,8 @@ i915_gem_execbuffer_reserve_object(struct drm_i915_gem_object *obj,
                obj->has_aliasing_ppgtt_mapping = 1;
        }
 
-       if (entry->offset != obj->gtt_offset) {
-               entry->offset = obj->gtt_offset;
+       if (entry->offset != i915_gem_obj_ggtt_offset(obj)) {
+               entry->offset = i915_gem_obj_ggtt_offset(obj);
                *need_reloc = true;
        }
 
@@ -458,7 +458,7 @@ i915_gem_execbuffer_unreserve_object(struct drm_i915_gem_object *obj)
 {
        struct drm_i915_gem_exec_object2 *entry;
 
-       if (!obj->gtt_space)
+       if (!i915_gem_obj_ggtt_bound(obj))
                return;
 
        entry = obj->exec_entry;
@@ -530,7 +530,7 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring,
                        struct drm_i915_gem_exec_object2 *entry = obj->exec_entry;
                        bool need_fence, need_mappable;
 
-                       if (!obj->gtt_space)
+                       if (!i915_gem_obj_ggtt_bound(obj))
                                continue;
 
                        need_fence =
@@ -539,7 +539,8 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring,
                                obj->tiling_mode != I915_TILING_NONE;
                        need_mappable = need_fence || need_reloc_mappable(obj);
 
-                       if ((entry->alignment && obj->gtt_offset & (entry->alignment - 1)) ||
+                       if ((entry->alignment &&
+                            i915_gem_obj_ggtt_offset(obj) & (entry->alignment - 1)) ||
                            (need_mappable && !obj->map_and_fenceable))
                                ret = i915_gem_object_unbind(obj);
                        else
@@ -550,7 +551,7 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring,
 
                /* Bind fresh objects */
                list_for_each_entry(obj, objects, exec_list) {
-                       if (obj->gtt_space)
+                       if (i915_gem_obj_ggtt_bound(obj))
                                continue;
 
                        ret = i915_gem_execbuffer_reserve_object(obj, ring, need_relocs);
@@ -758,8 +759,10 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec,
                if (!access_ok(VERIFY_WRITE, ptr, length))
                        return -EFAULT;
 
-               if (fault_in_multipages_readable(ptr, length))
-                       return -EFAULT;
+               if (likely(!i915_prefault_disable)) {
+                       if (fault_in_multipages_readable(ptr, length))
+                               return -EFAULT;
+               }
        }
 
        return 0;
@@ -872,7 +875,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                break;
        case I915_EXEC_BSD:
                ring = &dev_priv->ring[VCS];
-               if (ctx_id != 0) {
+               if (ctx_id != DEFAULT_CONTEXT_ID) {
                        DRM_DEBUG("Ring %s doesn't support contexts\n",
                                  ring->name);
                        return -EPERM;
@@ -880,7 +883,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                break;
        case I915_EXEC_BLT:
                ring = &dev_priv->ring[BCS];
-               if (ctx_id != 0) {
+               if (ctx_id != DEFAULT_CONTEXT_ID) {
                        DRM_DEBUG("Ring %s doesn't support contexts\n",
                                  ring->name);
                        return -EPERM;
@@ -888,7 +891,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                break;
        case I915_EXEC_VEBOX:
                ring = &dev_priv->ring[VECS];
-               if (ctx_id != 0) {
+               if (ctx_id != DEFAULT_CONTEXT_ID) {
                        DRM_DEBUG("Ring %s doesn't support contexts\n",
                                  ring->name);
                        return -EPERM;
@@ -972,7 +975,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
        if (ret)
                goto pre_mutex_err;
 
-       if (dev_priv->mm.suspended) {
+       if (dev_priv->ums.mm_suspended) {
                mutex_unlock(&dev->struct_mutex);
                ret = -EBUSY;
                goto pre_mutex_err;
@@ -1058,7 +1061,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                        goto err;
        }
 
-       exec_start = batch_obj->gtt_offset + args->batch_start_offset;
+       exec_start = i915_gem_obj_ggtt_offset(batch_obj) + args->batch_start_offset;
        exec_len = args->batch_len;
        if (cliprects) {
                for (i = 0; i < args->num_cliprects; i++) {
index 5101ab6869b47eef37b5be33e9b4786bc862beca..3b639a94dddf72b1fdebcf2f00e46f9d60c17bb8 100644 (file)
 #include "i915_trace.h"
 #include "intel_drv.h"
 
+#define GEN6_PPGTT_PD_ENTRIES 512
+#define I915_PPGTT_PT_ENTRIES (PAGE_SIZE / sizeof(gen6_gtt_pte_t))
+
 /* PPGTT stuff */
 #define GEN6_GTT_ADDR_ENCODE(addr)     ((addr) | (((addr) >> 28) & 0xff0))
+#define HSW_GTT_ADDR_ENCODE(addr)      ((addr) | (((addr) >> 28) & 0x7f0))
 
 #define GEN6_PDE_VALID                 (1 << 0)
 /* gen6+ has bit 11-4 for physical addr bit 39-32 */
 #define GEN6_PTE_CACHE_LLC             (2 << 1)
 #define GEN6_PTE_CACHE_LLC_MLC         (3 << 1)
 #define GEN6_PTE_ADDR_ENCODE(addr)     GEN6_GTT_ADDR_ENCODE(addr)
+#define HSW_PTE_ADDR_ENCODE(addr)      HSW_GTT_ADDR_ENCODE(addr)
+
+/* Cacheability Control is a 4-bit value. The low three bits are stored in *
+ * bits 3:1 of the PTE, while the fourth bit is stored in bit 11 of the PTE.
+ */
+#define HSW_CACHEABILITY_CONTROL(bits) ((((bits) & 0x7) << 1) | \
+                                        (((bits) & 0x8) << (11 - 3)))
+#define HSW_WB_LLC_AGE0                        HSW_CACHEABILITY_CONTROL(0x3)
+#define HSW_WB_ELLC_LLC_AGE0           HSW_CACHEABILITY_CONTROL(0xb)
 
-static gen6_gtt_pte_t gen6_pte_encode(struct drm_device *dev,
-                                     dma_addr_t addr,
+static gen6_gtt_pte_t gen6_pte_encode(dma_addr_t addr,
                                      enum i915_cache_level level)
 {
        gen6_gtt_pte_t pte = GEN6_PTE_VALID;
@@ -69,8 +81,7 @@ static gen6_gtt_pte_t gen6_pte_encode(struct drm_device *dev,
 #define BYT_PTE_WRITEABLE              (1 << 1)
 #define BYT_PTE_SNOOPED_BY_CPU_CACHES  (1 << 2)
 
-static gen6_gtt_pte_t byt_pte_encode(struct drm_device *dev,
-                                    dma_addr_t addr,
+static gen6_gtt_pte_t byt_pte_encode(dma_addr_t addr,
                                     enum i915_cache_level level)
 {
        gen6_gtt_pte_t pte = GEN6_PTE_VALID;
@@ -87,22 +98,33 @@ static gen6_gtt_pte_t byt_pte_encode(struct drm_device *dev,
        return pte;
 }
 
-static gen6_gtt_pte_t hsw_pte_encode(struct drm_device *dev,
-                                    dma_addr_t addr,
+static gen6_gtt_pte_t hsw_pte_encode(dma_addr_t addr,
                                     enum i915_cache_level level)
 {
        gen6_gtt_pte_t pte = GEN6_PTE_VALID;
-       pte |= GEN6_PTE_ADDR_ENCODE(addr);
+       pte |= HSW_PTE_ADDR_ENCODE(addr);
 
        if (level != I915_CACHE_NONE)
-               pte |= GEN6_PTE_CACHE_LLC;
+               pte |= HSW_WB_LLC_AGE0;
+
+       return pte;
+}
+
+static gen6_gtt_pte_t iris_pte_encode(dma_addr_t addr,
+                                     enum i915_cache_level level)
+{
+       gen6_gtt_pte_t pte = GEN6_PTE_VALID;
+       pte |= HSW_PTE_ADDR_ENCODE(addr);
+
+       if (level != I915_CACHE_NONE)
+               pte |= HSW_WB_ELLC_LLC_AGE0;
 
        return pte;
 }
 
 static void gen6_write_pdes(struct i915_hw_ppgtt *ppgtt)
 {
-       struct drm_i915_private *dev_priv = ppgtt->dev->dev_private;
+       struct drm_i915_private *dev_priv = ppgtt->base.dev->dev_private;
        gen6_gtt_pte_t __iomem *pd_addr;
        uint32_t pd_entry;
        int i;
@@ -181,18 +203,18 @@ static int gen6_ppgtt_enable(struct drm_device *dev)
 }
 
 /* PPGTT support for Sandybdrige/Gen6 and later */
-static void gen6_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt,
+static void gen6_ppgtt_clear_range(struct i915_address_space *vm,
                                   unsigned first_entry,
                                   unsigned num_entries)
 {
+       struct i915_hw_ppgtt *ppgtt =
+               container_of(vm, struct i915_hw_ppgtt, base);
        gen6_gtt_pte_t *pt_vaddr, scratch_pte;
        unsigned act_pt = first_entry / I915_PPGTT_PT_ENTRIES;
        unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES;
        unsigned last_pte, i;
 
-       scratch_pte = ppgtt->pte_encode(ppgtt->dev,
-                                       ppgtt->scratch_page_dma_addr,
-                                       I915_CACHE_LLC);
+       scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC);
 
        while (num_entries) {
                last_pte = first_pte + num_entries;
@@ -212,11 +234,13 @@ static void gen6_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt,
        }
 }
 
-static void gen6_ppgtt_insert_entries(struct i915_hw_ppgtt *ppgtt,
+static void gen6_ppgtt_insert_entries(struct i915_address_space *vm,
                                      struct sg_table *pages,
                                      unsigned first_entry,
                                      enum i915_cache_level cache_level)
 {
+       struct i915_hw_ppgtt *ppgtt =
+               container_of(vm, struct i915_hw_ppgtt, base);
        gen6_gtt_pte_t *pt_vaddr;
        unsigned act_pt = first_entry / I915_PPGTT_PT_ENTRIES;
        unsigned act_pte = first_entry % I915_PPGTT_PT_ENTRIES;
@@ -227,8 +251,7 @@ static void gen6_ppgtt_insert_entries(struct i915_hw_ppgtt *ppgtt,
                dma_addr_t page_addr;
 
                page_addr = sg_page_iter_dma_address(&sg_iter);
-               pt_vaddr[act_pte] = ppgtt->pte_encode(ppgtt->dev, page_addr,
-                                                     cache_level);
+               pt_vaddr[act_pte] = vm->pte_encode(page_addr, cache_level);
                if (++act_pte == I915_PPGTT_PT_ENTRIES) {
                        kunmap_atomic(pt_vaddr);
                        act_pt++;
@@ -240,13 +263,17 @@ static void gen6_ppgtt_insert_entries(struct i915_hw_ppgtt *ppgtt,
        kunmap_atomic(pt_vaddr);
 }
 
-static void gen6_ppgtt_cleanup(struct i915_hw_ppgtt *ppgtt)
+static void gen6_ppgtt_cleanup(struct i915_address_space *vm)
 {
+       struct i915_hw_ppgtt *ppgtt =
+               container_of(vm, struct i915_hw_ppgtt, base);
        int i;
 
+       drm_mm_takedown(&ppgtt->base.mm);
+
        if (ppgtt->pt_dma_addr) {
                for (i = 0; i < ppgtt->num_pd_entries; i++)
-                       pci_unmap_page(ppgtt->dev->pdev,
+                       pci_unmap_page(ppgtt->base.dev->pdev,
                                       ppgtt->pt_dma_addr[i],
                                       4096, PCI_DMA_BIDIRECTIONAL);
        }
@@ -260,7 +287,7 @@ static void gen6_ppgtt_cleanup(struct i915_hw_ppgtt *ppgtt)
 
 static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
 {
-       struct drm_device *dev = ppgtt->dev;
+       struct drm_device *dev = ppgtt->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned first_pd_entry_in_global_pt;
        int i;
@@ -272,17 +299,18 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
        first_pd_entry_in_global_pt = gtt_total_entries(dev_priv->gtt);
 
        if (IS_HASWELL(dev)) {
-               ppgtt->pte_encode = hsw_pte_encode;
+               ppgtt->base.pte_encode = hsw_pte_encode;
        } else if (IS_VALLEYVIEW(dev)) {
-               ppgtt->pte_encode = byt_pte_encode;
+               ppgtt->base.pte_encode = byt_pte_encode;
        } else {
-               ppgtt->pte_encode = gen6_pte_encode;
+               ppgtt->base.pte_encode = gen6_pte_encode;
        }
-       ppgtt->num_pd_entries = I915_PPGTT_PD_ENTRIES;
+       ppgtt->num_pd_entries = GEN6_PPGTT_PD_ENTRIES;
        ppgtt->enable = gen6_ppgtt_enable;
-       ppgtt->clear_range = gen6_ppgtt_clear_range;
-       ppgtt->insert_entries = gen6_ppgtt_insert_entries;
-       ppgtt->cleanup = gen6_ppgtt_cleanup;
+       ppgtt->base.clear_range = gen6_ppgtt_clear_range;
+       ppgtt->base.insert_entries = gen6_ppgtt_insert_entries;
+       ppgtt->base.cleanup = gen6_ppgtt_cleanup;
+       ppgtt->base.scratch = dev_priv->gtt.base.scratch;
        ppgtt->pt_pages = kzalloc(sizeof(struct page *)*ppgtt->num_pd_entries,
                                  GFP_KERNEL);
        if (!ppgtt->pt_pages)
@@ -313,8 +341,8 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
                ppgtt->pt_dma_addr[i] = pt_addr;
        }
 
-       ppgtt->clear_range(ppgtt, 0,
-                          ppgtt->num_pd_entries*I915_PPGTT_PT_ENTRIES);
+       ppgtt->base.clear_range(&ppgtt->base, 0,
+                               ppgtt->num_pd_entries * I915_PPGTT_PT_ENTRIES);
 
        ppgtt->pd_offset = first_pd_entry_in_global_pt * sizeof(gen6_gtt_pte_t);
 
@@ -347,8 +375,7 @@ static int i915_gem_init_aliasing_ppgtt(struct drm_device *dev)
        if (!ppgtt)
                return -ENOMEM;
 
-       ppgtt->dev = dev;
-       ppgtt->scratch_page_dma_addr = dev_priv->gtt.scratch_page_dma;
+       ppgtt->base.dev = dev;
 
        if (INTEL_INFO(dev)->gen < 8)
                ret = gen6_ppgtt_init(ppgtt);
@@ -357,8 +384,11 @@ static int i915_gem_init_aliasing_ppgtt(struct drm_device *dev)
 
        if (ret)
                kfree(ppgtt);
-       else
+       else {
                dev_priv->mm.aliasing_ppgtt = ppgtt;
+               drm_mm_init(&ppgtt->base.mm, ppgtt->base.start,
+                           ppgtt->base.total);
+       }
 
        return ret;
 }
@@ -371,7 +401,7 @@ void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev)
        if (!ppgtt)
                return;
 
-       ppgtt->cleanup(ppgtt);
+       ppgtt->base.cleanup(&ppgtt->base);
        dev_priv->mm.aliasing_ppgtt = NULL;
 }
 
@@ -379,17 +409,17 @@ void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt,
                            struct drm_i915_gem_object *obj,
                            enum i915_cache_level cache_level)
 {
-       ppgtt->insert_entries(ppgtt, obj->pages,
-                             obj->gtt_space->start >> PAGE_SHIFT,
-                             cache_level);
+       ppgtt->base.insert_entries(&ppgtt->base, obj->pages,
+                                  i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT,
+                                  cache_level);
 }
 
 void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt,
                              struct drm_i915_gem_object *obj)
 {
-       ppgtt->clear_range(ppgtt,
-                          obj->gtt_space->start >> PAGE_SHIFT,
-                          obj->base.size >> PAGE_SHIFT);
+       ppgtt->base.clear_range(&ppgtt->base,
+                               i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT,
+                               obj->base.size >> PAGE_SHIFT);
 }
 
 extern int intel_iommu_gfx_mapped;
@@ -436,8 +466,9 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
        struct drm_i915_gem_object *obj;
 
        /* First fill our portion of the GTT with scratch pages */
-       dev_priv->gtt.gtt_clear_range(dev, dev_priv->gtt.start / PAGE_SIZE,
-                                     dev_priv->gtt.total / PAGE_SIZE);
+       dev_priv->gtt.base.clear_range(&dev_priv->gtt.base,
+                                      dev_priv->gtt.base.start / PAGE_SIZE,
+                                      dev_priv->gtt.base.total / PAGE_SIZE);
 
        list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
                i915_gem_clflush_object(obj);
@@ -466,12 +497,12 @@ int i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj)
  * within the global GTT as well as accessible by the GPU through the GMADR
  * mapped BAR (dev_priv->mm.gtt->gtt).
  */
-static void gen6_ggtt_insert_entries(struct drm_device *dev,
+static void gen6_ggtt_insert_entries(struct i915_address_space *vm,
                                     struct sg_table *st,
                                     unsigned int first_entry,
                                     enum i915_cache_level level)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = vm->dev->dev_private;
        gen6_gtt_pte_t __iomem *gtt_entries =
                (gen6_gtt_pte_t __iomem *)dev_priv->gtt.gsm + first_entry;
        int i = 0;
@@ -480,8 +511,7 @@ static void gen6_ggtt_insert_entries(struct drm_device *dev,
 
        for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) {
                addr = sg_page_iter_dma_address(&sg_iter);
-               iowrite32(dev_priv->gtt.pte_encode(dev, addr, level),
-                         &gtt_entries[i]);
+               iowrite32(vm->pte_encode(addr, level), &gtt_entries[i]);
                i++;
        }
 
@@ -492,8 +522,8 @@ static void gen6_ggtt_insert_entries(struct drm_device *dev,
         * hardware should work, we must keep this posting read for paranoia.
         */
        if (i != 0)
-               WARN_ON(readl(&gtt_entries[i-1])
-                       != dev_priv->gtt.pte_encode(dev, addr, level));
+               WARN_ON(readl(&gtt_entries[i-1]) !=
+                       vm->pte_encode(addr, level));
 
        /* This next bit makes the above posting read even more important. We
         * want to flush the TLBs only after we're certain all the PTE updates
@@ -503,11 +533,11 @@ static void gen6_ggtt_insert_entries(struct drm_device *dev,
        POSTING_READ(GFX_FLSH_CNTL_GEN6);
 }
 
-static void gen6_ggtt_clear_range(struct drm_device *dev,
+static void gen6_ggtt_clear_range(struct i915_address_space *vm,
                                  unsigned int first_entry,
                                  unsigned int num_entries)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = vm->dev->dev_private;
        gen6_gtt_pte_t scratch_pte, __iomem *gtt_base =
                (gen6_gtt_pte_t __iomem *) dev_priv->gtt.gsm + first_entry;
        const int max_entries = gtt_total_entries(dev_priv->gtt) - first_entry;
@@ -518,16 +548,14 @@ static void gen6_ggtt_clear_range(struct drm_device *dev,
                 first_entry, num_entries, max_entries))
                num_entries = max_entries;
 
-       scratch_pte = dev_priv->gtt.pte_encode(dev,
-                                              dev_priv->gtt.scratch_page_dma,
-                                              I915_CACHE_LLC);
+       scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC);
        for (i = 0; i < num_entries; i++)
                iowrite32(scratch_pte, &gtt_base[i]);
        readl(gtt_base);
 }
 
 
-static void i915_ggtt_insert_entries(struct drm_device *dev,
+static void i915_ggtt_insert_entries(struct i915_address_space *vm,
                                     struct sg_table *st,
                                     unsigned int pg_start,
                                     enum i915_cache_level cache_level)
@@ -539,7 +567,7 @@ static void i915_ggtt_insert_entries(struct drm_device *dev,
 
 }
 
-static void i915_ggtt_clear_range(struct drm_device *dev,
+static void i915_ggtt_clear_range(struct i915_address_space *vm,
                                  unsigned int first_entry,
                                  unsigned int num_entries)
 {
@@ -552,10 +580,11 @@ void i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj,
 {
        struct drm_device *dev = obj->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       const unsigned long entry = i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT;
 
-       dev_priv->gtt.gtt_insert_entries(dev, obj->pages,
-                                        obj->gtt_space->start >> PAGE_SHIFT,
-                                        cache_level);
+       dev_priv->gtt.base.insert_entries(&dev_priv->gtt.base, obj->pages,
+                                         entry,
+                                         cache_level);
 
        obj->has_global_gtt_mapping = 1;
 }
@@ -564,10 +593,11 @@ void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj)
 {
        struct drm_device *dev = obj->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       const unsigned long entry = i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT;
 
-       dev_priv->gtt.gtt_clear_range(obj->base.dev,
-                                     obj->gtt_space->start >> PAGE_SHIFT,
-                                     obj->base.size >> PAGE_SHIFT);
+       dev_priv->gtt.base.clear_range(&dev_priv->gtt.base,
+                                      entry,
+                                      obj->base.size >> PAGE_SHIFT);
 
        obj->has_global_gtt_mapping = 0;
 }
@@ -626,37 +656,42 @@ void i915_gem_setup_global_gtt(struct drm_device *dev,
        BUG_ON(mappable_end > end);
 
        /* Subtract the guard page ... */
-       drm_mm_init(&dev_priv->mm.gtt_space, start, end - start - PAGE_SIZE);
+       drm_mm_init(&dev_priv->gtt.base.mm, start, end - start - PAGE_SIZE);
        if (!HAS_LLC(dev))
-               dev_priv->mm.gtt_space.color_adjust = i915_gtt_color_adjust;
+               dev_priv->gtt.base.mm.color_adjust = i915_gtt_color_adjust;
 
        /* Mark any preallocated objects as occupied */
        list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
-               DRM_DEBUG_KMS("reserving preallocated space: %x + %zx\n",
-                             obj->gtt_offset, obj->base.size);
-
-               BUG_ON(obj->gtt_space != I915_GTT_RESERVED);
-               obj->gtt_space = drm_mm_create_block(&dev_priv->mm.gtt_space,
-                                                    obj->gtt_offset,
-                                                    obj->base.size,
-                                                    false);
+               struct i915_vma *vma = __i915_gem_obj_to_vma(obj);
+               int ret;
+               DRM_DEBUG_KMS("reserving preallocated space: %lx + %zx\n",
+                             i915_gem_obj_ggtt_offset(obj), obj->base.size);
+
+               WARN_ON(i915_gem_obj_ggtt_bound(obj));
+               ret = drm_mm_reserve_node(&dev_priv->gtt.base.mm, &vma->node);
+               if (ret)
+                       DRM_DEBUG_KMS("Reservation failed\n");
                obj->has_global_gtt_mapping = 1;
+               list_add(&vma->vma_link, &obj->vma_list);
        }
 
-       dev_priv->gtt.start = start;
-       dev_priv->gtt.total = end - start;
+       dev_priv->gtt.base.start = start;
+       dev_priv->gtt.base.total = end - start;
 
        /* Clear any non-preallocated blocks */
-       drm_mm_for_each_hole(entry, &dev_priv->mm.gtt_space,
+       drm_mm_for_each_hole(entry, &dev_priv->gtt.base.mm,
                             hole_start, hole_end) {
+               const unsigned long count = (hole_end - hole_start) / PAGE_SIZE;
                DRM_DEBUG_KMS("clearing unused GTT space: [%lx, %lx]\n",
                              hole_start, hole_end);
-               dev_priv->gtt.gtt_clear_range(dev, hole_start / PAGE_SIZE,
-                                             (hole_end-hole_start) / PAGE_SIZE);
+               dev_priv->gtt.base.clear_range(&dev_priv->gtt.base,
+                                              hole_start / PAGE_SIZE,
+                                              count);
        }
 
        /* And finally clear the reserved guard page */
-       dev_priv->gtt.gtt_clear_range(dev, end / PAGE_SIZE - 1, 1);
+       dev_priv->gtt.base.clear_range(&dev_priv->gtt.base,
+                                      end / PAGE_SIZE - 1, 1);
 }
 
 static bool
@@ -679,7 +714,7 @@ void i915_gem_init_global_gtt(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long gtt_size, mappable_size;
 
-       gtt_size = dev_priv->gtt.total;
+       gtt_size = dev_priv->gtt.base.total;
        mappable_size = dev_priv->gtt.mappable_end;
 
        if (intel_enable_ppgtt(dev) && HAS_ALIASING_PPGTT(dev)) {
@@ -688,7 +723,7 @@ void i915_gem_init_global_gtt(struct drm_device *dev)
                if (INTEL_INFO(dev)->gen <= 7) {
                        /* PPGTT pdes are stolen from global gtt ptes, so shrink the
                         * aperture accordingly when using aliasing ppgtt. */
-                       gtt_size -= I915_PPGTT_PD_ENTRIES*PAGE_SIZE;
+                       gtt_size -= GEN6_PPGTT_PD_ENTRIES * PAGE_SIZE;
                }
 
                i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size);
@@ -698,8 +733,8 @@ void i915_gem_init_global_gtt(struct drm_device *dev)
                        return;
 
                DRM_ERROR("Aliased PPGTT setup failed %d\n", ret);
-               drm_mm_takedown(&dev_priv->mm.gtt_space);
-               gtt_size += I915_PPGTT_PD_ENTRIES*PAGE_SIZE;
+               drm_mm_takedown(&dev_priv->gtt.base.mm);
+               gtt_size += GEN6_PPGTT_PD_ENTRIES * PAGE_SIZE;
        }
        i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size);
 }
@@ -724,8 +759,8 @@ static int setup_scratch_page(struct drm_device *dev)
 #else
        dma_addr = page_to_phys(page);
 #endif
-       dev_priv->gtt.scratch_page = page;
-       dev_priv->gtt.scratch_page_dma = dma_addr;
+       dev_priv->gtt.base.scratch.page = page;
+       dev_priv->gtt.base.scratch.addr = dma_addr;
 
        return 0;
 }
@@ -733,11 +768,13 @@ static int setup_scratch_page(struct drm_device *dev)
 static void teardown_scratch_page(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       set_pages_wb(dev_priv->gtt.scratch_page, 1);
-       pci_unmap_page(dev->pdev, dev_priv->gtt.scratch_page_dma,
+       struct page *page = dev_priv->gtt.base.scratch.page;
+
+       set_pages_wb(page, 1);
+       pci_unmap_page(dev->pdev, dev_priv->gtt.base.scratch.addr,
                       PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
-       put_page(dev_priv->gtt.scratch_page);
-       __free_page(dev_priv->gtt.scratch_page);
+       put_page(page);
+       __free_page(page);
 }
 
 static inline unsigned int gen6_get_total_gtt_size(u16 snb_gmch_ctl)
@@ -800,17 +837,18 @@ static int gen6_gmch_probe(struct drm_device *dev,
        if (ret)
                DRM_ERROR("Scratch setup failed\n");
 
-       dev_priv->gtt.gtt_clear_range = gen6_ggtt_clear_range;
-       dev_priv->gtt.gtt_insert_entries = gen6_ggtt_insert_entries;
+       dev_priv->gtt.base.clear_range = gen6_ggtt_clear_range;
+       dev_priv->gtt.base.insert_entries = gen6_ggtt_insert_entries;
 
        return ret;
 }
 
-static void gen6_gmch_remove(struct drm_device *dev)
+static void gen6_gmch_remove(struct i915_address_space *vm)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       iounmap(dev_priv->gtt.gsm);
-       teardown_scratch_page(dev_priv->dev);
+
+       struct i915_gtt *gtt = container_of(vm, struct i915_gtt, base);
+       iounmap(gtt->gsm);
+       teardown_scratch_page(vm->dev);
 }
 
 static int i915_gmch_probe(struct drm_device *dev,
@@ -831,13 +869,13 @@ static int i915_gmch_probe(struct drm_device *dev,
        intel_gtt_get(gtt_total, stolen, mappable_base, mappable_end);
 
        dev_priv->gtt.do_idle_maps = needs_idle_maps(dev_priv->dev);
-       dev_priv->gtt.gtt_clear_range = i915_ggtt_clear_range;
-       dev_priv->gtt.gtt_insert_entries = i915_ggtt_insert_entries;
+       dev_priv->gtt.base.clear_range = i915_ggtt_clear_range;
+       dev_priv->gtt.base.insert_entries = i915_ggtt_insert_entries;
 
        return 0;
 }
 
-static void i915_gmch_remove(struct drm_device *dev)
+static void i915_gmch_remove(struct i915_address_space *vm)
 {
        intel_gmch_remove();
 }
@@ -849,34 +887,33 @@ int i915_gem_gtt_init(struct drm_device *dev)
        int ret;
 
        if (INTEL_INFO(dev)->gen <= 5) {
-               dev_priv->gtt.gtt_probe = i915_gmch_probe;
-               dev_priv->gtt.gtt_remove = i915_gmch_remove;
+               gtt->gtt_probe = i915_gmch_probe;
+               gtt->base.cleanup = i915_gmch_remove;
        } else {
-               dev_priv->gtt.gtt_probe = gen6_gmch_probe;
-               dev_priv->gtt.gtt_remove = gen6_gmch_remove;
-               if (IS_HASWELL(dev)) {
-                       dev_priv->gtt.pte_encode = hsw_pte_encode;
-               } else if (IS_VALLEYVIEW(dev)) {
-                       dev_priv->gtt.pte_encode = byt_pte_encode;
-               } else {
-                       dev_priv->gtt.pte_encode = gen6_pte_encode;
-               }
+               gtt->gtt_probe = gen6_gmch_probe;
+               gtt->base.cleanup = gen6_gmch_remove;
+               if (IS_HASWELL(dev) && dev_priv->ellc_size)
+                       gtt->base.pte_encode = iris_pte_encode;
+               else if (IS_HASWELL(dev))
+                       gtt->base.pte_encode = hsw_pte_encode;
+               else if (IS_VALLEYVIEW(dev))
+                       gtt->base.pte_encode = byt_pte_encode;
+               else
+                       gtt->base.pte_encode = gen6_pte_encode;
        }
 
-       ret = dev_priv->gtt.gtt_probe(dev, &dev_priv->gtt.total,
-                                    &dev_priv->gtt.stolen_size,
-                                    &gtt->mappable_base,
-                                    &gtt->mappable_end);
+       ret = gtt->gtt_probe(dev, &gtt->base.total, &gtt->stolen_size,
+                            &gtt->mappable_base, &gtt->mappable_end);
        if (ret)
                return ret;
 
+       gtt->base.dev = dev;
+
        /* GMADR is the PCI mmio aperture into the global GTT. */
        DRM_INFO("Memory usable by graphics device = %zdM\n",
-                dev_priv->gtt.total >> 20);
-       DRM_DEBUG_DRIVER("GMADR size = %ldM\n",
-                        dev_priv->gtt.mappable_end >> 20);
-       DRM_DEBUG_DRIVER("GTT stolen size = %zdM\n",
-                        dev_priv->gtt.stolen_size >> 20);
+                gtt->base.total >> 20);
+       DRM_DEBUG_DRIVER("GMADR size = %ldM\n", gtt->mappable_end >> 20);
+       DRM_DEBUG_DRIVER("GTT stolen size = %zdM\n", gtt->stolen_size >> 20);
 
        return 0;
 }
index 982d4732cecff93e45370f30dfab03cc1bfdb32a..cacf769c95fd05084e653369c84c94f095416243 100644 (file)
 static unsigned long i915_stolen_to_physical(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct pci_dev *pdev = dev_priv->bridge_dev;
+       struct resource *r;
        u32 base;
 
-       /* On the machines I have tested the Graphics Base of Stolen Memory
-        * is unreliable, so on those compute the base by subtracting the
-        * stolen memory from the Top of Low Usable DRAM which is where the
-        * BIOS places the graphics stolen memory.
+       /* Almost universally we can find the Graphics Base of Stolen Memory
+        * at offset 0x5c in the igfx configuration space. On a few (desktop)
+        * machines this is also mirrored in the bridge device at different
+        * locations, or in the MCHBAR. On gen2, the layout is again slightly
+        * different with the Graphics Segment immediately following Top of
+        * Memory (or Top of Usable DRAM). Note it appears that TOUD is only
+        * reported by 865g, so we just use the top of memory as determined
+        * by the e820 probe.
         *
-        * On gen2, the layout is slightly different with the Graphics Segment
-        * immediately following Top of Memory (or Top of Usable DRAM). Note
-        * it appears that TOUD is only reported by 865g, so we just use the
-        * top of memory as determined by the e820 probe.
-        *
-        * XXX gen2 requires an unavailable symbol and 945gm fails with
-        * its value of TOLUD.
+        * XXX However gen2 requires an unavailable symbol.
         */
        base = 0;
-       if (IS_VALLEYVIEW(dev)) {
+       if (INTEL_INFO(dev)->gen >= 3) {
+               /* Read Graphics Base of Stolen Memory directly */
                pci_read_config_dword(dev->pdev, 0x5c, &base);
                base &= ~((1<<20) - 1);
-       } else if (INTEL_INFO(dev)->gen >= 6) {
-               /* Read Base Data of Stolen Memory Register (BDSM) directly.
-                * Note that there is also a MCHBAR miror at 0x1080c0 or
-                * we could use device 2:0x5c instead.
-               */
-               pci_read_config_dword(pdev, 0xB0, &base);
-               base &= ~4095; /* lower bits used for locking register */
-       } else if (INTEL_INFO(dev)->gen > 3 || IS_G33(dev)) {
-               /* Read Graphics Base of Stolen Memory directly */
-               pci_read_config_dword(pdev, 0xA4, &base);
+       } else { /* GEN2 */
 #if 0
-       } else if (IS_GEN3(dev)) {
-               u8 val;
-               /* Stolen is immediately below Top of Low Usable DRAM */
-               pci_read_config_byte(pdev, 0x9c, &val);
-               base = val >> 3 << 27;
-               base -= dev_priv->mm.gtt->stolen_size;
-       } else {
                /* Stolen is immediately above Top of Memory */
                base = max_low_pfn_mapped << PAGE_SHIFT;
 #endif
        }
 
+       if (base == 0)
+               return 0;
+
+       /* Verify that nothing else uses this physical address. Stolen
+        * memory should be reserved by the BIOS and hidden from the
+        * kernel. So if the region is already marked as busy, something
+        * is seriously wrong.
+        */
+       r = devm_request_mem_region(dev->dev, base, dev_priv->gtt.stolen_size,
+                                   "Graphics Stolen Memory");
+       if (r == NULL) {
+               DRM_ERROR("conflict detected with stolen region: [0x%08x - 0x%08x]\n",
+                         base, base + (uint32_t)dev_priv->gtt.stolen_size);
+               base = 0;
+       }
+
        return base;
 }
 
@@ -120,7 +119,7 @@ static int i915_setup_compression(struct drm_device *dev, int size)
                if (!compressed_llb)
                        goto err_fb;
 
-               dev_priv->compressed_llb = compressed_llb;
+               dev_priv->fbc.compressed_llb = compressed_llb;
 
                I915_WRITE(FBC_CFB_BASE,
                           dev_priv->mm.stolen_base + compressed_fb->start);
@@ -128,8 +127,8 @@ static int i915_setup_compression(struct drm_device *dev, int size)
                           dev_priv->mm.stolen_base + compressed_llb->start);
        }
 
-       dev_priv->compressed_fb = compressed_fb;
-       dev_priv->cfb_size = size;
+       dev_priv->fbc.compressed_fb = compressed_fb;
+       dev_priv->fbc.size = size;
 
        DRM_DEBUG_KMS("reserved %d bytes of contiguous stolen space for FBC\n",
                      size);
@@ -150,7 +149,7 @@ int i915_gem_stolen_setup_compression(struct drm_device *dev, int size)
        if (!drm_mm_initialized(&dev_priv->mm.stolen))
                return -ENODEV;
 
-       if (size < dev_priv->cfb_size)
+       if (size < dev_priv->fbc.size)
                return 0;
 
        /* Release any current block */
@@ -163,16 +162,16 @@ void i915_gem_stolen_cleanup_compression(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       if (dev_priv->cfb_size == 0)
+       if (dev_priv->fbc.size == 0)
                return;
 
-       if (dev_priv->compressed_fb)
-               drm_mm_put_block(dev_priv->compressed_fb);
+       if (dev_priv->fbc.compressed_fb)
+               drm_mm_put_block(dev_priv->fbc.compressed_fb);
 
-       if (dev_priv->compressed_llb)
-               drm_mm_put_block(dev_priv->compressed_llb);
+       if (dev_priv->fbc.compressed_llb)
+               drm_mm_put_block(dev_priv->fbc.compressed_llb);
 
-       dev_priv->cfb_size = 0;
+       dev_priv->fbc.size = 0;
 }
 
 void i915_gem_cleanup_stolen(struct drm_device *dev)
@@ -201,6 +200,9 @@ int i915_gem_init_stolen(struct drm_device *dev)
        if (IS_VALLEYVIEW(dev))
                bios_reserved = 1024*1024; /* top 1M on VLV/BYT */
 
+       if (WARN_ON(bios_reserved > dev_priv->gtt.stolen_size))
+               return 0;
+
        /* Basic memrange allocator for stolen space */
        drm_mm_init(&dev_priv->mm.stolen, 0, dev_priv->gtt.stolen_size -
                    bios_reserved);
@@ -271,9 +273,7 @@ _i915_gem_object_create_stolen(struct drm_device *dev,
        if (obj == NULL)
                return NULL;
 
-       if (drm_gem_private_object_init(dev, &obj->base, stolen->size))
-               goto cleanup;
-
+       drm_gem_private_object_init(dev, &obj->base, stolen->size);
        i915_gem_object_init(obj, &i915_gem_object_stolen_ops);
 
        obj->pages = i915_pages_create_for_stolen(dev,
@@ -331,8 +331,11 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev,
                                               u32 size)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       struct i915_address_space *vm = &dev_priv->gtt.base;
        struct drm_i915_gem_object *obj;
        struct drm_mm_node *stolen;
+       struct i915_vma *vma;
+       int ret;
 
        if (!drm_mm_initialized(&dev_priv->mm.stolen))
                return NULL;
@@ -347,11 +350,16 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev,
        if (WARN_ON(size == 0))
                return NULL;
 
-       stolen = drm_mm_create_block(&dev_priv->mm.stolen,
-                                    stolen_offset, size,
-                                    false);
-       if (stolen == NULL) {
+       stolen = kzalloc(sizeof(*stolen), GFP_KERNEL);
+       if (!stolen)
+               return NULL;
+
+       stolen->start = stolen_offset;
+       stolen->size = size;
+       ret = drm_mm_reserve_node(&dev_priv->mm.stolen, stolen);
+       if (ret) {
                DRM_DEBUG_KMS("failed to allocate stolen space\n");
+               kfree(stolen);
                return NULL;
        }
 
@@ -363,33 +371,42 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev,
        }
 
        /* Some objects just need physical mem from stolen space */
-       if (gtt_offset == -1)
+       if (gtt_offset == I915_GTT_OFFSET_NONE)
                return obj;
 
+       vma = i915_gem_vma_create(obj, &dev_priv->gtt.base);
+       if (IS_ERR(vma)) {
+               ret = PTR_ERR(vma);
+               goto err_out;
+       }
+
        /* To simplify the initialisation sequence between KMS and GTT,
         * we allow construction of the stolen object prior to
         * setting up the GTT space. The actual reservation will occur
         * later.
         */
-       if (drm_mm_initialized(&dev_priv->mm.gtt_space)) {
-               obj->gtt_space = drm_mm_create_block(&dev_priv->mm.gtt_space,
-                                                    gtt_offset, size,
-                                                    false);
-               if (obj->gtt_space == NULL) {
+       vma->node.start = gtt_offset;
+       vma->node.size = size;
+       if (drm_mm_initialized(&dev_priv->gtt.base.mm)) {
+               ret = drm_mm_reserve_node(&dev_priv->gtt.base.mm, &vma->node);
+               if (ret) {
                        DRM_DEBUG_KMS("failed to allocate stolen GTT space\n");
-                       drm_gem_object_unreference(&obj->base);
-                       return NULL;
+                       i915_gem_vma_destroy(vma);
+                       goto err_out;
                }
-       } else
-               obj->gtt_space = I915_GTT_RESERVED;
+       }
 
-       obj->gtt_offset = gtt_offset;
        obj->has_global_gtt_mapping = 1;
 
        list_add_tail(&obj->global_list, &dev_priv->mm.bound_list);
-       list_add_tail(&obj->mm_list, &dev_priv->mm.inactive_list);
+       list_add_tail(&obj->mm_list, &vm->inactive_list);
 
        return obj;
+
+err_out:
+       drm_mm_put_block(stolen);
+       drm_gem_object_unreference(&obj->base);
+       return NULL;
 }
 
 void
index 537545be69db89fb8c2d19e692a94cca0b418bf8..92a8d279ca39749d6582cb412e874d21c07416cd 100644 (file)
@@ -268,18 +268,18 @@ i915_gem_object_fence_ok(struct drm_i915_gem_object *obj, int tiling_mode)
                return true;
 
        if (INTEL_INFO(obj->base.dev)->gen == 3) {
-               if (obj->gtt_offset & ~I915_FENCE_START_MASK)
+               if (i915_gem_obj_ggtt_offset(obj) & ~I915_FENCE_START_MASK)
                        return false;
        } else {
-               if (obj->gtt_offset & ~I830_FENCE_START_MASK)
+               if (i915_gem_obj_ggtt_offset(obj) & ~I830_FENCE_START_MASK)
                        return false;
        }
 
        size = i915_gem_get_gtt_size(obj->base.dev, obj->base.size, tiling_mode);
-       if (obj->gtt_space->size != size)
+       if (i915_gem_obj_ggtt_size(obj) != size)
                return false;
 
-       if (obj->gtt_offset & (size - 1))
+       if (i915_gem_obj_ggtt_offset(obj) & (size - 1))
                return false;
 
        return true;
@@ -359,8 +359,8 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
                 */
 
                obj->map_and_fenceable =
-                       obj->gtt_space == NULL ||
-                       (obj->gtt_offset + obj->base.size <= dev_priv->gtt.mappable_end &&
+                       !i915_gem_obj_ggtt_bound(obj) ||
+                       (i915_gem_obj_ggtt_offset(obj) + obj->base.size <= dev_priv->gtt.mappable_end &&
                         i915_gem_object_fence_ok(obj, args->tiling_mode));
 
                /* Rebind if we need a change of alignment */
@@ -369,7 +369,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
                                i915_gem_get_gtt_alignment(dev, obj->base.size,
                                                            args->tiling_mode,
                                                            false);
-                       if (obj->gtt_offset & (unfenced_alignment - 1))
+                       if (i915_gem_obj_ggtt_offset(obj) & (unfenced_alignment - 1))
                                ret = i915_gem_object_unbind(obj);
                }
 
diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c
new file mode 100644 (file)
index 0000000..d970d84
--- /dev/null
@@ -0,0 +1,973 @@
+/*
+ * Copyright (c) 2008 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Eric Anholt <eric@anholt.net>
+ *    Keith Packard <keithp@keithp.com>
+ *    Mika Kuoppala <mika.kuoppala@intel.com>
+ *
+ */
+
+#include <generated/utsrelease.h>
+#include "i915_drv.h"
+
+static const char *yesno(int v)
+{
+       return v ? "yes" : "no";
+}
+
+static const char *ring_str(int ring)
+{
+       switch (ring) {
+       case RCS: return "render";
+       case VCS: return "bsd";
+       case BCS: return "blt";
+       case VECS: return "vebox";
+       default: return "";
+       }
+}
+
+static const char *pin_flag(int pinned)
+{
+       if (pinned > 0)
+               return " P";
+       else if (pinned < 0)
+               return " p";
+       else
+               return "";
+}
+
+static const char *tiling_flag(int tiling)
+{
+       switch (tiling) {
+       default:
+       case I915_TILING_NONE: return "";
+       case I915_TILING_X: return " X";
+       case I915_TILING_Y: return " Y";
+       }
+}
+
+static const char *dirty_flag(int dirty)
+{
+       return dirty ? " dirty" : "";
+}
+
+static const char *purgeable_flag(int purgeable)
+{
+       return purgeable ? " purgeable" : "";
+}
+
+static bool __i915_error_ok(struct drm_i915_error_state_buf *e)
+{
+
+       if (!e->err && WARN(e->bytes > (e->size - 1), "overflow")) {
+               e->err = -ENOSPC;
+               return false;
+       }
+
+       if (e->bytes == e->size - 1 || e->err)
+               return false;
+
+       return true;
+}
+
+static bool __i915_error_seek(struct drm_i915_error_state_buf *e,
+                             unsigned len)
+{
+       if (e->pos + len <= e->start) {
+               e->pos += len;
+               return false;
+       }
+
+       /* First vsnprintf needs to fit in its entirety for memmove */
+       if (len >= e->size) {
+               e->err = -EIO;
+               return false;
+       }
+
+       return true;
+}
+
+static void __i915_error_advance(struct drm_i915_error_state_buf *e,
+                                unsigned len)
+{
+       /* If this is first printf in this window, adjust it so that
+        * start position matches start of the buffer
+        */
+
+       if (e->pos < e->start) {
+               const size_t off = e->start - e->pos;
+
+               /* Should not happen but be paranoid */
+               if (off > len || e->bytes) {
+                       e->err = -EIO;
+                       return;
+               }
+
+               memmove(e->buf, e->buf + off, len - off);
+               e->bytes = len - off;
+               e->pos = e->start;
+               return;
+       }
+
+       e->bytes += len;
+       e->pos += len;
+}
+
+static void i915_error_vprintf(struct drm_i915_error_state_buf *e,
+                              const char *f, va_list args)
+{
+       unsigned len;
+
+       if (!__i915_error_ok(e))
+               return;
+
+       /* Seek the first printf which is hits start position */
+       if (e->pos < e->start) {
+               len = vsnprintf(NULL, 0, f, args);
+               if (!__i915_error_seek(e, len))
+                       return;
+       }
+
+       len = vsnprintf(e->buf + e->bytes, e->size - e->bytes, f, args);
+       if (len >= e->size - e->bytes)
+               len = e->size - e->bytes - 1;
+
+       __i915_error_advance(e, len);
+}
+
+static void i915_error_puts(struct drm_i915_error_state_buf *e,
+                           const char *str)
+{
+       unsigned len;
+
+       if (!__i915_error_ok(e))
+               return;
+
+       len = strlen(str);
+
+       /* Seek the first printf which is hits start position */
+       if (e->pos < e->start) {
+               if (!__i915_error_seek(e, len))
+                       return;
+       }
+
+       if (len >= e->size - e->bytes)
+               len = e->size - e->bytes - 1;
+       memcpy(e->buf + e->bytes, str, len);
+
+       __i915_error_advance(e, len);
+}
+
+#define err_printf(e, ...) i915_error_printf(e, __VA_ARGS__)
+#define err_puts(e, s) i915_error_puts(e, s)
+
+static void print_error_buffers(struct drm_i915_error_state_buf *m,
+                               const char *name,
+                               struct drm_i915_error_buffer *err,
+                               int count)
+{
+       err_printf(m, "%s [%d]:\n", name, count);
+
+       while (count--) {
+               err_printf(m, "  %08x %8u %02x %02x %x %x",
+                          err->gtt_offset,
+                          err->size,
+                          err->read_domains,
+                          err->write_domain,
+                          err->rseqno, err->wseqno);
+               err_puts(m, pin_flag(err->pinned));
+               err_puts(m, tiling_flag(err->tiling));
+               err_puts(m, dirty_flag(err->dirty));
+               err_puts(m, purgeable_flag(err->purgeable));
+               err_puts(m, err->ring != -1 ? " " : "");
+               err_puts(m, ring_str(err->ring));
+               err_puts(m, i915_cache_level_str(err->cache_level));
+
+               if (err->name)
+                       err_printf(m, " (name: %d)", err->name);
+               if (err->fence_reg != I915_FENCE_REG_NONE)
+                       err_printf(m, " (fence: %d)", err->fence_reg);
+
+               err_puts(m, "\n");
+               err++;
+       }
+}
+
+static void i915_ring_error_state(struct drm_i915_error_state_buf *m,
+                                 struct drm_device *dev,
+                                 struct drm_i915_error_state *error,
+                                 unsigned ring)
+{
+       BUG_ON(ring >= I915_NUM_RINGS); /* shut up confused gcc */
+       err_printf(m, "%s command stream:\n", ring_str(ring));
+       err_printf(m, "  HEAD: 0x%08x\n", error->head[ring]);
+       err_printf(m, "  TAIL: 0x%08x\n", error->tail[ring]);
+       err_printf(m, "  CTL: 0x%08x\n", error->ctl[ring]);
+       err_printf(m, "  ACTHD: 0x%08x\n", error->acthd[ring]);
+       err_printf(m, "  IPEIR: 0x%08x\n", error->ipeir[ring]);
+       err_printf(m, "  IPEHR: 0x%08x\n", error->ipehr[ring]);
+       err_printf(m, "  INSTDONE: 0x%08x\n", error->instdone[ring]);
+       if (ring == RCS && INTEL_INFO(dev)->gen >= 4)
+               err_printf(m, "  BBADDR: 0x%08llx\n", error->bbaddr);
+
+       if (INTEL_INFO(dev)->gen >= 4)
+               err_printf(m, "  INSTPS: 0x%08x\n", error->instps[ring]);
+       err_printf(m, "  INSTPM: 0x%08x\n", error->instpm[ring]);
+       err_printf(m, "  FADDR: 0x%08x\n", error->faddr[ring]);
+       if (INTEL_INFO(dev)->gen >= 6) {
+               err_printf(m, "  RC PSMI: 0x%08x\n", error->rc_psmi[ring]);
+               err_printf(m, "  FAULT_REG: 0x%08x\n", error->fault_reg[ring]);
+               err_printf(m, "  SYNC_0: 0x%08x [last synced 0x%08x]\n",
+                          error->semaphore_mboxes[ring][0],
+                          error->semaphore_seqno[ring][0]);
+               err_printf(m, "  SYNC_1: 0x%08x [last synced 0x%08x]\n",
+                          error->semaphore_mboxes[ring][1],
+                          error->semaphore_seqno[ring][1]);
+       }
+       err_printf(m, "  seqno: 0x%08x\n", error->seqno[ring]);
+       err_printf(m, "  waiting: %s\n", yesno(error->waiting[ring]));
+       err_printf(m, "  ring->head: 0x%08x\n", error->cpu_ring_head[ring]);
+       err_printf(m, "  ring->tail: 0x%08x\n", error->cpu_ring_tail[ring]);
+}
+
+void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...)
+{
+       va_list args;
+
+       va_start(args, f);
+       i915_error_vprintf(e, f, args);
+       va_end(args);
+}
+
+int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
+                           const struct i915_error_state_file_priv *error_priv)
+{
+       struct drm_device *dev = error_priv->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_error_state *error = error_priv->error;
+       struct intel_ring_buffer *ring;
+       int i, j, page, offset, elt;
+
+       if (!error) {
+               err_printf(m, "no error state collected\n");
+               goto out;
+       }
+
+       err_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec,
+                  error->time.tv_usec);
+       err_printf(m, "Kernel: " UTS_RELEASE "\n");
+       err_printf(m, "PCI ID: 0x%04x\n", dev->pci_device);
+       err_printf(m, "EIR: 0x%08x\n", error->eir);
+       err_printf(m, "IER: 0x%08x\n", error->ier);
+       err_printf(m, "PGTBL_ER: 0x%08x\n", error->pgtbl_er);
+       err_printf(m, "FORCEWAKE: 0x%08x\n", error->forcewake);
+       err_printf(m, "DERRMR: 0x%08x\n", error->derrmr);
+       err_printf(m, "CCID: 0x%08x\n", error->ccid);
+
+       for (i = 0; i < dev_priv->num_fence_regs; i++)
+               err_printf(m, "  fence[%d] = %08llx\n", i, error->fence[i]);
+
+       for (i = 0; i < ARRAY_SIZE(error->extra_instdone); i++)
+               err_printf(m, "  INSTDONE_%d: 0x%08x\n", i,
+                          error->extra_instdone[i]);
+
+       if (INTEL_INFO(dev)->gen >= 6) {
+               err_printf(m, "ERROR: 0x%08x\n", error->error);
+               err_printf(m, "DONE_REG: 0x%08x\n", error->done_reg);
+       }
+
+       if (INTEL_INFO(dev)->gen == 7)
+               err_printf(m, "ERR_INT: 0x%08x\n", error->err_int);
+
+       for_each_ring(ring, dev_priv, i)
+               i915_ring_error_state(m, dev, error, i);
+
+       if (error->active_bo)
+               print_error_buffers(m, "Active",
+                                   error->active_bo,
+                                   error->active_bo_count);
+
+       if (error->pinned_bo)
+               print_error_buffers(m, "Pinned",
+                                   error->pinned_bo,
+                                   error->pinned_bo_count);
+
+       for (i = 0; i < ARRAY_SIZE(error->ring); i++) {
+               struct drm_i915_error_object *obj;
+
+               if ((obj = error->ring[i].batchbuffer)) {
+                       err_printf(m, "%s --- gtt_offset = 0x%08x\n",
+                                  dev_priv->ring[i].name,
+                                  obj->gtt_offset);
+                       offset = 0;
+                       for (page = 0; page < obj->page_count; page++) {
+                               for (elt = 0; elt < PAGE_SIZE/4; elt++) {
+                                       err_printf(m, "%08x :  %08x\n", offset,
+                                                  obj->pages[page][elt]);
+                                       offset += 4;
+                               }
+                       }
+               }
+
+               if (error->ring[i].num_requests) {
+                       err_printf(m, "%s --- %d requests\n",
+                                  dev_priv->ring[i].name,
+                                  error->ring[i].num_requests);
+                       for (j = 0; j < error->ring[i].num_requests; j++) {
+                               err_printf(m, "  seqno 0x%08x, emitted %ld, tail 0x%08x\n",
+                                          error->ring[i].requests[j].seqno,
+                                          error->ring[i].requests[j].jiffies,
+                                          error->ring[i].requests[j].tail);
+                       }
+               }
+
+               if ((obj = error->ring[i].ringbuffer)) {
+                       err_printf(m, "%s --- ringbuffer = 0x%08x\n",
+                                  dev_priv->ring[i].name,
+                                  obj->gtt_offset);
+                       offset = 0;
+                       for (page = 0; page < obj->page_count; page++) {
+                               for (elt = 0; elt < PAGE_SIZE/4; elt++) {
+                                       err_printf(m, "%08x :  %08x\n",
+                                                  offset,
+                                                  obj->pages[page][elt]);
+                                       offset += 4;
+                               }
+                       }
+               }
+
+               obj = error->ring[i].ctx;
+               if (obj) {
+                       err_printf(m, "%s --- HW Context = 0x%08x\n",
+                                  dev_priv->ring[i].name,
+                                  obj->gtt_offset);
+                       offset = 0;
+                       for (elt = 0; elt < PAGE_SIZE/16; elt += 4) {
+                               err_printf(m, "[%04x] %08x %08x %08x %08x\n",
+                                          offset,
+                                          obj->pages[0][elt],
+                                          obj->pages[0][elt+1],
+                                          obj->pages[0][elt+2],
+                                          obj->pages[0][elt+3]);
+                                       offset += 16;
+                       }
+               }
+       }
+
+       if (error->overlay)
+               intel_overlay_print_error_state(m, error->overlay);
+
+       if (error->display)
+               intel_display_print_error_state(m, dev, error->display);
+
+out:
+       if (m->bytes == 0 && m->err)
+               return m->err;
+
+       return 0;
+}
+
+int i915_error_state_buf_init(struct drm_i915_error_state_buf *ebuf,
+                             size_t count, loff_t pos)
+{
+       memset(ebuf, 0, sizeof(*ebuf));
+
+       /* We need to have enough room to store any i915_error_state printf
+        * so that we can move it to start position.
+        */
+       ebuf->size = count + 1 > PAGE_SIZE ? count + 1 : PAGE_SIZE;
+       ebuf->buf = kmalloc(ebuf->size,
+                               GFP_TEMPORARY | __GFP_NORETRY | __GFP_NOWARN);
+
+       if (ebuf->buf == NULL) {
+               ebuf->size = PAGE_SIZE;
+               ebuf->buf = kmalloc(ebuf->size, GFP_TEMPORARY);
+       }
+
+       if (ebuf->buf == NULL) {
+               ebuf->size = 128;
+               ebuf->buf = kmalloc(ebuf->size, GFP_TEMPORARY);
+       }
+
+       if (ebuf->buf == NULL)
+               return -ENOMEM;
+
+       ebuf->start = pos;
+
+       return 0;
+}
+
+static void i915_error_object_free(struct drm_i915_error_object *obj)
+{
+       int page;
+
+       if (obj == NULL)
+               return;
+
+       for (page = 0; page < obj->page_count; page++)
+               kfree(obj->pages[page]);
+
+       kfree(obj);
+}
+
+static void i915_error_state_free(struct kref *error_ref)
+{
+       struct drm_i915_error_state *error = container_of(error_ref,
+                                                         typeof(*error), ref);
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(error->ring); i++) {
+               i915_error_object_free(error->ring[i].batchbuffer);
+               i915_error_object_free(error->ring[i].ringbuffer);
+               i915_error_object_free(error->ring[i].ctx);
+               kfree(error->ring[i].requests);
+       }
+
+       kfree(error->active_bo);
+       kfree(error->overlay);
+       kfree(error->display);
+       kfree(error);
+}
+
+static struct drm_i915_error_object *
+i915_error_object_create_sized(struct drm_i915_private *dev_priv,
+                              struct drm_i915_gem_object *src,
+                              const int num_pages)
+{
+       struct drm_i915_error_object *dst;
+       int i;
+       u32 reloc_offset;
+
+       if (src == NULL || src->pages == NULL)
+               return NULL;
+
+       dst = kmalloc(sizeof(*dst) + num_pages * sizeof(u32 *), GFP_ATOMIC);
+       if (dst == NULL)
+               return NULL;
+
+       reloc_offset = dst->gtt_offset = i915_gem_obj_ggtt_offset(src);
+       for (i = 0; i < num_pages; i++) {
+               unsigned long flags;
+               void *d;
+
+               d = kmalloc(PAGE_SIZE, GFP_ATOMIC);
+               if (d == NULL)
+                       goto unwind;
+
+               local_irq_save(flags);
+               if (reloc_offset < dev_priv->gtt.mappable_end &&
+                   src->has_global_gtt_mapping) {
+                       void __iomem *s;
+
+                       /* Simply ignore tiling or any overlapping fence.
+                        * It's part of the error state, and this hopefully
+                        * captures what the GPU read.
+                        */
+
+                       s = io_mapping_map_atomic_wc(dev_priv->gtt.mappable,
+                                                    reloc_offset);
+                       memcpy_fromio(d, s, PAGE_SIZE);
+                       io_mapping_unmap_atomic(s);
+               } else if (src->stolen) {
+                       unsigned long offset;
+
+                       offset = dev_priv->mm.stolen_base;
+                       offset += src->stolen->start;
+                       offset += i << PAGE_SHIFT;
+
+                       memcpy_fromio(d, (void __iomem *) offset, PAGE_SIZE);
+               } else {
+                       struct page *page;
+                       void *s;
+
+                       page = i915_gem_object_get_page(src, i);
+
+                       drm_clflush_pages(&page, 1);
+
+                       s = kmap_atomic(page);
+                       memcpy(d, s, PAGE_SIZE);
+                       kunmap_atomic(s);
+
+                       drm_clflush_pages(&page, 1);
+               }
+               local_irq_restore(flags);
+
+               dst->pages[i] = d;
+
+               reloc_offset += PAGE_SIZE;
+       }
+       dst->page_count = num_pages;
+
+       return dst;
+
+unwind:
+       while (i--)
+               kfree(dst->pages[i]);
+       kfree(dst);
+       return NULL;
+}
+#define i915_error_object_create(dev_priv, src) \
+       i915_error_object_create_sized((dev_priv), (src), \
+                                      (src)->base.size>>PAGE_SHIFT)
+
+static void capture_bo(struct drm_i915_error_buffer *err,
+                      struct drm_i915_gem_object *obj)
+{
+       err->size = obj->base.size;
+       err->name = obj->base.name;
+       err->rseqno = obj->last_read_seqno;
+       err->wseqno = obj->last_write_seqno;
+       err->gtt_offset = i915_gem_obj_ggtt_offset(obj);
+       err->read_domains = obj->base.read_domains;
+       err->write_domain = obj->base.write_domain;
+       err->fence_reg = obj->fence_reg;
+       err->pinned = 0;
+       if (obj->pin_count > 0)
+               err->pinned = 1;
+       if (obj->user_pin_count > 0)
+               err->pinned = -1;
+       err->tiling = obj->tiling_mode;
+       err->dirty = obj->dirty;
+       err->purgeable = obj->madv != I915_MADV_WILLNEED;
+       err->ring = obj->ring ? obj->ring->id : -1;
+       err->cache_level = obj->cache_level;
+}
+
+static u32 capture_active_bo(struct drm_i915_error_buffer *err,
+                            int count, struct list_head *head)
+{
+       struct drm_i915_gem_object *obj;
+       int i = 0;
+
+       list_for_each_entry(obj, head, mm_list) {
+               capture_bo(err++, obj);
+               if (++i == count)
+                       break;
+       }
+
+       return i;
+}
+
+static u32 capture_pinned_bo(struct drm_i915_error_buffer *err,
+                            int count, struct list_head *head)
+{
+       struct drm_i915_gem_object *obj;
+       int i = 0;
+
+       list_for_each_entry(obj, head, global_list) {
+               if (obj->pin_count == 0)
+                       continue;
+
+               capture_bo(err++, obj);
+               if (++i == count)
+                       break;
+       }
+
+       return i;
+}
+
+static void i915_gem_record_fences(struct drm_device *dev,
+                                  struct drm_i915_error_state *error)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int i;
+
+       /* Fences */
+       switch (INTEL_INFO(dev)->gen) {
+       case 7:
+       case 6:
+               for (i = 0; i < dev_priv->num_fence_regs; i++)
+                       error->fence[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8));
+               break;
+       case 5:
+       case 4:
+               for (i = 0; i < 16; i++)
+                       error->fence[i] = I915_READ64(FENCE_REG_965_0 + (i * 8));
+               break;
+       case 3:
+               if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
+                       for (i = 0; i < 8; i++)
+                               error->fence[i+8] = I915_READ(FENCE_REG_945_8 + (i * 4));
+       case 2:
+               for (i = 0; i < 8; i++)
+                       error->fence[i] = I915_READ(FENCE_REG_830_0 + (i * 4));
+               break;
+
+       default:
+               BUG();
+       }
+}
+
+static struct drm_i915_error_object *
+i915_error_first_batchbuffer(struct drm_i915_private *dev_priv,
+                            struct intel_ring_buffer *ring)
+{
+       struct i915_address_space *vm = &dev_priv->gtt.base;
+       struct drm_i915_gem_object *obj;
+       u32 seqno;
+
+       if (!ring->get_seqno)
+               return NULL;
+
+       if (HAS_BROKEN_CS_TLB(dev_priv->dev)) {
+               u32 acthd = I915_READ(ACTHD);
+
+               if (WARN_ON(ring->id != RCS))
+                       return NULL;
+
+               obj = ring->private;
+               if (acthd >= i915_gem_obj_ggtt_offset(obj) &&
+                   acthd < i915_gem_obj_ggtt_offset(obj) + obj->base.size)
+                       return i915_error_object_create(dev_priv, obj);
+       }
+
+       seqno = ring->get_seqno(ring, false);
+       list_for_each_entry(obj, &vm->active_list, mm_list) {
+               if (obj->ring != ring)
+                       continue;
+
+               if (i915_seqno_passed(seqno, obj->last_read_seqno))
+                       continue;
+
+               if ((obj->base.read_domains & I915_GEM_DOMAIN_COMMAND) == 0)
+                       continue;
+
+               /* We need to copy these to an anonymous buffer as the simplest
+                * method to avoid being overwritten by userspace.
+                */
+               return i915_error_object_create(dev_priv, obj);
+       }
+
+       return NULL;
+}
+
+static void i915_record_ring_state(struct drm_device *dev,
+                                  struct drm_i915_error_state *error,
+                                  struct intel_ring_buffer *ring)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (INTEL_INFO(dev)->gen >= 6) {
+               error->rc_psmi[ring->id] = I915_READ(ring->mmio_base + 0x50);
+               error->fault_reg[ring->id] = I915_READ(RING_FAULT_REG(ring));
+               error->semaphore_mboxes[ring->id][0]
+                       = I915_READ(RING_SYNC_0(ring->mmio_base));
+               error->semaphore_mboxes[ring->id][1]
+                       = I915_READ(RING_SYNC_1(ring->mmio_base));
+               error->semaphore_seqno[ring->id][0] = ring->sync_seqno[0];
+               error->semaphore_seqno[ring->id][1] = ring->sync_seqno[1];
+       }
+
+       if (INTEL_INFO(dev)->gen >= 4) {
+               error->faddr[ring->id] = I915_READ(RING_DMA_FADD(ring->mmio_base));
+               error->ipeir[ring->id] = I915_READ(RING_IPEIR(ring->mmio_base));
+               error->ipehr[ring->id] = I915_READ(RING_IPEHR(ring->mmio_base));
+               error->instdone[ring->id] = I915_READ(RING_INSTDONE(ring->mmio_base));
+               error->instps[ring->id] = I915_READ(RING_INSTPS(ring->mmio_base));
+               if (ring->id == RCS)
+                       error->bbaddr = I915_READ64(BB_ADDR);
+       } else {
+               error->faddr[ring->id] = I915_READ(DMA_FADD_I8XX);
+               error->ipeir[ring->id] = I915_READ(IPEIR);
+               error->ipehr[ring->id] = I915_READ(IPEHR);
+               error->instdone[ring->id] = I915_READ(INSTDONE);
+       }
+
+       error->waiting[ring->id] = waitqueue_active(&ring->irq_queue);
+       error->instpm[ring->id] = I915_READ(RING_INSTPM(ring->mmio_base));
+       error->seqno[ring->id] = ring->get_seqno(ring, false);
+       error->acthd[ring->id] = intel_ring_get_active_head(ring);
+       error->head[ring->id] = I915_READ_HEAD(ring);
+       error->tail[ring->id] = I915_READ_TAIL(ring);
+       error->ctl[ring->id] = I915_READ_CTL(ring);
+
+       error->cpu_ring_head[ring->id] = ring->head;
+       error->cpu_ring_tail[ring->id] = ring->tail;
+}
+
+
+static void i915_gem_record_active_context(struct intel_ring_buffer *ring,
+                                          struct drm_i915_error_state *error,
+                                          struct drm_i915_error_ring *ering)
+{
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+       struct drm_i915_gem_object *obj;
+
+       /* Currently render ring is the only HW context user */
+       if (ring->id != RCS || !error->ccid)
+               return;
+
+       list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
+               if ((error->ccid & PAGE_MASK) == i915_gem_obj_ggtt_offset(obj)) {
+                       ering->ctx = i915_error_object_create_sized(dev_priv,
+                                                                   obj, 1);
+                       break;
+               }
+       }
+}
+
+static void i915_gem_record_rings(struct drm_device *dev,
+                                 struct drm_i915_error_state *error)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_ring_buffer *ring;
+       struct drm_i915_gem_request *request;
+       int i, count;
+
+       for_each_ring(ring, dev_priv, i) {
+               i915_record_ring_state(dev, error, ring);
+
+               error->ring[i].batchbuffer =
+                       i915_error_first_batchbuffer(dev_priv, ring);
+
+               error->ring[i].ringbuffer =
+                       i915_error_object_create(dev_priv, ring->obj);
+
+
+               i915_gem_record_active_context(ring, error, &error->ring[i]);
+
+               count = 0;
+               list_for_each_entry(request, &ring->request_list, list)
+                       count++;
+
+               error->ring[i].num_requests = count;
+               error->ring[i].requests =
+                       kmalloc(count*sizeof(struct drm_i915_error_request),
+                               GFP_ATOMIC);
+               if (error->ring[i].requests == NULL) {
+                       error->ring[i].num_requests = 0;
+                       continue;
+               }
+
+               count = 0;
+               list_for_each_entry(request, &ring->request_list, list) {
+                       struct drm_i915_error_request *erq;
+
+                       erq = &error->ring[i].requests[count++];
+                       erq->seqno = request->seqno;
+                       erq->jiffies = request->emitted_jiffies;
+                       erq->tail = request->tail;
+               }
+       }
+}
+
+static void i915_gem_capture_buffers(struct drm_i915_private *dev_priv,
+                                    struct drm_i915_error_state *error)
+{
+       struct i915_address_space *vm = &dev_priv->gtt.base;
+       struct drm_i915_gem_object *obj;
+       int i;
+
+       i = 0;
+       list_for_each_entry(obj, &vm->active_list, mm_list)
+               i++;
+       error->active_bo_count = i;
+       list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list)
+               if (obj->pin_count)
+                       i++;
+       error->pinned_bo_count = i - error->active_bo_count;
+
+       if (i) {
+               error->active_bo = kmalloc(sizeof(*error->active_bo)*i,
+                                          GFP_ATOMIC);
+               if (error->active_bo)
+                       error->pinned_bo =
+                               error->active_bo + error->active_bo_count;
+       }
+
+       if (error->active_bo)
+               error->active_bo_count =
+                       capture_active_bo(error->active_bo,
+                                         error->active_bo_count,
+                                         &vm->active_list);
+
+       if (error->pinned_bo)
+               error->pinned_bo_count =
+                       capture_pinned_bo(error->pinned_bo,
+                                         error->pinned_bo_count,
+                                         &dev_priv->mm.bound_list);
+}
+
+/**
+ * i915_capture_error_state - capture an error record for later analysis
+ * @dev: drm device
+ *
+ * Should be called when an error is detected (either a hang or an error
+ * interrupt) to capture error state from the time of the error.  Fills
+ * out a structure which becomes available in debugfs for user level tools
+ * to pick up.
+ */
+void i915_capture_error_state(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_error_state *error;
+       unsigned long flags;
+       int pipe;
+
+       spin_lock_irqsave(&dev_priv->gpu_error.lock, flags);
+       error = dev_priv->gpu_error.first_error;
+       spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags);
+       if (error)
+               return;
+
+       /* Account for pipe specific data like PIPE*STAT */
+       error = kzalloc(sizeof(*error), GFP_ATOMIC);
+       if (!error) {
+               DRM_DEBUG_DRIVER("out of memory, not capturing error state\n");
+               return;
+       }
+
+       DRM_INFO("capturing error event; look for more information in "
+                "/sys/class/drm/card%d/error\n", dev->primary->index);
+
+       kref_init(&error->ref);
+       error->eir = I915_READ(EIR);
+       error->pgtbl_er = I915_READ(PGTBL_ER);
+       if (HAS_HW_CONTEXTS(dev))
+               error->ccid = I915_READ(CCID);
+
+       if (HAS_PCH_SPLIT(dev))
+               error->ier = I915_READ(DEIER) | I915_READ(GTIER);
+       else if (IS_VALLEYVIEW(dev))
+               error->ier = I915_READ(GTIER) | I915_READ(VLV_IER);
+       else if (IS_GEN2(dev))
+               error->ier = I915_READ16(IER);
+       else
+               error->ier = I915_READ(IER);
+
+       if (INTEL_INFO(dev)->gen >= 6)
+               error->derrmr = I915_READ(DERRMR);
+
+       if (IS_VALLEYVIEW(dev))
+               error->forcewake = I915_READ(FORCEWAKE_VLV);
+       else if (INTEL_INFO(dev)->gen >= 7)
+               error->forcewake = I915_READ(FORCEWAKE_MT);
+       else if (INTEL_INFO(dev)->gen == 6)
+               error->forcewake = I915_READ(FORCEWAKE);
+
+       if (!HAS_PCH_SPLIT(dev))
+               for_each_pipe(pipe)
+                       error->pipestat[pipe] = I915_READ(PIPESTAT(pipe));
+
+       if (INTEL_INFO(dev)->gen >= 6) {
+               error->error = I915_READ(ERROR_GEN6);
+               error->done_reg = I915_READ(DONE_REG);
+       }
+
+       if (INTEL_INFO(dev)->gen == 7)
+               error->err_int = I915_READ(GEN7_ERR_INT);
+
+       i915_get_extra_instdone(dev, error->extra_instdone);
+
+       i915_gem_capture_buffers(dev_priv, error);
+       i915_gem_record_fences(dev, error);
+       i915_gem_record_rings(dev, error);
+
+       do_gettimeofday(&error->time);
+
+       error->overlay = intel_overlay_capture_error_state(dev);
+       error->display = intel_display_capture_error_state(dev);
+
+       spin_lock_irqsave(&dev_priv->gpu_error.lock, flags);
+       if (dev_priv->gpu_error.first_error == NULL) {
+               dev_priv->gpu_error.first_error = error;
+               error = NULL;
+       }
+       spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags);
+
+       if (error)
+               i915_error_state_free(&error->ref);
+}
+
+void i915_error_state_get(struct drm_device *dev,
+                         struct i915_error_state_file_priv *error_priv)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev_priv->gpu_error.lock, flags);
+       error_priv->error = dev_priv->gpu_error.first_error;
+       if (error_priv->error)
+               kref_get(&error_priv->error->ref);
+       spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags);
+
+}
+
+void i915_error_state_put(struct i915_error_state_file_priv *error_priv)
+{
+       if (error_priv->error)
+               kref_put(&error_priv->error->ref, i915_error_state_free);
+}
+
+void i915_destroy_error_state(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_error_state *error;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev_priv->gpu_error.lock, flags);
+       error = dev_priv->gpu_error.first_error;
+       dev_priv->gpu_error.first_error = NULL;
+       spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags);
+
+       if (error)
+               kref_put(&error->ref, i915_error_state_free);
+}
+
+const char *i915_cache_level_str(int type)
+{
+       switch (type) {
+       case I915_CACHE_NONE: return " uncached";
+       case I915_CACHE_LLC: return " snooped (LLC)";
+       case I915_CACHE_LLC_MLC: return " snooped (LLC+MLC)";
+       default: return "";
+       }
+}
+
+/* NB: please notice the memset */
+void i915_get_extra_instdone(struct drm_device *dev, uint32_t *instdone)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       memset(instdone, 0, sizeof(*instdone) * I915_NUM_INSTDONE_REG);
+
+       switch (INTEL_INFO(dev)->gen) {
+       case 2:
+       case 3:
+               instdone[0] = I915_READ(INSTDONE);
+               break;
+       case 4:
+       case 5:
+       case 6:
+               instdone[0] = I915_READ(INSTDONE_I965);
+               instdone[1] = I915_READ(INSTDONE1);
+               break;
+       default:
+               WARN_ONCE(1, "Unsupported platform\n");
+       case 7:
+               instdone[0] = I915_READ(GEN7_INSTDONE_1);
+               instdone[1] = I915_READ(GEN7_SC_INSTDONE);
+               instdone[2] = I915_READ(GEN7_SAMPLER_INSTDONE);
+               instdone[3] = I915_READ(GEN7_ROW_INSTDONE);
+               break;
+       }
+}
index 3d92a7cef1541bd20b2c4016cdc2447791991c56..6a1c207a296b481b07533863d74440bd66536683 100644 (file)
@@ -128,6 +128,8 @@ static bool cpt_can_enable_serr_int(struct drm_device *dev)
        enum pipe pipe;
        struct intel_crtc *crtc;
 
+       assert_spin_locked(&dev_priv->irq_lock);
+
        for_each_pipe(pipe) {
                crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
 
@@ -152,38 +154,66 @@ static void ironlake_set_fifo_underrun_reporting(struct drm_device *dev,
 }
 
 static void ivybridge_set_fifo_underrun_reporting(struct drm_device *dev,
-                                                 bool enable)
+                                                 enum pipe pipe, bool enable)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-
        if (enable) {
+               I915_WRITE(GEN7_ERR_INT, ERR_INT_FIFO_UNDERRUN(pipe));
+
                if (!ivb_can_enable_err_int(dev))
                        return;
 
-               I915_WRITE(GEN7_ERR_INT, ERR_INT_FIFO_UNDERRUN_A |
-                                        ERR_INT_FIFO_UNDERRUN_B |
-                                        ERR_INT_FIFO_UNDERRUN_C);
-
                ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB);
        } else {
+               bool was_enabled = !(I915_READ(DEIMR) & DE_ERR_INT_IVB);
+
+               /* Change the state _after_ we've read out the current one. */
                ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB);
+
+               if (!was_enabled &&
+                   (I915_READ(GEN7_ERR_INT) & ERR_INT_FIFO_UNDERRUN(pipe))) {
+                       DRM_DEBUG_KMS("uncleared fifo underrun on pipe %c\n",
+                                     pipe_name(pipe));
+               }
        }
 }
 
-static void ibx_set_fifo_underrun_reporting(struct intel_crtc *crtc,
+/**
+ * ibx_display_interrupt_update - update SDEIMR
+ * @dev_priv: driver private
+ * @interrupt_mask: mask of interrupt bits to update
+ * @enabled_irq_mask: mask of interrupt bits to enable
+ */
+static void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
+                                        uint32_t interrupt_mask,
+                                        uint32_t enabled_irq_mask)
+{
+       uint32_t sdeimr = I915_READ(SDEIMR);
+       sdeimr &= ~interrupt_mask;
+       sdeimr |= (~enabled_irq_mask & interrupt_mask);
+
+       assert_spin_locked(&dev_priv->irq_lock);
+
+       I915_WRITE(SDEIMR, sdeimr);
+       POSTING_READ(SDEIMR);
+}
+#define ibx_enable_display_interrupt(dev_priv, bits) \
+       ibx_display_interrupt_update((dev_priv), (bits), (bits))
+#define ibx_disable_display_interrupt(dev_priv, bits) \
+       ibx_display_interrupt_update((dev_priv), (bits), 0)
+
+static void ibx_set_fifo_underrun_reporting(struct drm_device *dev,
+                                           enum transcoder pch_transcoder,
                                            bool enable)
 {
-       struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       uint32_t bit = (crtc->pipe == PIPE_A) ? SDE_TRANSA_FIFO_UNDER :
-                                               SDE_TRANSB_FIFO_UNDER;
+       uint32_t bit = (pch_transcoder == TRANSCODER_A) ?
+                      SDE_TRANSA_FIFO_UNDER : SDE_TRANSB_FIFO_UNDER;
 
        if (enable)
-               I915_WRITE(SDEIMR, I915_READ(SDEIMR) & ~bit);
+               ibx_enable_display_interrupt(dev_priv, bit);
        else
-               I915_WRITE(SDEIMR, I915_READ(SDEIMR) | bit);
-
-       POSTING_READ(SDEIMR);
+               ibx_disable_display_interrupt(dev_priv, bit);
 }
 
 static void cpt_set_fifo_underrun_reporting(struct drm_device *dev,
@@ -193,19 +223,26 @@ static void cpt_set_fifo_underrun_reporting(struct drm_device *dev,
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        if (enable) {
+               I915_WRITE(SERR_INT,
+                          SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder));
+
                if (!cpt_can_enable_serr_int(dev))
                        return;
 
-               I915_WRITE(SERR_INT, SERR_INT_TRANS_A_FIFO_UNDERRUN |
-                                    SERR_INT_TRANS_B_FIFO_UNDERRUN |
-                                    SERR_INT_TRANS_C_FIFO_UNDERRUN);
-
-               I915_WRITE(SDEIMR, I915_READ(SDEIMR) & ~SDE_ERROR_CPT);
+               ibx_enable_display_interrupt(dev_priv, SDE_ERROR_CPT);
        } else {
-               I915_WRITE(SDEIMR, I915_READ(SDEIMR) | SDE_ERROR_CPT);
-       }
+               uint32_t tmp = I915_READ(SERR_INT);
+               bool was_enabled = !(I915_READ(SDEIMR) & SDE_ERROR_CPT);
 
-       POSTING_READ(SDEIMR);
+               /* Change the state _after_ we've read out the current one. */
+               ibx_disable_display_interrupt(dev_priv, SDE_ERROR_CPT);
+
+               if (!was_enabled &&
+                   (tmp & SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder))) {
+                       DRM_DEBUG_KMS("uncleared pch fifo underrun on pch transcoder %c\n",
+                                     transcoder_name(pch_transcoder));
+               }
+       }
 }
 
 /**
@@ -243,7 +280,7 @@ bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
        if (IS_GEN5(dev) || IS_GEN6(dev))
                ironlake_set_fifo_underrun_reporting(dev, pipe, enable);
        else if (IS_GEN7(dev))
-               ivybridge_set_fifo_underrun_reporting(dev, enable);
+               ivybridge_set_fifo_underrun_reporting(dev, pipe, enable);
 
 done:
        spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
@@ -269,29 +306,19 @@ bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
                                           bool enable)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       enum pipe p;
-       struct drm_crtc *crtc;
-       struct intel_crtc *intel_crtc;
+       struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pch_transcoder];
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        unsigned long flags;
        bool ret;
 
-       if (HAS_PCH_LPT(dev)) {
-               crtc = NULL;
-               for_each_pipe(p) {
-                       struct drm_crtc *c = dev_priv->pipe_to_crtc_mapping[p];
-                       if (intel_pipe_has_type(c, INTEL_OUTPUT_ANALOG)) {
-                               crtc = c;
-                               break;
-                       }
-               }
-               if (!crtc) {
-                       DRM_ERROR("PCH FIFO underrun, but no CRTC using the PCH found\n");
-                       return false;
-               }
-       } else {
-               crtc = dev_priv->pipe_to_crtc_mapping[pch_transcoder];
-       }
-       intel_crtc = to_intel_crtc(crtc);
+       /*
+        * NOTE: Pre-LPT has a fixed cpu pipe -> pch transcoder mapping, but LPT
+        * has only one pch transcoder A that all pipes can use. To avoid racy
+        * pch transcoder -> pipe lookups from interrupt code simply store the
+        * underrun statistics in crtc A. Since we never expose this anywhere
+        * nor use it outside of the fifo underrun code here using the "wrong"
+        * crtc on LPT won't cause issues.
+        */
 
        spin_lock_irqsave(&dev_priv->irq_lock, flags);
 
@@ -303,7 +330,7 @@ bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
        intel_crtc->pch_fifo_underrun_disabled = !enable;
 
        if (HAS_PCH_IBX(dev))
-               ibx_set_fifo_underrun_reporting(intel_crtc, enable);
+               ibx_set_fifo_underrun_reporting(dev, pch_transcoder, enable);
        else
                cpt_set_fifo_underrun_reporting(dev, pch_transcoder, enable);
 
@@ -319,6 +346,8 @@ i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
        u32 reg = PIPESTAT(pipe);
        u32 pipestat = I915_READ(reg) & 0x7fff0000;
 
+       assert_spin_locked(&dev_priv->irq_lock);
+
        if ((pipestat & mask) == mask)
                return;
 
@@ -334,6 +363,8 @@ i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
        u32 reg = PIPESTAT(pipe);
        u32 pipestat = I915_READ(reg) & 0x7fff0000;
 
+       assert_spin_locked(&dev_priv->irq_lock);
+
        if ((pipestat & mask) == 0)
                return;
 
@@ -625,14 +656,13 @@ static void i915_hotplug_work_func(struct work_struct *work)
                drm_kms_helper_hotplug_event(dev);
 }
 
-static void ironlake_handle_rps_change(struct drm_device *dev)
+static void ironlake_rps_change_irq_handler(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        u32 busy_up, busy_down, max_avg, min_avg;
        u8 new_delay;
-       unsigned long flags;
 
-       spin_lock_irqsave(&mchdev_lock, flags);
+       spin_lock(&mchdev_lock);
 
        I915_WRITE16(MEMINTRSTS, I915_READ(MEMINTRSTS));
 
@@ -660,7 +690,7 @@ static void ironlake_handle_rps_change(struct drm_device *dev)
        if (ironlake_set_drps(dev, new_delay))
                dev_priv->ips.cur_delay = new_delay;
 
-       spin_unlock_irqrestore(&mchdev_lock, flags);
+       spin_unlock(&mchdev_lock);
 
        return;
 }
@@ -668,18 +698,13 @@ static void ironlake_handle_rps_change(struct drm_device *dev)
 static void notify_ring(struct drm_device *dev,
                        struct intel_ring_buffer *ring)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
        if (ring->obj == NULL)
                return;
 
        trace_i915_gem_request_complete(ring, ring->get_seqno(ring, false));
 
        wake_up_all(&ring->irq_queue);
-       if (i915_enable_hangcheck) {
-               mod_timer(&dev_priv->gpu_error.hangcheck_timer,
-                         round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES));
-       }
+       i915_queue_hangcheck(dev);
 }
 
 static void gen6_pm_rps_work(struct work_struct *work)
@@ -689,13 +714,13 @@ static void gen6_pm_rps_work(struct work_struct *work)
        u32 pm_iir, pm_imr;
        u8 new_delay;
 
-       spin_lock_irq(&dev_priv->rps.lock);
+       spin_lock_irq(&dev_priv->irq_lock);
        pm_iir = dev_priv->rps.pm_iir;
        dev_priv->rps.pm_iir = 0;
        pm_imr = I915_READ(GEN6_PMIMR);
        /* Make sure not to corrupt PMIMR state used by ringbuffer code */
        I915_WRITE(GEN6_PMIMR, pm_imr & ~GEN6_PM_RPS_EVENTS);
-       spin_unlock_irq(&dev_priv->rps.lock);
+       spin_unlock_irq(&dev_priv->irq_lock);
 
        if ((pm_iir & GEN6_PM_RPS_EVENTS) == 0)
                return;
@@ -787,7 +812,7 @@ static void ivybridge_parity_work(struct work_struct *work)
 
        mutex_unlock(&dev_priv->dev->struct_mutex);
 
-       parity_event[0] = "L3_PARITY_ERROR=1";
+       parity_event[0] = I915_L3_PARITY_UEVENT "=1";
        parity_event[1] = kasprintf(GFP_KERNEL, "ROW=%d", row);
        parity_event[2] = kasprintf(GFP_KERNEL, "BANK=%d", bank);
        parity_event[3] = kasprintf(GFP_KERNEL, "SUBBANK=%d", subbank);
@@ -804,22 +829,32 @@ static void ivybridge_parity_work(struct work_struct *work)
        kfree(parity_event[1]);
 }
 
-static void ivybridge_handle_parity_error(struct drm_device *dev)
+static void ivybridge_parity_error_irq_handler(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       unsigned long flags;
 
        if (!HAS_L3_GPU_CACHE(dev))
                return;
 
-       spin_lock_irqsave(&dev_priv->irq_lock, flags);
+       spin_lock(&dev_priv->irq_lock);
        dev_priv->gt_irq_mask |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
        I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
-       spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
+       spin_unlock(&dev_priv->irq_lock);
 
        queue_work(dev_priv->wq, &dev_priv->l3_parity.error_work);
 }
 
+static void ilk_gt_irq_handler(struct drm_device *dev,
+                              struct drm_i915_private *dev_priv,
+                              u32 gt_iir)
+{
+       if (gt_iir &
+           (GT_RENDER_USER_INTERRUPT | GT_RENDER_PIPECTL_NOTIFY_INTERRUPT))
+               notify_ring(dev, &dev_priv->ring[RCS]);
+       if (gt_iir & ILK_BSD_USER_INTERRUPT)
+               notify_ring(dev, &dev_priv->ring[VCS]);
+}
+
 static void snb_gt_irq_handler(struct drm_device *dev,
                               struct drm_i915_private *dev_priv,
                               u32 gt_iir)
@@ -841,15 +876,13 @@ static void snb_gt_irq_handler(struct drm_device *dev,
        }
 
        if (gt_iir & GT_RENDER_L3_PARITY_ERROR_INTERRUPT)
-               ivybridge_handle_parity_error(dev);
+               ivybridge_parity_error_irq_handler(dev);
 }
 
 /* Legacy way of handling PM interrupts */
-static void gen6_queue_rps_work(struct drm_i915_private *dev_priv,
-                               u32 pm_iir)
+static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv,
+                                u32 pm_iir)
 {
-       unsigned long flags;
-
        /*
         * IIR bits should never already be set because IMR should
         * prevent an interrupt from being shown in IIR. The warning
@@ -860,11 +893,11 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv,
         * The mask bit in IMR is cleared by dev_priv->rps.work.
         */
 
-       spin_lock_irqsave(&dev_priv->rps.lock, flags);
+       spin_lock(&dev_priv->irq_lock);
        dev_priv->rps.pm_iir |= pm_iir;
        I915_WRITE(GEN6_PMIMR, dev_priv->rps.pm_iir);
        POSTING_READ(GEN6_PMIMR);
-       spin_unlock_irqrestore(&dev_priv->rps.lock, flags);
+       spin_unlock(&dev_priv->irq_lock);
 
        queue_work(dev_priv->wq, &dev_priv->rps.work);
 }
@@ -886,6 +919,10 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,
        spin_lock(&dev_priv->irq_lock);
        for (i = 1; i < HPD_NUM_PINS; i++) {
 
+               WARN(((hpd[i] & hotplug_trigger) &&
+                     dev_priv->hpd_stats[i].hpd_mark != HPD_ENABLED),
+                    "Received HPD interrupt although disabled\n");
+
                if (!(hpd[i] & hotplug_trigger) ||
                    dev_priv->hpd_stats[i].hpd_mark != HPD_ENABLED)
                        continue;
@@ -896,6 +933,7 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,
                                   + msecs_to_jiffies(HPD_STORM_DETECT_PERIOD))) {
                        dev_priv->hpd_stats[i].hpd_last_jiffies = jiffies;
                        dev_priv->hpd_stats[i].hpd_cnt = 0;
+                       DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: 0\n", i);
                } else if (dev_priv->hpd_stats[i].hpd_cnt > HPD_STORM_THRESHOLD) {
                        dev_priv->hpd_stats[i].hpd_mark = HPD_MARK_DISABLED;
                        dev_priv->hpd_event_bits &= ~(1 << i);
@@ -903,6 +941,8 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,
                        storm_detected = true;
                } else {
                        dev_priv->hpd_stats[i].hpd_cnt++;
+                       DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: %d\n", i,
+                                     dev_priv->hpd_stats[i].hpd_cnt);
                }
        }
 
@@ -928,7 +968,7 @@ static void dp_aux_irq_handler(struct drm_device *dev)
        wake_up_all(&dev_priv->gmbus_wait_queue);
 }
 
-/* Unlike gen6_queue_rps_work() from which this function is originally derived,
+/* Unlike gen6_rps_irq_handler() from which this function is originally derived,
  * we must be able to deal with other PM interrupts. This is complicated because
  * of the way in which we use the masks to defer the RPS work (which for
  * posterity is necessary because of forcewake).
@@ -936,27 +976,23 @@ static void dp_aux_irq_handler(struct drm_device *dev)
 static void hsw_pm_irq_handler(struct drm_i915_private *dev_priv,
                               u32 pm_iir)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&dev_priv->rps.lock, flags);
-       dev_priv->rps.pm_iir |= pm_iir & GEN6_PM_RPS_EVENTS;
-       if (dev_priv->rps.pm_iir) {
+       if (pm_iir & GEN6_PM_RPS_EVENTS) {
+               spin_lock(&dev_priv->irq_lock);
+               dev_priv->rps.pm_iir |= pm_iir & GEN6_PM_RPS_EVENTS;
                I915_WRITE(GEN6_PMIMR, dev_priv->rps.pm_iir);
                /* never want to mask useful interrupts. (also posting read) */
                WARN_ON(I915_READ_NOTRACE(GEN6_PMIMR) & ~GEN6_PM_RPS_EVENTS);
-               /* TODO: if queue_work is slow, move it out of the spinlock */
+               spin_unlock(&dev_priv->irq_lock);
+
                queue_work(dev_priv->wq, &dev_priv->rps.work);
        }
-       spin_unlock_irqrestore(&dev_priv->rps.lock, flags);
 
-       if (pm_iir & ~GEN6_PM_RPS_EVENTS) {
-               if (pm_iir & PM_VEBOX_USER_INTERRUPT)
-                       notify_ring(dev_priv->dev, &dev_priv->ring[VECS]);
+       if (pm_iir & PM_VEBOX_USER_INTERRUPT)
+               notify_ring(dev_priv->dev, &dev_priv->ring[VECS]);
 
-               if (pm_iir & PM_VEBOX_CS_ERROR_INTERRUPT) {
-                       DRM_ERROR("VEBOX CS error interrupt 0x%08x\n", pm_iir);
-                       i915_handle_error(dev_priv->dev, false);
-               }
+       if (pm_iir & PM_VEBOX_CS_ERROR_INTERRUPT) {
+               DRM_ERROR("VEBOX CS error interrupt 0x%08x\n", pm_iir);
+               i915_handle_error(dev_priv->dev, false);
        }
 }
 
@@ -1029,7 +1065,7 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
                        gmbus_irq_handler(dev);
 
                if (pm_iir & GEN6_PM_RPS_EVENTS)
-                       gen6_queue_rps_work(dev_priv, pm_iir);
+                       gen6_rps_irq_handler(dev_priv, pm_iir);
 
                I915_WRITE(GTIIR, gt_iir);
                I915_WRITE(GEN6_PMIIR, pm_iir);
@@ -1179,163 +1215,9 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
                cpt_serr_int_handler(dev);
 }
 
-static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
-{
-       struct drm_device *dev = (struct drm_device *) arg;
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       u32 de_iir, gt_iir, de_ier, pm_iir, sde_ier = 0;
-       irqreturn_t ret = IRQ_NONE;
-       int i;
-
-       atomic_inc(&dev_priv->irq_received);
-
-       /* We get interrupts on unclaimed registers, so check for this before we
-        * do any I915_{READ,WRITE}. */
-       if (IS_HASWELL(dev) &&
-           (I915_READ_NOTRACE(FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) {
-               DRM_ERROR("Unclaimed register before interrupt\n");
-               I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
-       }
-
-       /* disable master interrupt before clearing iir  */
-       de_ier = I915_READ(DEIER);
-       I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL);
-
-       /* Disable south interrupts. We'll only write to SDEIIR once, so further
-        * interrupts will will be stored on its back queue, and then we'll be
-        * able to process them after we restore SDEIER (as soon as we restore
-        * it, we'll get an interrupt if SDEIIR still has something to process
-        * due to its back queue). */
-       if (!HAS_PCH_NOP(dev)) {
-               sde_ier = I915_READ(SDEIER);
-               I915_WRITE(SDEIER, 0);
-               POSTING_READ(SDEIER);
-       }
-
-       /* On Haswell, also mask ERR_INT because we don't want to risk
-        * generating "unclaimed register" interrupts from inside the interrupt
-        * handler. */
-       if (IS_HASWELL(dev)) {
-               spin_lock(&dev_priv->irq_lock);
-               ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB);
-               spin_unlock(&dev_priv->irq_lock);
-       }
-
-       gt_iir = I915_READ(GTIIR);
-       if (gt_iir) {
-               snb_gt_irq_handler(dev, dev_priv, gt_iir);
-               I915_WRITE(GTIIR, gt_iir);
-               ret = IRQ_HANDLED;
-       }
-
-       de_iir = I915_READ(DEIIR);
-       if (de_iir) {
-               if (de_iir & DE_ERR_INT_IVB)
-                       ivb_err_int_handler(dev);
-
-               if (de_iir & DE_AUX_CHANNEL_A_IVB)
-                       dp_aux_irq_handler(dev);
-
-               if (de_iir & DE_GSE_IVB)
-                       intel_opregion_asle_intr(dev);
-
-               for (i = 0; i < 3; i++) {
-                       if (de_iir & (DE_PIPEA_VBLANK_IVB << (5 * i)))
-                               drm_handle_vblank(dev, i);
-                       if (de_iir & (DE_PLANEA_FLIP_DONE_IVB << (5 * i))) {
-                               intel_prepare_page_flip(dev, i);
-                               intel_finish_page_flip_plane(dev, i);
-                       }
-               }
-
-               /* check event from PCH */
-               if (!HAS_PCH_NOP(dev) && (de_iir & DE_PCH_EVENT_IVB)) {
-                       u32 pch_iir = I915_READ(SDEIIR);
-
-                       cpt_irq_handler(dev, pch_iir);
-
-                       /* clear PCH hotplug event before clear CPU irq */
-                       I915_WRITE(SDEIIR, pch_iir);
-               }
-
-               I915_WRITE(DEIIR, de_iir);
-               ret = IRQ_HANDLED;
-       }
-
-       pm_iir = I915_READ(GEN6_PMIIR);
-       if (pm_iir) {
-               if (IS_HASWELL(dev))
-                       hsw_pm_irq_handler(dev_priv, pm_iir);
-               else if (pm_iir & GEN6_PM_RPS_EVENTS)
-                       gen6_queue_rps_work(dev_priv, pm_iir);
-               I915_WRITE(GEN6_PMIIR, pm_iir);
-               ret = IRQ_HANDLED;
-       }
-
-       if (IS_HASWELL(dev)) {
-               spin_lock(&dev_priv->irq_lock);
-               if (ivb_can_enable_err_int(dev))
-                       ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB);
-               spin_unlock(&dev_priv->irq_lock);
-       }
-
-       I915_WRITE(DEIER, de_ier);
-       POSTING_READ(DEIER);
-       if (!HAS_PCH_NOP(dev)) {
-               I915_WRITE(SDEIER, sde_ier);
-               POSTING_READ(SDEIER);
-       }
-
-       return ret;
-}
-
-static void ilk_gt_irq_handler(struct drm_device *dev,
-                              struct drm_i915_private *dev_priv,
-                              u32 gt_iir)
-{
-       if (gt_iir &
-           (GT_RENDER_USER_INTERRUPT | GT_RENDER_PIPECTL_NOTIFY_INTERRUPT))
-               notify_ring(dev, &dev_priv->ring[RCS]);
-       if (gt_iir & ILK_BSD_USER_INTERRUPT)
-               notify_ring(dev, &dev_priv->ring[VCS]);
-}
-
-static irqreturn_t ironlake_irq_handler(int irq, void *arg)
+static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir)
 {
-       struct drm_device *dev = (struct drm_device *) arg;
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       int ret = IRQ_NONE;
-       u32 de_iir, gt_iir, de_ier, pm_iir, sde_ier;
-
-       atomic_inc(&dev_priv->irq_received);
-
-       /* disable master interrupt before clearing iir  */
-       de_ier = I915_READ(DEIER);
-       I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL);
-       POSTING_READ(DEIER);
-
-       /* Disable south interrupts. We'll only write to SDEIIR once, so further
-        * interrupts will will be stored on its back queue, and then we'll be
-        * able to process them after we restore SDEIER (as soon as we restore
-        * it, we'll get an interrupt if SDEIIR still has something to process
-        * due to its back queue). */
-       sde_ier = I915_READ(SDEIER);
-       I915_WRITE(SDEIER, 0);
-       POSTING_READ(SDEIER);
-
-       de_iir = I915_READ(DEIIR);
-       gt_iir = I915_READ(GTIIR);
-       pm_iir = I915_READ(GEN6_PMIIR);
-
-       if (de_iir == 0 && gt_iir == 0 && (!IS_GEN6(dev) || pm_iir == 0))
-               goto done;
-
-       ret = IRQ_HANDLED;
-
-       if (IS_GEN5(dev))
-               ilk_gt_irq_handler(dev, dev_priv, gt_iir);
-       else
-               snb_gt_irq_handler(dev, dev_priv, gt_iir);
+       struct drm_i915_private *dev_priv = dev->dev_private;
 
        if (de_iir & DE_AUX_CHANNEL_A)
                dp_aux_irq_handler(dev);
@@ -1383,622 +1265,199 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
                I915_WRITE(SDEIIR, pch_iir);
        }
 
-       if (IS_GEN5(dev) &&  de_iir & DE_PCU_EVENT)
-               ironlake_handle_rps_change(dev);
-
-       if (IS_GEN6(dev) && pm_iir & GEN6_PM_RPS_EVENTS)
-               gen6_queue_rps_work(dev_priv, pm_iir);
-
-       I915_WRITE(GTIIR, gt_iir);
-       I915_WRITE(DEIIR, de_iir);
-       I915_WRITE(GEN6_PMIIR, pm_iir);
-
-done:
-       I915_WRITE(DEIER, de_ier);
-       POSTING_READ(DEIER);
-       I915_WRITE(SDEIER, sde_ier);
-       POSTING_READ(SDEIER);
-
-       return ret;
-}
-
-/**
- * i915_error_work_func - do process context error handling work
- * @work: work struct
- *
- * Fire an error uevent so userspace can see that a hang or error
- * was detected.
- */
-static void i915_error_work_func(struct work_struct *work)
-{
-       struct i915_gpu_error *error = container_of(work, struct i915_gpu_error,
-                                                   work);
-       drm_i915_private_t *dev_priv = container_of(error, drm_i915_private_t,
-                                                   gpu_error);
-       struct drm_device *dev = dev_priv->dev;
-       struct intel_ring_buffer *ring;
-       char *error_event[] = { "ERROR=1", NULL };
-       char *reset_event[] = { "RESET=1", NULL };
-       char *reset_done_event[] = { "ERROR=0", NULL };
-       int i, ret;
-
-       kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, error_event);
-
-       /*
-        * Note that there's only one work item which does gpu resets, so we
-        * need not worry about concurrent gpu resets potentially incrementing
-        * error->reset_counter twice. We only need to take care of another
-        * racing irq/hangcheck declaring the gpu dead for a second time. A
-        * quick check for that is good enough: schedule_work ensures the
-        * correct ordering between hang detection and this work item, and since
-        * the reset in-progress bit is only ever set by code outside of this
-        * work we don't need to worry about any other races.
-        */
-       if (i915_reset_in_progress(error) && !i915_terminally_wedged(error)) {
-               DRM_DEBUG_DRIVER("resetting chip\n");
-               kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE,
-                                  reset_event);
-
-               ret = i915_reset(dev);
-
-               if (ret == 0) {
-                       /*
-                        * After all the gem state is reset, increment the reset
-                        * counter and wake up everyone waiting for the reset to
-                        * complete.
-                        *
-                        * Since unlock operations are a one-sided barrier only,
-                        * we need to insert a barrier here to order any seqno
-                        * updates before
-                        * the counter increment.
-                        */
-                       smp_mb__before_atomic_inc();
-                       atomic_inc(&dev_priv->gpu_error.reset_counter);
-
-                       kobject_uevent_env(&dev->primary->kdev.kobj,
-                                          KOBJ_CHANGE, reset_done_event);
-               } else {
-                       atomic_set(&error->reset_counter, I915_WEDGED);
-               }
-
-               for_each_ring(ring, dev_priv, i)
-                       wake_up_all(&ring->irq_queue);
-
-               intel_display_handle_reset(dev);
-
-               wake_up_all(&dev_priv->gpu_error.reset_queue);
-       }
+       if (IS_GEN5(dev) && de_iir & DE_PCU_EVENT)
+               ironlake_rps_change_irq_handler(dev);
 }
 
-/* NB: please notice the memset */
-static void i915_get_extra_instdone(struct drm_device *dev,
-                                   uint32_t *instdone)
+static void ivb_display_irq_handler(struct drm_device *dev, u32 de_iir)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       memset(instdone, 0, sizeof(*instdone) * I915_NUM_INSTDONE_REG);
-
-       switch(INTEL_INFO(dev)->gen) {
-       case 2:
-       case 3:
-               instdone[0] = I915_READ(INSTDONE);
-               break;
-       case 4:
-       case 5:
-       case 6:
-               instdone[0] = I915_READ(INSTDONE_I965);
-               instdone[1] = I915_READ(INSTDONE1);
-               break;
-       default:
-               WARN_ONCE(1, "Unsupported platform\n");
-       case 7:
-               instdone[0] = I915_READ(GEN7_INSTDONE_1);
-               instdone[1] = I915_READ(GEN7_SC_INSTDONE);
-               instdone[2] = I915_READ(GEN7_SAMPLER_INSTDONE);
-               instdone[3] = I915_READ(GEN7_ROW_INSTDONE);
-               break;
-       }
-}
-
-#ifdef CONFIG_DEBUG_FS
-static struct drm_i915_error_object *
-i915_error_object_create_sized(struct drm_i915_private *dev_priv,
-                              struct drm_i915_gem_object *src,
-                              const int num_pages)
-{
-       struct drm_i915_error_object *dst;
        int i;
-       u32 reloc_offset;
-
-       if (src == NULL || src->pages == NULL)
-               return NULL;
-
-       dst = kmalloc(sizeof(*dst) + num_pages * sizeof(u32 *), GFP_ATOMIC);
-       if (dst == NULL)
-               return NULL;
-
-       reloc_offset = src->gtt_offset;
-       for (i = 0; i < num_pages; i++) {
-               unsigned long flags;
-               void *d;
-
-               d = kmalloc(PAGE_SIZE, GFP_ATOMIC);
-               if (d == NULL)
-                       goto unwind;
-
-               local_irq_save(flags);
-               if (reloc_offset < dev_priv->gtt.mappable_end &&
-                   src->has_global_gtt_mapping) {
-                       void __iomem *s;
-
-                       /* Simply ignore tiling or any overlapping fence.
-                        * It's part of the error state, and this hopefully
-                        * captures what the GPU read.
-                        */
-
-                       s = io_mapping_map_atomic_wc(dev_priv->gtt.mappable,
-                                                    reloc_offset);
-                       memcpy_fromio(d, s, PAGE_SIZE);
-                       io_mapping_unmap_atomic(s);
-               } else if (src->stolen) {
-                       unsigned long offset;
 
-                       offset = dev_priv->mm.stolen_base;
-                       offset += src->stolen->start;
-                       offset += i << PAGE_SHIFT;
+       if (de_iir & DE_ERR_INT_IVB)
+               ivb_err_int_handler(dev);
 
-                       memcpy_fromio(d, (void __iomem *) offset, PAGE_SIZE);
-               } else {
-                       struct page *page;
-                       void *s;
-
-                       page = i915_gem_object_get_page(src, i);
-
-                       drm_clflush_pages(&page, 1);
+       if (de_iir & DE_AUX_CHANNEL_A_IVB)
+               dp_aux_irq_handler(dev);
 
-                       s = kmap_atomic(page);
-                       memcpy(d, s, PAGE_SIZE);
-                       kunmap_atomic(s);
+       if (de_iir & DE_GSE_IVB)
+               intel_opregion_asle_intr(dev);
 
-                       drm_clflush_pages(&page, 1);
+       for (i = 0; i < 3; i++) {
+               if (de_iir & (DE_PIPEA_VBLANK_IVB << (5 * i)))
+                       drm_handle_vblank(dev, i);
+               if (de_iir & (DE_PLANEA_FLIP_DONE_IVB << (5 * i))) {
+                       intel_prepare_page_flip(dev, i);
+                       intel_finish_page_flip_plane(dev, i);
                }
-               local_irq_restore(flags);
-
-               dst->pages[i] = d;
-
-               reloc_offset += PAGE_SIZE;
-       }
-       dst->page_count = num_pages;
-       dst->gtt_offset = src->gtt_offset;
-
-       return dst;
-
-unwind:
-       while (i--)
-               kfree(dst->pages[i]);
-       kfree(dst);
-       return NULL;
-}
-#define i915_error_object_create(dev_priv, src) \
-       i915_error_object_create_sized((dev_priv), (src), \
-                                      (src)->base.size>>PAGE_SHIFT)
-
-static void
-i915_error_object_free(struct drm_i915_error_object *obj)
-{
-       int page;
-
-       if (obj == NULL)
-               return;
-
-       for (page = 0; page < obj->page_count; page++)
-               kfree(obj->pages[page]);
-
-       kfree(obj);
-}
-
-void
-i915_error_state_free(struct kref *error_ref)
-{
-       struct drm_i915_error_state *error = container_of(error_ref,
-                                                         typeof(*error), ref);
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(error->ring); i++) {
-               i915_error_object_free(error->ring[i].batchbuffer);
-               i915_error_object_free(error->ring[i].ringbuffer);
-               i915_error_object_free(error->ring[i].ctx);
-               kfree(error->ring[i].requests);
-       }
-
-       kfree(error->active_bo);
-       kfree(error->overlay);
-       kfree(error->display);
-       kfree(error);
-}
-static void capture_bo(struct drm_i915_error_buffer *err,
-                      struct drm_i915_gem_object *obj)
-{
-       err->size = obj->base.size;
-       err->name = obj->base.name;
-       err->rseqno = obj->last_read_seqno;
-       err->wseqno = obj->last_write_seqno;
-       err->gtt_offset = obj->gtt_offset;
-       err->read_domains = obj->base.read_domains;
-       err->write_domain = obj->base.write_domain;
-       err->fence_reg = obj->fence_reg;
-       err->pinned = 0;
-       if (obj->pin_count > 0)
-               err->pinned = 1;
-       if (obj->user_pin_count > 0)
-               err->pinned = -1;
-       err->tiling = obj->tiling_mode;
-       err->dirty = obj->dirty;
-       err->purgeable = obj->madv != I915_MADV_WILLNEED;
-       err->ring = obj->ring ? obj->ring->id : -1;
-       err->cache_level = obj->cache_level;
-}
-
-static u32 capture_active_bo(struct drm_i915_error_buffer *err,
-                            int count, struct list_head *head)
-{
-       struct drm_i915_gem_object *obj;
-       int i = 0;
-
-       list_for_each_entry(obj, head, mm_list) {
-               capture_bo(err++, obj);
-               if (++i == count)
-                       break;
-       }
-
-       return i;
-}
-
-static u32 capture_pinned_bo(struct drm_i915_error_buffer *err,
-                            int count, struct list_head *head)
-{
-       struct drm_i915_gem_object *obj;
-       int i = 0;
-
-       list_for_each_entry(obj, head, global_list) {
-               if (obj->pin_count == 0)
-                       continue;
-
-               capture_bo(err++, obj);
-               if (++i == count)
-                       break;
-       }
-
-       return i;
-}
-
-static void i915_gem_record_fences(struct drm_device *dev,
-                                  struct drm_i915_error_state *error)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int i;
-
-       /* Fences */
-       switch (INTEL_INFO(dev)->gen) {
-       case 7:
-       case 6:
-               for (i = 0; i < dev_priv->num_fence_regs; i++)
-                       error->fence[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8));
-               break;
-       case 5:
-       case 4:
-               for (i = 0; i < 16; i++)
-                       error->fence[i] = I915_READ64(FENCE_REG_965_0 + (i * 8));
-               break;
-       case 3:
-               if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
-                       for (i = 0; i < 8; i++)
-                               error->fence[i+8] = I915_READ(FENCE_REG_945_8 + (i * 4));
-       case 2:
-               for (i = 0; i < 8; i++)
-                       error->fence[i] = I915_READ(FENCE_REG_830_0 + (i * 4));
-               break;
-
-       default:
-               BUG();
-       }
-}
-
-static struct drm_i915_error_object *
-i915_error_first_batchbuffer(struct drm_i915_private *dev_priv,
-                            struct intel_ring_buffer *ring)
-{
-       struct drm_i915_gem_object *obj;
-       u32 seqno;
-
-       if (!ring->get_seqno)
-               return NULL;
-
-       if (HAS_BROKEN_CS_TLB(dev_priv->dev)) {
-               u32 acthd = I915_READ(ACTHD);
-
-               if (WARN_ON(ring->id != RCS))
-                       return NULL;
-
-               obj = ring->private;
-               if (acthd >= obj->gtt_offset &&
-                   acthd < obj->gtt_offset + obj->base.size)
-                       return i915_error_object_create(dev_priv, obj);
        }
 
-       seqno = ring->get_seqno(ring, false);
-       list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) {
-               if (obj->ring != ring)
-                       continue;
-
-               if (i915_seqno_passed(seqno, obj->last_read_seqno))
-                       continue;
+       /* check event from PCH */
+       if (!HAS_PCH_NOP(dev) && (de_iir & DE_PCH_EVENT_IVB)) {
+               u32 pch_iir = I915_READ(SDEIIR);
 
-               if ((obj->base.read_domains & I915_GEM_DOMAIN_COMMAND) == 0)
-                       continue;
+               cpt_irq_handler(dev, pch_iir);
 
-               /* We need to copy these to an anonymous buffer as the simplest
-                * method to avoid being overwritten by userspace.
-                */
-               return i915_error_object_create(dev_priv, obj);
+               /* clear PCH hotplug event before clear CPU irq */
+               I915_WRITE(SDEIIR, pch_iir);
        }
-
-       return NULL;
 }
 
-static void i915_record_ring_state(struct drm_device *dev,
-                                  struct drm_i915_error_state *error,
-                                  struct intel_ring_buffer *ring)
+static irqreturn_t ironlake_irq_handler(int irq, void *arg)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       if (INTEL_INFO(dev)->gen >= 6) {
-               error->rc_psmi[ring->id] = I915_READ(ring->mmio_base + 0x50);
-               error->fault_reg[ring->id] = I915_READ(RING_FAULT_REG(ring));
-               error->semaphore_mboxes[ring->id][0]
-                       = I915_READ(RING_SYNC_0(ring->mmio_base));
-               error->semaphore_mboxes[ring->id][1]
-                       = I915_READ(RING_SYNC_1(ring->mmio_base));
-               error->semaphore_seqno[ring->id][0] = ring->sync_seqno[0];
-               error->semaphore_seqno[ring->id][1] = ring->sync_seqno[1];
-       }
-
-       if (INTEL_INFO(dev)->gen >= 4) {
-               error->faddr[ring->id] = I915_READ(RING_DMA_FADD(ring->mmio_base));
-               error->ipeir[ring->id] = I915_READ(RING_IPEIR(ring->mmio_base));
-               error->ipehr[ring->id] = I915_READ(RING_IPEHR(ring->mmio_base));
-               error->instdone[ring->id] = I915_READ(RING_INSTDONE(ring->mmio_base));
-               error->instps[ring->id] = I915_READ(RING_INSTPS(ring->mmio_base));
-               if (ring->id == RCS)
-                       error->bbaddr = I915_READ64(BB_ADDR);
-       } else {
-               error->faddr[ring->id] = I915_READ(DMA_FADD_I8XX);
-               error->ipeir[ring->id] = I915_READ(IPEIR);
-               error->ipehr[ring->id] = I915_READ(IPEHR);
-               error->instdone[ring->id] = I915_READ(INSTDONE);
-       }
-
-       error->waiting[ring->id] = waitqueue_active(&ring->irq_queue);
-       error->instpm[ring->id] = I915_READ(RING_INSTPM(ring->mmio_base));
-       error->seqno[ring->id] = ring->get_seqno(ring, false);
-       error->acthd[ring->id] = intel_ring_get_active_head(ring);
-       error->head[ring->id] = I915_READ_HEAD(ring);
-       error->tail[ring->id] = I915_READ_TAIL(ring);
-       error->ctl[ring->id] = I915_READ_CTL(ring);
-
-       error->cpu_ring_head[ring->id] = ring->head;
-       error->cpu_ring_tail[ring->id] = ring->tail;
-}
+       struct drm_device *dev = (struct drm_device *) arg;
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       u32 de_iir, gt_iir, de_ier, sde_ier = 0;
+       irqreturn_t ret = IRQ_NONE;
 
+       atomic_inc(&dev_priv->irq_received);
 
-static void i915_gem_record_active_context(struct intel_ring_buffer *ring,
-                                          struct drm_i915_error_state *error,
-                                          struct drm_i915_error_ring *ering)
-{
-       struct drm_i915_private *dev_priv = ring->dev->dev_private;
-       struct drm_i915_gem_object *obj;
+       /* We get interrupts on unclaimed registers, so check for this before we
+        * do any I915_{READ,WRITE}. */
+       intel_uncore_check_errors(dev);
 
-       /* Currently render ring is the only HW context user */
-       if (ring->id != RCS || !error->ccid)
-               return;
+       /* disable master interrupt before clearing iir  */
+       de_ier = I915_READ(DEIER);
+       I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL);
+       POSTING_READ(DEIER);
 
-       list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
-               if ((error->ccid & PAGE_MASK) == obj->gtt_offset) {
-                       ering->ctx = i915_error_object_create_sized(dev_priv,
-                                                                   obj, 1);
-               }
+       /* Disable south interrupts. We'll only write to SDEIIR once, so further
+        * interrupts will will be stored on its back queue, and then we'll be
+        * able to process them after we restore SDEIER (as soon as we restore
+        * it, we'll get an interrupt if SDEIIR still has something to process
+        * due to its back queue). */
+       if (!HAS_PCH_NOP(dev)) {
+               sde_ier = I915_READ(SDEIER);
+               I915_WRITE(SDEIER, 0);
+               POSTING_READ(SDEIER);
        }
-}
-
-static void i915_gem_record_rings(struct drm_device *dev,
-                                 struct drm_i915_error_state *error)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_ring_buffer *ring;
-       struct drm_i915_gem_request *request;
-       int i, count;
-
-       for_each_ring(ring, dev_priv, i) {
-               i915_record_ring_state(dev, error, ring);
-
-               error->ring[i].batchbuffer =
-                       i915_error_first_batchbuffer(dev_priv, ring);
-
-               error->ring[i].ringbuffer =
-                       i915_error_object_create(dev_priv, ring->obj);
 
+       /* On Haswell, also mask ERR_INT because we don't want to risk
+        * generating "unclaimed register" interrupts from inside the interrupt
+        * handler. */
+       if (IS_HASWELL(dev)) {
+               spin_lock(&dev_priv->irq_lock);
+               ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB);
+               spin_unlock(&dev_priv->irq_lock);
+       }
 
-               i915_gem_record_active_context(ring, error, &error->ring[i]);
+       gt_iir = I915_READ(GTIIR);
+       if (gt_iir) {
+               if (INTEL_INFO(dev)->gen >= 6)
+                       snb_gt_irq_handler(dev, dev_priv, gt_iir);
+               else
+                       ilk_gt_irq_handler(dev, dev_priv, gt_iir);
+               I915_WRITE(GTIIR, gt_iir);
+               ret = IRQ_HANDLED;
+       }
 
-               count = 0;
-               list_for_each_entry(request, &ring->request_list, list)
-                       count++;
+       de_iir = I915_READ(DEIIR);
+       if (de_iir) {
+               if (INTEL_INFO(dev)->gen >= 7)
+                       ivb_display_irq_handler(dev, de_iir);
+               else
+                       ilk_display_irq_handler(dev, de_iir);
+               I915_WRITE(DEIIR, de_iir);
+               ret = IRQ_HANDLED;
+       }
 
-               error->ring[i].num_requests = count;
-               error->ring[i].requests =
-                       kmalloc(count*sizeof(struct drm_i915_error_request),
-                               GFP_ATOMIC);
-               if (error->ring[i].requests == NULL) {
-                       error->ring[i].num_requests = 0;
-                       continue;
+       if (INTEL_INFO(dev)->gen >= 6) {
+               u32 pm_iir = I915_READ(GEN6_PMIIR);
+               if (pm_iir) {
+                       if (IS_HASWELL(dev))
+                               hsw_pm_irq_handler(dev_priv, pm_iir);
+                       else if (pm_iir & GEN6_PM_RPS_EVENTS)
+                               gen6_rps_irq_handler(dev_priv, pm_iir);
+                       I915_WRITE(GEN6_PMIIR, pm_iir);
+                       ret = IRQ_HANDLED;
                }
+       }
 
-               count = 0;
-               list_for_each_entry(request, &ring->request_list, list) {
-                       struct drm_i915_error_request *erq;
+       if (IS_HASWELL(dev)) {
+               spin_lock(&dev_priv->irq_lock);
+               if (ivb_can_enable_err_int(dev))
+                       ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB);
+               spin_unlock(&dev_priv->irq_lock);
+       }
 
-                       erq = &error->ring[i].requests[count++];
-                       erq->seqno = request->seqno;
-                       erq->jiffies = request->emitted_jiffies;
-                       erq->tail = request->tail;
-               }
+       I915_WRITE(DEIER, de_ier);
+       POSTING_READ(DEIER);
+       if (!HAS_PCH_NOP(dev)) {
+               I915_WRITE(SDEIER, sde_ier);
+               POSTING_READ(SDEIER);
        }
+
+       return ret;
 }
 
 /**
- * i915_capture_error_state - capture an error record for later analysis
- * @dev: drm device
+ * i915_error_work_func - do process context error handling work
+ * @work: work struct
  *
- * Should be called when an error is detected (either a hang or an error
- * interrupt) to capture error state from the time of the error.  Fills
- * out a structure which becomes available in debugfs for user level tools
- * to pick up.
+ * Fire an error uevent so userspace can see that a hang or error
+ * was detected.
  */
-static void i915_capture_error_state(struct drm_device *dev)
+static void i915_error_work_func(struct work_struct *work)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_i915_gem_object *obj;
-       struct drm_i915_error_state *error;
-       unsigned long flags;
-       int i, pipe;
-
-       spin_lock_irqsave(&dev_priv->gpu_error.lock, flags);
-       error = dev_priv->gpu_error.first_error;
-       spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags);
-       if (error)
-               return;
-
-       /* Account for pipe specific data like PIPE*STAT */
-       error = kzalloc(sizeof(*error), GFP_ATOMIC);
-       if (!error) {
-               DRM_DEBUG_DRIVER("out of memory, not capturing error state\n");
-               return;
-       }
-
-       DRM_INFO("capturing error event; look for more information in "
-                "/sys/kernel/debug/dri/%d/i915_error_state\n",
-                dev->primary->index);
-
-       kref_init(&error->ref);
-       error->eir = I915_READ(EIR);
-       error->pgtbl_er = I915_READ(PGTBL_ER);
-       if (HAS_HW_CONTEXTS(dev))
-               error->ccid = I915_READ(CCID);
-
-       if (HAS_PCH_SPLIT(dev))
-               error->ier = I915_READ(DEIER) | I915_READ(GTIER);
-       else if (IS_VALLEYVIEW(dev))
-               error->ier = I915_READ(GTIER) | I915_READ(VLV_IER);
-       else if (IS_GEN2(dev))
-               error->ier = I915_READ16(IER);
-       else
-               error->ier = I915_READ(IER);
-
-       if (INTEL_INFO(dev)->gen >= 6)
-               error->derrmr = I915_READ(DERRMR);
-
-       if (IS_VALLEYVIEW(dev))
-               error->forcewake = I915_READ(FORCEWAKE_VLV);
-       else if (INTEL_INFO(dev)->gen >= 7)
-               error->forcewake = I915_READ(FORCEWAKE_MT);
-       else if (INTEL_INFO(dev)->gen == 6)
-               error->forcewake = I915_READ(FORCEWAKE);
-
-       if (!HAS_PCH_SPLIT(dev))
-               for_each_pipe(pipe)
-                       error->pipestat[pipe] = I915_READ(PIPESTAT(pipe));
-
-       if (INTEL_INFO(dev)->gen >= 6) {
-               error->error = I915_READ(ERROR_GEN6);
-               error->done_reg = I915_READ(DONE_REG);
-       }
-
-       if (INTEL_INFO(dev)->gen == 7)
-               error->err_int = I915_READ(GEN7_ERR_INT);
-
-       i915_get_extra_instdone(dev, error->extra_instdone);
-
-       i915_gem_record_fences(dev, error);
-       i915_gem_record_rings(dev, error);
+       struct i915_gpu_error *error = container_of(work, struct i915_gpu_error,
+                                                   work);
+       drm_i915_private_t *dev_priv = container_of(error, drm_i915_private_t,
+                                                   gpu_error);
+       struct drm_device *dev = dev_priv->dev;
+       struct intel_ring_buffer *ring;
+       char *error_event[] = { I915_ERROR_UEVENT "=1", NULL };
+       char *reset_event[] = { I915_RESET_UEVENT "=1", NULL };
+       char *reset_done_event[] = { I915_ERROR_UEVENT "=0", NULL };
+       int i, ret;
 
-       /* Record buffers on the active and pinned lists. */
-       error->active_bo = NULL;
-       error->pinned_bo = NULL;
+       kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, error_event);
 
-       i = 0;
-       list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list)
-               i++;
-       error->active_bo_count = i;
-       list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list)
-               if (obj->pin_count)
-                       i++;
-       error->pinned_bo_count = i - error->active_bo_count;
+       /*
+        * Note that there's only one work item which does gpu resets, so we
+        * need not worry about concurrent gpu resets potentially incrementing
+        * error->reset_counter twice. We only need to take care of another
+        * racing irq/hangcheck declaring the gpu dead for a second time. A
+        * quick check for that is good enough: schedule_work ensures the
+        * correct ordering between hang detection and this work item, and since
+        * the reset in-progress bit is only ever set by code outside of this
+        * work we don't need to worry about any other races.
+        */
+       if (i915_reset_in_progress(error) && !i915_terminally_wedged(error)) {
+               DRM_DEBUG_DRIVER("resetting chip\n");
+               kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE,
+                                  reset_event);
 
-       error->active_bo = NULL;
-       error->pinned_bo = NULL;
-       if (i) {
-               error->active_bo = kmalloc(sizeof(*error->active_bo)*i,
-                                          GFP_ATOMIC);
-               if (error->active_bo)
-                       error->pinned_bo =
-                               error->active_bo + error->active_bo_count;
-       }
+               ret = i915_reset(dev);
 
-       if (error->active_bo)
-               error->active_bo_count =
-                       capture_active_bo(error->active_bo,
-                                         error->active_bo_count,
-                                         &dev_priv->mm.active_list);
+               if (ret == 0) {
+                       /*
+                        * After all the gem state is reset, increment the reset
+                        * counter and wake up everyone waiting for the reset to
+                        * complete.
+                        *
+                        * Since unlock operations are a one-sided barrier only,
+                        * we need to insert a barrier here to order any seqno
+                        * updates before
+                        * the counter increment.
+                        */
+                       smp_mb__before_atomic_inc();
+                       atomic_inc(&dev_priv->gpu_error.reset_counter);
 
-       if (error->pinned_bo)
-               error->pinned_bo_count =
-                       capture_pinned_bo(error->pinned_bo,
-                                         error->pinned_bo_count,
-                                         &dev_priv->mm.bound_list);
+                       kobject_uevent_env(&dev->primary->kdev.kobj,
+                                          KOBJ_CHANGE, reset_done_event);
+               } else {
+                       atomic_set(&error->reset_counter, I915_WEDGED);
+               }
 
-       do_gettimeofday(&error->time);
+               for_each_ring(ring, dev_priv, i)
+                       wake_up_all(&ring->irq_queue);
 
-       error->overlay = intel_overlay_capture_error_state(dev);
-       error->display = intel_display_capture_error_state(dev);
+               intel_display_handle_reset(dev);
 
-       spin_lock_irqsave(&dev_priv->gpu_error.lock, flags);
-       if (dev_priv->gpu_error.first_error == NULL) {
-               dev_priv->gpu_error.first_error = error;
-               error = NULL;
+               wake_up_all(&dev_priv->gpu_error.reset_queue);
        }
-       spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags);
-
-       if (error)
-               i915_error_state_free(&error->ref);
 }
 
-void i915_destroy_error_state(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_i915_error_state *error;
-       unsigned long flags;
-
-       spin_lock_irqsave(&dev_priv->gpu_error.lock, flags);
-       error = dev_priv->gpu_error.first_error;
-       dev_priv->gpu_error.first_error = NULL;
-       spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags);
-
-       if (error)
-               kref_put(&error->ref, i915_error_state_free);
-}
-#else
-#define i915_capture_error_state(x)
-#endif
-
 static void i915_report_and_clear_eir(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2155,10 +1614,10 @@ static void __always_unused i915_pageflip_stall_check(struct drm_device *dev, in
        if (INTEL_INFO(dev)->gen >= 4) {
                int dspsurf = DSPSURF(intel_crtc->plane);
                stall_detected = I915_HI_DISPBASE(I915_READ(dspsurf)) ==
-                                       obj->gtt_offset;
+                                       i915_gem_obj_ggtt_offset(obj);
        } else {
                int dspaddr = DSPADDR(intel_crtc->plane);
-               stall_detected = I915_READ(dspaddr) == (obj->gtt_offset +
+               stall_detected = I915_READ(dspaddr) == (i915_gem_obj_ggtt_offset(obj) +
                                                        crtc->y * crtc->fb->pitches[0] +
                                                        crtc->x * crtc->fb->bits_per_pixel/8);
        }
@@ -2202,29 +1661,14 @@ static int ironlake_enable_vblank(struct drm_device *dev, int pipe)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        unsigned long irqflags;
+       uint32_t bit = (INTEL_INFO(dev)->gen >= 7) ? DE_PIPE_VBLANK_IVB(pipe) :
+                                                    DE_PIPE_VBLANK_ILK(pipe);
 
        if (!i915_pipe_enabled(dev, pipe))
                return -EINVAL;
 
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-       ironlake_enable_display_irq(dev_priv, (pipe == 0) ?
-                                   DE_PIPEA_VBLANK : DE_PIPEB_VBLANK);
-       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
-
-       return 0;
-}
-
-static int ivybridge_enable_vblank(struct drm_device *dev, int pipe)
-{
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       unsigned long irqflags;
-
-       if (!i915_pipe_enabled(dev, pipe))
-               return -EINVAL;
-
-       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-       ironlake_enable_display_irq(dev_priv,
-                                   DE_PIPEA_VBLANK_IVB << (5 * pipe));
+       ironlake_enable_display_irq(dev_priv, bit);
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
        return 0;
@@ -2275,21 +1719,11 @@ static void ironlake_disable_vblank(struct drm_device *dev, int pipe)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        unsigned long irqflags;
+       uint32_t bit = (INTEL_INFO(dev)->gen >= 7) ? DE_PIPE_VBLANK_IVB(pipe) :
+                                                    DE_PIPE_VBLANK_ILK(pipe);
 
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-       ironlake_disable_display_irq(dev_priv, (pipe == 0) ?
-                                    DE_PIPEA_VBLANK : DE_PIPEB_VBLANK);
-       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
-}
-
-static void ivybridge_disable_vblank(struct drm_device *dev, int pipe)
-{
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       unsigned long irqflags;
-
-       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-       ironlake_disable_display_irq(dev_priv,
-                                    DE_PIPEA_VBLANK_IVB << (pipe * 5));
+       ironlake_disable_display_irq(dev_priv, bit);
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 }
 
@@ -2536,9 +1970,17 @@ void i915_hangcheck_elapsed(unsigned long data)
        if (busy_count)
                /* Reset timer case chip hangs without another request
                 * being added */
-               mod_timer(&dev_priv->gpu_error.hangcheck_timer,
-                         round_jiffies_up(jiffies +
-                                          DRM_I915_HANGCHECK_JIFFIES));
+               i915_queue_hangcheck(dev);
+}
+
+void i915_queue_hangcheck(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       if (!i915_enable_hangcheck)
+               return;
+
+       mod_timer(&dev_priv->gpu_error.hangcheck_timer,
+                 round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES));
 }
 
 static void ibx_irq_preinstall(struct drm_device *dev)
@@ -2560,31 +2002,26 @@ static void ibx_irq_preinstall(struct drm_device *dev)
        POSTING_READ(SDEIER);
 }
 
-/* drm_dma.h hooks
-*/
-static void ironlake_irq_preinstall(struct drm_device *dev)
+static void gen5_gt_irq_preinstall(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-
-       atomic_set(&dev_priv->irq_received, 0);
-
-       I915_WRITE(HWSTAM, 0xeffe);
-
-       /* XXX hotplug from PCH */
-
-       I915_WRITE(DEIMR, 0xffffffff);
-       I915_WRITE(DEIER, 0x0);
-       POSTING_READ(DEIER);
+       struct drm_i915_private *dev_priv = dev->dev_private;
 
        /* and GT */
        I915_WRITE(GTIMR, 0xffffffff);
        I915_WRITE(GTIER, 0x0);
        POSTING_READ(GTIER);
 
-       ibx_irq_preinstall(dev);
+       if (INTEL_INFO(dev)->gen >= 6) {
+               /* and PM */
+               I915_WRITE(GEN6_PMIMR, 0xffffffff);
+               I915_WRITE(GEN6_PMIER, 0x0);
+               POSTING_READ(GEN6_PMIER);
+       }
 }
 
-static void ivybridge_irq_preinstall(struct drm_device *dev)
+/* drm_dma.h hooks
+*/
+static void ironlake_irq_preinstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 
@@ -2592,21 +2029,11 @@ static void ivybridge_irq_preinstall(struct drm_device *dev)
 
        I915_WRITE(HWSTAM, 0xeffe);
 
-       /* XXX hotplug from PCH */
-
        I915_WRITE(DEIMR, 0xffffffff);
        I915_WRITE(DEIER, 0x0);
        POSTING_READ(DEIER);
 
-       /* and GT */
-       I915_WRITE(GTIMR, 0xffffffff);
-       I915_WRITE(GTIER, 0x0);
-       POSTING_READ(GTIER);
-
-       /* Power management */
-       I915_WRITE(GEN6_PMIMR, 0xffffffff);
-       I915_WRITE(GEN6_PMIER, 0x0);
-       POSTING_READ(GEN6_PMIER);
+       gen5_gt_irq_preinstall(dev);
 
        ibx_irq_preinstall(dev);
 }
@@ -2627,9 +2054,8 @@ static void valleyview_irq_preinstall(struct drm_device *dev)
        /* and GT */
        I915_WRITE(GTIIR, I915_READ(GTIIR));
        I915_WRITE(GTIIR, I915_READ(GTIIR));
-       I915_WRITE(GTIMR, 0xffffffff);
-       I915_WRITE(GTIER, 0x0);
-       POSTING_READ(GTIER);
+
+       gen5_gt_irq_preinstall(dev);
 
        I915_WRITE(DPINVGTT, 0xff);
 
@@ -2648,22 +2074,21 @@ static void ibx_hpd_irq_setup(struct drm_device *dev)
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        struct drm_mode_config *mode_config = &dev->mode_config;
        struct intel_encoder *intel_encoder;
-       u32 mask = ~I915_READ(SDEIMR);
-       u32 hotplug;
+       u32 hotplug_irqs, hotplug, enabled_irqs = 0;
 
        if (HAS_PCH_IBX(dev)) {
-               mask &= ~SDE_HOTPLUG_MASK;
+               hotplug_irqs = SDE_HOTPLUG_MASK;
                list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head)
                        if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED)
-                               mask |= hpd_ibx[intel_encoder->hpd_pin];
+                               enabled_irqs |= hpd_ibx[intel_encoder->hpd_pin];
        } else {
-               mask &= ~SDE_HOTPLUG_MASK_CPT;
+               hotplug_irqs = SDE_HOTPLUG_MASK_CPT;
                list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head)
                        if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED)
-                               mask |= hpd_cpt[intel_encoder->hpd_pin];
+                               enabled_irqs |= hpd_cpt[intel_encoder->hpd_pin];
        }
 
-       I915_WRITE(SDEIMR, ~mask);
+       ibx_display_interrupt_update(dev_priv, hotplug_irqs, enabled_irqs);
 
        /*
         * Enable digital hotplug on the PCH, and configure the DP short pulse
@@ -2700,123 +2125,102 @@ static void ibx_irq_postinstall(struct drm_device *dev)
        I915_WRITE(SDEIMR, ~mask);
 }
 
-static int ironlake_irq_postinstall(struct drm_device *dev)
+static void gen5_gt_irq_postinstall(struct drm_device *dev)
 {
-       unsigned long irqflags;
-
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       /* enable kind of interrupts always enabled */
-       u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
-                          DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE |
-                          DE_AUX_CHANNEL_A | DE_PIPEB_FIFO_UNDERRUN |
-                          DE_PIPEA_FIFO_UNDERRUN | DE_POISON;
-       u32 gt_irqs;
-
-       dev_priv->irq_mask = ~display_mask;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 pm_irqs, gt_irqs;
 
-       /* should always can generate irq */
-       I915_WRITE(DEIIR, I915_READ(DEIIR));
-       I915_WRITE(DEIMR, dev_priv->irq_mask);
-       I915_WRITE(DEIER, display_mask |
-                         DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT);
-       POSTING_READ(DEIER);
+       pm_irqs = gt_irqs = 0;
 
        dev_priv->gt_irq_mask = ~0;
+       if (HAS_L3_GPU_CACHE(dev)) {
+               /* L3 parity interrupt is always unmasked. */
+               dev_priv->gt_irq_mask = ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
+               gt_irqs |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
+       }
 
-       I915_WRITE(GTIIR, I915_READ(GTIIR));
-       I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
-
-       gt_irqs = GT_RENDER_USER_INTERRUPT;
-
-       if (IS_GEN6(dev))
-               gt_irqs |= GT_BLT_USER_INTERRUPT | GT_BSD_USER_INTERRUPT;
-       else
+       gt_irqs |= GT_RENDER_USER_INTERRUPT;
+       if (IS_GEN5(dev)) {
                gt_irqs |= GT_RENDER_PIPECTL_NOTIFY_INTERRUPT |
                           ILK_BSD_USER_INTERRUPT;
+       } else {
+               gt_irqs |= GT_BLT_USER_INTERRUPT | GT_BSD_USER_INTERRUPT;
+       }
 
+       I915_WRITE(GTIIR, I915_READ(GTIIR));
+       I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
        I915_WRITE(GTIER, gt_irqs);
        POSTING_READ(GTIER);
 
-       ibx_irq_postinstall(dev);
+       if (INTEL_INFO(dev)->gen >= 6) {
+               pm_irqs |= GEN6_PM_RPS_EVENTS;
 
-       if (IS_IRONLAKE_M(dev)) {
-               /* Enable PCU event interrupts
-                *
-                * spinlocking not required here for correctness since interrupt
-                * setup is guaranteed to run in single-threaded context. But we
-                * need it to make the assert_spin_locked happy. */
-               spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-               ironlake_enable_display_irq(dev_priv, DE_PCU_EVENT);
-               spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
-       }
+               if (HAS_VEBOX(dev))
+                       pm_irqs |= PM_VEBOX_USER_INTERRUPT;
 
-       return 0;
+               I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR));
+               I915_WRITE(GEN6_PMIMR, 0xffffffff);
+               I915_WRITE(GEN6_PMIER, pm_irqs);
+               POSTING_READ(GEN6_PMIER);
+       }
 }
 
-static int ivybridge_irq_postinstall(struct drm_device *dev)
+static int ironlake_irq_postinstall(struct drm_device *dev)
 {
+       unsigned long irqflags;
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       /* enable kind of interrupts always enabled */
-       u32 display_mask =
-               DE_MASTER_IRQ_CONTROL | DE_GSE_IVB | DE_PCH_EVENT_IVB |
-               DE_PLANEC_FLIP_DONE_IVB |
-               DE_PLANEB_FLIP_DONE_IVB |
-               DE_PLANEA_FLIP_DONE_IVB |
-               DE_AUX_CHANNEL_A_IVB |
-               DE_ERR_INT_IVB;
-       u32 pm_irqs = GEN6_PM_RPS_EVENTS;
-       u32 gt_irqs;
+       u32 display_mask, extra_mask;
+
+       if (INTEL_INFO(dev)->gen >= 7) {
+               display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE_IVB |
+                               DE_PCH_EVENT_IVB | DE_PLANEC_FLIP_DONE_IVB |
+                               DE_PLANEB_FLIP_DONE_IVB |
+                               DE_PLANEA_FLIP_DONE_IVB | DE_AUX_CHANNEL_A_IVB |
+                               DE_ERR_INT_IVB);
+               extra_mask = (DE_PIPEC_VBLANK_IVB | DE_PIPEB_VBLANK_IVB |
+                             DE_PIPEA_VBLANK_IVB);
+
+               I915_WRITE(GEN7_ERR_INT, I915_READ(GEN7_ERR_INT));
+       } else {
+               display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
+                               DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE |
+                               DE_AUX_CHANNEL_A | DE_PIPEB_FIFO_UNDERRUN |
+                               DE_PIPEA_FIFO_UNDERRUN | DE_POISON);
+               extra_mask = DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT;
+       }
 
        dev_priv->irq_mask = ~display_mask;
 
        /* should always can generate irq */
-       I915_WRITE(GEN7_ERR_INT, I915_READ(GEN7_ERR_INT));
        I915_WRITE(DEIIR, I915_READ(DEIIR));
        I915_WRITE(DEIMR, dev_priv->irq_mask);
-       I915_WRITE(DEIER,
-                  display_mask |
-                  DE_PIPEC_VBLANK_IVB |
-                  DE_PIPEB_VBLANK_IVB |
-                  DE_PIPEA_VBLANK_IVB);
+       I915_WRITE(DEIER, display_mask | extra_mask);
        POSTING_READ(DEIER);
 
-       dev_priv->gt_irq_mask = ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
-
-       I915_WRITE(GTIIR, I915_READ(GTIIR));
-       I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
-
-       gt_irqs = GT_RENDER_USER_INTERRUPT | GT_BSD_USER_INTERRUPT |
-                 GT_BLT_USER_INTERRUPT | GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
-       I915_WRITE(GTIER, gt_irqs);
-       POSTING_READ(GTIER);
-
-       I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR));
-       if (HAS_VEBOX(dev))
-               pm_irqs |= PM_VEBOX_USER_INTERRUPT |
-                       PM_VEBOX_CS_ERROR_INTERRUPT;
-
-       /* Our enable/disable rps functions may touch these registers so
-        * make sure to set a known state for only the non-RPS bits.
-        * The RMW is extra paranoia since this should be called after being set
-        * to a known state in preinstall.
-        * */
-       I915_WRITE(GEN6_PMIMR,
-                  (I915_READ(GEN6_PMIMR) | ~GEN6_PM_RPS_EVENTS) & ~pm_irqs);
-       I915_WRITE(GEN6_PMIER,
-                  (I915_READ(GEN6_PMIER) & GEN6_PM_RPS_EVENTS) | pm_irqs);
-       POSTING_READ(GEN6_PMIER);
+       gen5_gt_irq_postinstall(dev);
 
        ibx_irq_postinstall(dev);
 
+       if (IS_IRONLAKE_M(dev)) {
+               /* Enable PCU event interrupts
+                *
+                * spinlocking not required here for correctness since interrupt
+                * setup is guaranteed to run in single-threaded context. But we
+                * need it to make the assert_spin_locked happy. */
+               spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+               ironlake_enable_display_irq(dev_priv, DE_PCU_EVENT);
+               spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+       }
+
        return 0;
 }
 
 static int valleyview_irq_postinstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       u32 gt_irqs;
        u32 enable_mask;
        u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV;
+       unsigned long irqflags;
 
        enable_mask = I915_DISPLAY_PORT_INTERRUPT;
        enable_mask |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
@@ -2842,20 +2246,18 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
        I915_WRITE(PIPESTAT(1), 0xffff);
        POSTING_READ(VLV_IER);
 
+       /* Interrupt setup is already guaranteed to be single-threaded, this is
+        * just to make the assert_spin_locked check happy. */
+       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
        i915_enable_pipestat(dev_priv, 0, pipestat_enable);
        i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE);
        i915_enable_pipestat(dev_priv, 1, pipestat_enable);
+       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
        I915_WRITE(VLV_IIR, 0xffffffff);
        I915_WRITE(VLV_IIR, 0xffffffff);
 
-       I915_WRITE(GTIIR, I915_READ(GTIIR));
-       I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
-
-       gt_irqs = GT_RENDER_USER_INTERRUPT | GT_BSD_USER_INTERRUPT |
-               GT_BLT_USER_INTERRUPT;
-       I915_WRITE(GTIER, gt_irqs);
-       POSTING_READ(GTIER);
+       gen5_gt_irq_postinstall(dev);
 
        /* ack & enable invalid PTE error interrupts */
 #if 0 /* FIXME: add support to irq handler for checking these bits */
@@ -3323,6 +2725,7 @@ static int i965_irq_postinstall(struct drm_device *dev)
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        u32 enable_mask;
        u32 error_mask;
+       unsigned long irqflags;
 
        /* Unmask the interrupts that we always want on. */
        dev_priv->irq_mask = ~(I915_ASLE_INTERRUPT |
@@ -3341,7 +2744,11 @@ static int i965_irq_postinstall(struct drm_device *dev)
        if (IS_G4X(dev))
                enable_mask |= I915_BSD_USER_INTERRUPT;
 
+       /* Interrupt setup is already guaranteed to be single-threaded, this is
+        * just to make the assert_spin_locked check happy. */
+       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
        i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE);
+       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
        /*
         * Enable some error detection, note the instruction error mask
@@ -3616,15 +3023,6 @@ void intel_irq_init(struct drm_device *dev)
                dev->driver->enable_vblank = valleyview_enable_vblank;
                dev->driver->disable_vblank = valleyview_disable_vblank;
                dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
-       } else if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) {
-               /* Share uninstall handlers with ILK/SNB */
-               dev->driver->irq_handler = ivybridge_irq_handler;
-               dev->driver->irq_preinstall = ivybridge_irq_preinstall;
-               dev->driver->irq_postinstall = ivybridge_irq_postinstall;
-               dev->driver->irq_uninstall = ironlake_irq_uninstall;
-               dev->driver->enable_vblank = ivybridge_enable_vblank;
-               dev->driver->disable_vblank = ivybridge_disable_vblank;
-               dev_priv->display.hpd_irq_setup = ibx_hpd_irq_setup;
        } else if (HAS_PCH_SPLIT(dev)) {
                dev->driver->irq_handler = ironlake_irq_handler;
                dev->driver->irq_preinstall = ironlake_irq_preinstall;
index f2326fc60ac93d4a2f1c760333945fb33bbe0524..19941c679b5df596d5297cfd13f6ccbd635186a1 100644 (file)
 #define   GC_LOW_FREQUENCY_ENABLE      (1 << 7)
 #define   GC_DISPLAY_CLOCK_190_200_MHZ (0 << 4)
 #define   GC_DISPLAY_CLOCK_333_MHZ     (4 << 4)
+#define   GC_DISPLAY_CLOCK_267_MHZ_PNV (0 << 4)
+#define   GC_DISPLAY_CLOCK_333_MHZ_PNV (1 << 4)
+#define   GC_DISPLAY_CLOCK_444_MHZ_PNV (2 << 4)
+#define   GC_DISPLAY_CLOCK_200_MHZ_PNV (5 << 4)
+#define   GC_DISPLAY_CLOCK_133_MHZ_PNV (6 << 4)
+#define   GC_DISPLAY_CLOCK_167_MHZ_PNV (7 << 4)
 #define   GC_DISPLAY_CLOCK_MASK                (7 << 4)
 #define   GM45_GC_RENDER_CLOCK_MASK    (0xf << 0)
 #define   GM45_GC_RENDER_CLOCK_266_MHZ (8 << 0)
 #define PUNIT_REG_GPU_LFM                      0xd3
 #define PUNIT_REG_GPU_FREQ_REQ                 0xd4
 #define PUNIT_REG_GPU_FREQ_STS                 0xd8
+#define   GENFREQSTATUS                                (1<<0)
 #define PUNIT_REG_MEDIA_TURBO_FREQ_REQ         0xdc
 
 #define PUNIT_FUSE_BUS2                                0xf6 /* bits 47:40 */
 #define   ERR_INT_FIFO_UNDERRUN_C      (1<<6)
 #define   ERR_INT_FIFO_UNDERRUN_B      (1<<3)
 #define   ERR_INT_FIFO_UNDERRUN_A      (1<<0)
+#define   ERR_INT_FIFO_UNDERRUN(pipe)  (1<<(pipe*3))
 
 #define FPGA_DBG               0x42300
 #define   FPGA_DBG_RM_NOCLAIM  (1<<31)
 #define _DPLL_B        (dev_priv->info->display_mmio_offset + 0x6018)
 #define DPLL(pipe) _PIPE(pipe, _DPLL_A, _DPLL_B)
 #define   DPLL_VCO_ENABLE              (1 << 31)
-#define   DPLL_DVO_HIGH_SPEED          (1 << 30)
+#define   DPLL_SDVO_HIGH_SPEED         (1 << 30)
+#define   DPLL_DVO_2X_MODE             (1 << 30)
 #define   DPLL_EXT_BUFFER_ENABLE_VLV   (1 << 30)
 #define   DPLL_SYNCLOCK_ENABLE         (1 << 29)
 #define   DPLL_REFA_CLK_ENABLE_VLV     (1 << 29)
 #define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B)
 #define VSYNCSHIFT(trans) _TRANSCODER(trans, _VSYNCSHIFT_A, _VSYNCSHIFT_B)
 
+/* HSW eDP PSR registers */
+#define EDP_PSR_CTL                            0x64800
+#define   EDP_PSR_ENABLE                       (1<<31)
+#define   EDP_PSR_LINK_DISABLE                 (0<<27)
+#define   EDP_PSR_LINK_STANDBY                 (1<<27)
+#define   EDP_PSR_MIN_LINK_ENTRY_TIME_MASK     (3<<25)
+#define   EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES  (0<<25)
+#define   EDP_PSR_MIN_LINK_ENTRY_TIME_4_LINES  (1<<25)
+#define   EDP_PSR_MIN_LINK_ENTRY_TIME_2_LINES  (2<<25)
+#define   EDP_PSR_MIN_LINK_ENTRY_TIME_0_LINES  (3<<25)
+#define   EDP_PSR_MAX_SLEEP_TIME_SHIFT         20
+#define   EDP_PSR_SKIP_AUX_EXIT                        (1<<12)
+#define   EDP_PSR_TP1_TP2_SEL                  (0<<11)
+#define   EDP_PSR_TP1_TP3_SEL                  (1<<11)
+#define   EDP_PSR_TP2_TP3_TIME_500us           (0<<8)
+#define   EDP_PSR_TP2_TP3_TIME_100us           (1<<8)
+#define   EDP_PSR_TP2_TP3_TIME_2500us          (2<<8)
+#define   EDP_PSR_TP2_TP3_TIME_0us             (3<<8)
+#define   EDP_PSR_TP1_TIME_500us               (0<<4)
+#define   EDP_PSR_TP1_TIME_100us               (1<<4)
+#define   EDP_PSR_TP1_TIME_2500us              (2<<4)
+#define   EDP_PSR_TP1_TIME_0us                 (3<<4)
+#define   EDP_PSR_IDLE_FRAME_SHIFT             0
+
+#define EDP_PSR_AUX_CTL                        0x64810
+#define EDP_PSR_AUX_DATA1              0x64814
+#define   EDP_PSR_DPCD_COMMAND         0x80060000
+#define EDP_PSR_AUX_DATA2              0x64818
+#define   EDP_PSR_DPCD_NORMAL_OPERATION        (1<<24)
+#define EDP_PSR_AUX_DATA3              0x6481c
+#define EDP_PSR_AUX_DATA4              0x64820
+#define EDP_PSR_AUX_DATA5              0x64824
+
+#define EDP_PSR_STATUS_CTL                     0x64840
+#define   EDP_PSR_STATUS_STATE_MASK            (7<<29)
+#define   EDP_PSR_STATUS_STATE_IDLE            (0<<29)
+#define   EDP_PSR_STATUS_STATE_SRDONACK                (1<<29)
+#define   EDP_PSR_STATUS_STATE_SRDENT          (2<<29)
+#define   EDP_PSR_STATUS_STATE_BUFOFF          (3<<29)
+#define   EDP_PSR_STATUS_STATE_BUFON           (4<<29)
+#define   EDP_PSR_STATUS_STATE_AUXACK          (5<<29)
+#define   EDP_PSR_STATUS_STATE_SRDOFFACK       (6<<29)
+#define   EDP_PSR_STATUS_LINK_MASK             (3<<26)
+#define   EDP_PSR_STATUS_LINK_FULL_OFF         (0<<26)
+#define   EDP_PSR_STATUS_LINK_FULL_ON          (1<<26)
+#define   EDP_PSR_STATUS_LINK_STANDBY          (2<<26)
+#define   EDP_PSR_STATUS_MAX_SLEEP_TIMER_SHIFT 20
+#define   EDP_PSR_STATUS_MAX_SLEEP_TIMER_MASK  0x1f
+#define   EDP_PSR_STATUS_COUNT_SHIFT           16
+#define   EDP_PSR_STATUS_COUNT_MASK            0xf
+#define   EDP_PSR_STATUS_AUX_ERROR             (1<<15)
+#define   EDP_PSR_STATUS_AUX_SENDING           (1<<12)
+#define   EDP_PSR_STATUS_SENDING_IDLE          (1<<9)
+#define   EDP_PSR_STATUS_SENDING_TP2_TP3       (1<<8)
+#define   EDP_PSR_STATUS_SENDING_TP1           (1<<4)
+#define   EDP_PSR_STATUS_IDLE_MASK             0xf
+
+#define EDP_PSR_PERF_CNT               0x64844
+#define   EDP_PSR_PERF_CNT_MASK                0xffffff
+
+#define EDP_PSR_DEBUG_CTL              0x64860
+#define   EDP_PSR_DEBUG_MASK_LPSP      (1<<27)
+#define   EDP_PSR_DEBUG_MASK_MEMUP     (1<<26)
+#define   EDP_PSR_DEBUG_MASK_HPD       (1<<25)
+
 /* VGA port control */
 #define ADPA                   0x61100
 #define PCH_ADPA                0xe1100
 #define CRT_HOTPLUG_DETECT_VOLTAGE_475MV       (1 << 2)
 
 #define PORT_HOTPLUG_STAT      (dev_priv->info->display_mmio_offset + 0x61114)
-/* HDMI/DP bits are gen4+ */
-#define   PORTB_HOTPLUG_LIVE_STATUS               (1 << 29)
+/*
+ * HDMI/DP bits are gen4+
+ *
+ * WARNING: Bspec for hpd status bits on gen4 seems to be completely confused.
+ * Please check the detailed lore in the commit message for for experimental
+ * evidence.
+ */
+#define   PORTD_HOTPLUG_LIVE_STATUS               (1 << 29)
 #define   PORTC_HOTPLUG_LIVE_STATUS               (1 << 28)
-#define   PORTD_HOTPLUG_LIVE_STATUS               (1 << 27)
+#define   PORTB_HOTPLUG_LIVE_STATUS               (1 << 27)
 #define   PORTD_HOTPLUG_INT_STATUS             (3 << 21)
 #define   PORTC_HOTPLUG_INT_STATUS             (3 << 19)
 #define   PORTB_HOTPLUG_INT_STATUS             (3 << 17)
  * (Haswell and newer) to see which VIDEO_DIP_DATA byte corresponds to each byte
  * of the infoframe structure specified by CEA-861. */
 #define   VIDEO_DIP_DATA_SIZE  32
+#define   VIDEO_DIP_VSC_DATA_SIZE      36
 #define VIDEO_DIP_CTL          0x61170
 /* Pre HSW: */
 #define   VIDEO_DIP_ENABLE             (1 << 31)
 #define BLC_PWM_CPU_CTL2       0x48250
 #define BLC_PWM_CPU_CTL                0x48254
 
+#define HSW_BLC_PWM2_CTL       0x48350
+
 /* PCH CTL1 is totally different, all but the below bits are reserved. CTL2 is
  * like the normal CTL from gen4 and earlier. Hooray for confusing naming. */
 #define BLC_PWM_PCH_CTL1       0xc8250
 #define   BLM_PCH_POLARITY                     (1 << 29)
 #define BLC_PWM_PCH_CTL2       0xc8254
 
+#define UTIL_PIN_CTL           0x48400
+#define   UTIL_PIN_ENABLE      (1 << 31)
+
+#define PCH_GTC_CTL            0xe7000
+#define   PCH_GTC_ENABLE       (1 << 31)
+
 /* TV port control */
 #define TV_CTL                 0x68000
 /** Enables the TV encoder */
 #define DE_PLANEA_FLIP_DONE_IVB                (1<<3)
 #define DE_PIPEA_VBLANK_IVB            (1<<0)
 
+#define DE_PIPE_VBLANK_ILK(pipe)       (1 << ((pipe * 8) + 7))
+#define DE_PIPE_VBLANK_IVB(pipe)       (1 << (pipe * 5))
+
 #define VLV_MASTER_IER                 0x4400c /* Gunit master IER */
 #define   MASTER_INTERRUPT_ENABLE      (1<<31)
 
 #define  SERR_INT_TRANS_C_FIFO_UNDERRUN        (1<<6)
 #define  SERR_INT_TRANS_B_FIFO_UNDERRUN        (1<<3)
 #define  SERR_INT_TRANS_A_FIFO_UNDERRUN        (1<<0)
+#define  SERR_INT_TRANS_FIFO_UNDERRUN(pipe)    (1<<(pipe*3))
 
 /* digital port hotplug */
 #define PCH_PORT_HOTPLUG        0xc4030                /* SHOTPLUG_CTL */
 #define HSW_TVIDEO_DIP_VSC_DATA(trans) \
         _TRANSCODER(trans, HSW_VIDEO_DIP_VSC_DATA_A, HSW_VIDEO_DIP_VSC_DATA_B)
 
+#define HSW_STEREO_3D_CTL_A    0x70020
+#define   S3D_ENABLE           (1<<31)
+#define HSW_STEREO_3D_CTL_B    0x71020
+
+#define HSW_STEREO_3D_CTL(trans) \
+       _TRANSCODER(trans, HSW_STEREO_3D_CTL_A, HSW_STEREO_3D_CTL_A)
+
 #define _PCH_TRANS_HTOTAL_B          0xe1000
 #define _PCH_TRANS_HBLANK_B          0xe1004
 #define _PCH_TRANS_HSYNC_B           0xe1008
 #define  GT_FIFO_FREE_ENTRIES                  0x120008
 #define    GT_FIFO_NUM_RESERVED_ENTRIES                20
 
+#define  HSW_IDICR                             0x9008
+#define    IDIHASHMSK(x)                       (((x) & 0x3f) << 16)
+#define  HSW_EDRAM_PRESENT                     0x120010
+
 #define GEN6_UCGCTL1                           0x9400
 # define GEN6_BLBUNIT_CLOCK_GATE_DISABLE               (1 << 5)
 # define GEN6_CSUNIT_CLOCK_GATE_DISABLE                        (1 << 7)
 #define  SBI_SSCAUXDIV6                                0x0610
 #define   SBI_SSCAUXDIV_FINALDIV2SEL(x)                ((x)<<4)
 #define  SBI_DBUFF0                            0x2a00
-#define   SBI_DBUFF0_ENABLE                    (1<<0)
+#define  SBI_GEN0                              0x1f00
+#define   SBI_GEN0_CFG_BUFFENABLE_DISABLE      (1<<0)
 
 /* LPT PIXCLK_GATE */
 #define PIXCLK_GATE                    0xC6020
 #define  LCPLL_CLK_FREQ_450            (0<<26)
 #define  LCPLL_CD_CLOCK_DISABLE                (1<<25)
 #define  LCPLL_CD2X_CLOCK_DISABLE      (1<<23)
+#define  LCPLL_POWER_DOWN_ALLOW                (1<<22)
 #define  LCPLL_CD_SOURCE_FCLK          (1<<21)
+#define  LCPLL_CD_SOURCE_FCLK_DONE     (1<<19)
+
+#define D_COMP                         (MCHBAR_MIRROR_BASE_SNB + 0x5F0C)
+#define  D_COMP_RCOMP_IN_PROGRESS      (1<<9)
+#define  D_COMP_COMP_FORCE             (1<<8)
+#define  D_COMP_COMP_DISABLE           (1<<0)
 
 /* Pipe WM_LINETIME - watermark line time */
 #define PIPE_WM_LINETIME_A             0x45270
index 6875b5654c63d55a65dcf639734e0de101f1f037..a777e7f3b0df924c7e7d2401b3994f6b8e963f3c 100644 (file)
@@ -409,6 +409,71 @@ static const struct attribute *gen6_attrs[] = {
        NULL,
 };
 
+static ssize_t error_state_read(struct file *filp, struct kobject *kobj,
+                               struct bin_attribute *attr, char *buf,
+                               loff_t off, size_t count)
+{
+
+       struct device *kdev = container_of(kobj, struct device, kobj);
+       struct drm_minor *minor = container_of(kdev, struct drm_minor, kdev);
+       struct drm_device *dev = minor->dev;
+       struct i915_error_state_file_priv error_priv;
+       struct drm_i915_error_state_buf error_str;
+       ssize_t ret_count = 0;
+       int ret;
+
+       memset(&error_priv, 0, sizeof(error_priv));
+
+       ret = i915_error_state_buf_init(&error_str, count, off);
+       if (ret)
+               return ret;
+
+       error_priv.dev = dev;
+       i915_error_state_get(dev, &error_priv);
+
+       ret = i915_error_state_to_str(&error_str, &error_priv);
+       if (ret)
+               goto out;
+
+       ret_count = count < error_str.bytes ? count : error_str.bytes;
+
+       memcpy(buf, error_str.buf, ret_count);
+out:
+       i915_error_state_put(&error_priv);
+       i915_error_state_buf_release(&error_str);
+
+       return ret ?: ret_count;
+}
+
+static ssize_t error_state_write(struct file *file, struct kobject *kobj,
+                                struct bin_attribute *attr, char *buf,
+                                loff_t off, size_t count)
+{
+       struct device *kdev = container_of(kobj, struct device, kobj);
+       struct drm_minor *minor = container_of(kdev, struct drm_minor, kdev);
+       struct drm_device *dev = minor->dev;
+       int ret;
+
+       DRM_DEBUG_DRIVER("Resetting error state\n");
+
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
+
+       i915_destroy_error_state(dev);
+       mutex_unlock(&dev->struct_mutex);
+
+       return count;
+}
+
+static struct bin_attribute error_state_attr = {
+       .attr.name = "error",
+       .attr.mode = S_IRUSR | S_IWUSR,
+       .size = 0,
+       .read = error_state_read,
+       .write = error_state_write,
+};
+
 void i915_setup_sysfs(struct drm_device *dev)
 {
        int ret;
@@ -432,10 +497,16 @@ void i915_setup_sysfs(struct drm_device *dev)
                if (ret)
                        DRM_ERROR("gen6 sysfs setup failed\n");
        }
+
+       ret = sysfs_create_bin_file(&dev->primary->kdev.kobj,
+                                   &error_state_attr);
+       if (ret)
+               DRM_ERROR("error_state sysfs setup failed\n");
 }
 
 void i915_teardown_sysfs(struct drm_device *dev)
 {
+       sysfs_remove_bin_file(&dev->primary->kdev.kobj, &error_state_attr);
        sysfs_remove_files(&dev->primary->kdev.kobj, gen6_attrs);
        device_remove_bin_file(&dev->primary->kdev,  &dpf_attrs);
 #ifdef CONFIG_PM
index 3db4a681771320f1d42f8fb023c83d73e4426fb6..2933e2ffeaa4f53f372c0e1661f5f8bd23df146e 100644 (file)
@@ -46,8 +46,8 @@ TRACE_EVENT(i915_gem_object_bind,
 
            TP_fast_assign(
                           __entry->obj = obj;
-                          __entry->offset = obj->gtt_space->start;
-                          __entry->size = obj->gtt_space->size;
+                          __entry->offset = i915_gem_obj_ggtt_offset(obj);
+                          __entry->size = i915_gem_obj_ggtt_size(obj);
                           __entry->mappable = mappable;
                           ),
 
@@ -68,8 +68,8 @@ TRACE_EVENT(i915_gem_object_unbind,
 
            TP_fast_assign(
                           __entry->obj = obj;
-                          __entry->offset = obj->gtt_space->start;
-                          __entry->size = obj->gtt_space->size;
+                          __entry->offset = i915_gem_obj_ggtt_offset(obj);
+                          __entry->size = i915_gem_obj_ggtt_size(obj);
                           ),
 
            TP_printk("obj=%p, offset=%08x size=%x",
@@ -406,10 +406,12 @@ TRACE_EVENT(i915_flip_complete,
            TP_printk("plane=%d, obj=%p", __entry->plane, __entry->obj)
 );
 
-TRACE_EVENT(i915_reg_rw,
-       TP_PROTO(bool write, u32 reg, u64 val, int len),
+TRACE_EVENT_CONDITION(i915_reg_rw,
+       TP_PROTO(bool write, u32 reg, u64 val, int len, bool trace),
 
-       TP_ARGS(write, reg, val, len),
+       TP_ARGS(write, reg, val, len, trace),
+
+       TP_CONDITION(trace),
 
        TP_STRUCT__entry(
                __field(u64, val)
index 3acec8c4816606f1f2aa82bbe0ad3f5c105f4ad5..b5a3875f22c7cb5d18550b6be3b1c4b48b527274 100644 (file)
@@ -52,15 +52,14 @@ struct intel_crt {
        u32 adpa_reg;
 };
 
-static struct intel_crt *intel_attached_crt(struct drm_connector *connector)
+static struct intel_crt *intel_encoder_to_crt(struct intel_encoder *encoder)
 {
-       return container_of(intel_attached_encoder(connector),
-                           struct intel_crt, base);
+       return container_of(encoder, struct intel_crt, base);
 }
 
-static struct intel_crt *intel_encoder_to_crt(struct intel_encoder *encoder)
+static struct intel_crt *intel_attached_crt(struct drm_connector *connector)
 {
-       return container_of(encoder, struct intel_crt, base);
+       return intel_encoder_to_crt(intel_attached_encoder(connector));
 }
 
 static bool intel_crt_get_hw_state(struct intel_encoder *encoder,
@@ -238,17 +237,14 @@ static bool intel_crt_compute_config(struct intel_encoder *encoder,
        return true;
 }
 
-static void intel_crt_mode_set(struct drm_encoder *encoder,
-                              struct drm_display_mode *mode,
-                              struct drm_display_mode *adjusted_mode)
+static void intel_crt_mode_set(struct intel_encoder *encoder)
 {
 
-       struct drm_device *dev = encoder->dev;
-       struct drm_crtc *crtc = encoder->crtc;
-       struct intel_crt *crt =
-               intel_encoder_to_crt(to_intel_encoder(encoder));
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct drm_device *dev = encoder->base.dev;
+       struct intel_crt *crt = intel_encoder_to_crt(encoder);
+       struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
        struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_display_mode *adjusted_mode = &crtc->config.adjusted_mode;
        u32 adpa;
 
        if (HAS_PCH_SPLIT(dev))
@@ -265,14 +261,14 @@ static void intel_crt_mode_set(struct drm_encoder *encoder,
        if (HAS_PCH_LPT(dev))
                ; /* Those bits don't exist here */
        else if (HAS_PCH_CPT(dev))
-               adpa |= PORT_TRANS_SEL_CPT(intel_crtc->pipe);
-       else if (intel_crtc->pipe == 0)
+               adpa |= PORT_TRANS_SEL_CPT(crtc->pipe);
+       else if (crtc->pipe == 0)
                adpa |= ADPA_PIPE_A_SELECT;
        else
                adpa |= ADPA_PIPE_B_SELECT;
 
        if (!HAS_PCH_SPLIT(dev))
-               I915_WRITE(BCLRPAT(intel_crtc->pipe), 0);
+               I915_WRITE(BCLRPAT(crtc->pipe), 0);
 
        I915_WRITE(crt->adpa_reg, adpa);
 }
@@ -613,6 +609,10 @@ intel_crt_detect(struct drm_connector *connector, bool force)
        enum drm_connector_status status;
        struct intel_load_detect_pipe tmp;
 
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force=%d\n",
+                     connector->base.id, drm_get_connector_name(connector),
+                     force);
+
        if (I915_HAS_HOTPLUG(dev)) {
                /* We can not rely on the HPD pin always being correctly wired
                 * up, for example many KVM do not pass it through, and so
@@ -707,10 +707,6 @@ static void intel_crt_reset(struct drm_connector *connector)
  * Routines for controlling stuff on the analog port
  */
 
-static const struct drm_encoder_helper_funcs crt_encoder_funcs = {
-       .mode_set = intel_crt_mode_set,
-};
-
 static const struct drm_connector_funcs intel_crt_connector_funcs = {
        .reset = intel_crt_reset,
        .dpms = intel_crt_dpms,
@@ -800,6 +796,7 @@ void intel_crt_init(struct drm_device *dev)
                crt->adpa_reg = ADPA;
 
        crt->base.compute_config = intel_crt_compute_config;
+       crt->base.mode_set = intel_crt_mode_set;
        crt->base.disable = intel_disable_crt;
        crt->base.enable = intel_enable_crt;
        crt->base.get_config = intel_crt_get_config;
@@ -811,7 +808,6 @@ void intel_crt_init(struct drm_device *dev)
                crt->base.get_hw_state = intel_crt_get_hw_state;
        intel_connector->get_hw_state = intel_connector_get_hw_state;
 
-       drm_encoder_helper_add(&crt->base.base, &crt_encoder_funcs);
        drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs);
 
        drm_sysfs_connector_add(connector);
index b042ee5c40704a8beaa1e5b99f3d6a1b2082d722..b361c0862373ecea09e4a5f85690fcb6e43b72d5 100644 (file)
@@ -281,25 +281,22 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
        DRM_ERROR("FDI link training failed!\n");
 }
 
-static void intel_ddi_mode_set(struct drm_encoder *encoder,
-                              struct drm_display_mode *mode,
-                              struct drm_display_mode *adjusted_mode)
+static void intel_ddi_mode_set(struct intel_encoder *encoder)
 {
-       struct drm_crtc *crtc = encoder->crtc;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
-       int port = intel_ddi_get_encoder_port(intel_encoder);
-       int pipe = intel_crtc->pipe;
-       int type = intel_encoder->type;
+       struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
+       int port = intel_ddi_get_encoder_port(encoder);
+       int pipe = crtc->pipe;
+       int type = encoder->type;
+       struct drm_display_mode *adjusted_mode = &crtc->config.adjusted_mode;
 
        DRM_DEBUG_KMS("Preparing DDI mode on port %c, pipe %c\n",
                      port_name(port), pipe_name(pipe));
 
-       intel_crtc->eld_vld = false;
+       crtc->eld_vld = false;
        if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) {
-               struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+               struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
                struct intel_digital_port *intel_dig_port =
-                       enc_to_dig_port(encoder);
+                       enc_to_dig_port(&encoder->base);
 
                intel_dp->DP = intel_dig_port->saved_port_bits |
                               DDI_BUF_CTL_ENABLE | DDI_BUF_EMP_400MV_0DB_HSW;
@@ -307,17 +304,17 @@ static void intel_ddi_mode_set(struct drm_encoder *encoder,
 
                if (intel_dp->has_audio) {
                        DRM_DEBUG_DRIVER("DP audio on pipe %c on DDI\n",
-                                        pipe_name(intel_crtc->pipe));
+                                        pipe_name(crtc->pipe));
 
                        /* write eld */
                        DRM_DEBUG_DRIVER("DP audio: write eld information\n");
-                       intel_write_eld(encoder, adjusted_mode);
+                       intel_write_eld(&encoder->base, adjusted_mode);
                }
 
                intel_dp_init_link_config(intel_dp);
 
        } else if (type == INTEL_OUTPUT_HDMI) {
-               struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+               struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
 
                if (intel_hdmi->has_audio) {
                        /* Proper support for digital audio needs a new logic
@@ -325,14 +322,14 @@ static void intel_ddi_mode_set(struct drm_encoder *encoder,
                         * patch bombing.
                         */
                        DRM_DEBUG_DRIVER("HDMI audio on pipe %c on DDI\n",
-                                        pipe_name(intel_crtc->pipe));
+                                        pipe_name(crtc->pipe));
 
                        /* write eld */
                        DRM_DEBUG_DRIVER("HDMI audio: write eld information\n");
-                       intel_write_eld(encoder, adjusted_mode);
+                       intel_write_eld(&encoder->base, adjusted_mode);
                }
 
-               intel_hdmi->set_infoframes(encoder, adjusted_mode);
+               intel_hdmi->set_infoframes(&encoder->base, adjusted_mode);
        }
 }
 
@@ -1118,6 +1115,7 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder)
                        intel_dp_stop_link_train(intel_dp);
 
                ironlake_edp_backlight_on(intel_dp);
+               intel_edp_psr_enable(intel_dp);
        }
 
        if (intel_crtc->eld_vld && type != INTEL_OUTPUT_EDP) {
@@ -1148,6 +1146,7 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder)
        if (type == INTEL_OUTPUT_EDP) {
                struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 
+               intel_edp_psr_disable(intel_dp);
                ironlake_edp_backlight_off(intel_dp);
        }
 }
@@ -1309,10 +1308,6 @@ static const struct drm_encoder_funcs intel_ddi_funcs = {
        .destroy = intel_ddi_destroy,
 };
 
-static const struct drm_encoder_helper_funcs intel_ddi_helper_funcs = {
-       .mode_set = intel_ddi_mode_set,
-};
-
 void intel_ddi_init(struct drm_device *dev, enum port port)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1337,9 +1332,9 @@ void intel_ddi_init(struct drm_device *dev, enum port port)
 
        drm_encoder_init(dev, encoder, &intel_ddi_funcs,
                         DRM_MODE_ENCODER_TMDS);
-       drm_encoder_helper_add(encoder, &intel_ddi_helper_funcs);
 
        intel_encoder->compute_config = intel_ddi_compute_config;
+       intel_encoder->mode_set = intel_ddi_mode_set;
        intel_encoder->enable = intel_enable_ddi;
        intel_encoder->pre_enable = intel_ddi_pre_enable;
        intel_encoder->disable = intel_disable_ddi;
index 5fb305840db89ecd80b5cd42b69ff9c35dd9432b..e1e50dfb08da03f6aa4264d39a2481fe41191e01 100644 (file)
@@ -45,6 +45,11 @@ bool intel_pipe_has_type(struct drm_crtc *crtc, int type);
 static void intel_increase_pllclock(struct drm_crtc *crtc);
 static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on);
 
+static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
+                               struct intel_crtc_config *pipe_config);
+static void ironlake_crtc_clock_get(struct intel_crtc *crtc,
+                                   struct intel_crtc_config *pipe_config);
+
 typedef struct {
        int     min, max;
 } intel_range_t;
@@ -84,7 +89,7 @@ intel_fdi_link_freq(struct drm_device *dev)
                return 27;
 }
 
-static const intel_limit_t intel_limits_i8xx_dvo = {
+static const intel_limit_t intel_limits_i8xx_dac = {
        .dot = { .min = 25000, .max = 350000 },
        .vco = { .min = 930000, .max = 1400000 },
        .n = { .min = 3, .max = 16 },
@@ -97,6 +102,19 @@ static const intel_limit_t intel_limits_i8xx_dvo = {
                .p2_slow = 4, .p2_fast = 2 },
 };
 
+static const intel_limit_t intel_limits_i8xx_dvo = {
+       .dot = { .min = 25000, .max = 350000 },
+       .vco = { .min = 930000, .max = 1400000 },
+       .n = { .min = 3, .max = 16 },
+       .m = { .min = 96, .max = 140 },
+       .m1 = { .min = 18, .max = 26 },
+       .m2 = { .min = 6, .max = 16 },
+       .p = { .min = 4, .max = 128 },
+       .p1 = { .min = 2, .max = 33 },
+       .p2 = { .dot_limit = 165000,
+               .p2_slow = 4, .p2_fast = 4 },
+};
+
 static const intel_limit_t intel_limits_i8xx_lvds = {
        .dot = { .min = 25000, .max = 350000 },
        .vco = { .min = 930000, .max = 1400000 },
@@ -405,8 +423,10 @@ static const intel_limit_t *intel_limit(struct drm_crtc *crtc, int refclk)
        } else {
                if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
                        limit = &intel_limits_i8xx_lvds;
-               else
+               else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DVO))
                        limit = &intel_limits_i8xx_dvo;
+               else
+                       limit = &intel_limits_i8xx_dac;
        }
        return limit;
 }
@@ -892,8 +912,8 @@ static const char *state_string(bool enabled)
 }
 
 /* Only for pre-ILK configs */
-static void assert_pll(struct drm_i915_private *dev_priv,
-                      enum pipe pipe, bool state)
+void assert_pll(struct drm_i915_private *dev_priv,
+               enum pipe pipe, bool state)
 {
        int reg;
        u32 val;
@@ -906,10 +926,8 @@ static void assert_pll(struct drm_i915_private *dev_priv,
             "PLL state assertion failure (expected %s, current %s)\n",
             state_string(state), state_string(cur_state));
 }
-#define assert_pll_enabled(d, p) assert_pll(d, p, true)
-#define assert_pll_disabled(d, p) assert_pll(d, p, false)
 
-static struct intel_shared_dpll *
+struct intel_shared_dpll *
 intel_crtc_to_shared_dpll(struct intel_crtc *crtc)
 {
        struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
@@ -921,9 +939,9 @@ intel_crtc_to_shared_dpll(struct intel_crtc *crtc)
 }
 
 /* For ILK+ */
-static void assert_shared_dpll(struct drm_i915_private *dev_priv,
-                              struct intel_shared_dpll *pll,
-                              bool state)
+void assert_shared_dpll(struct drm_i915_private *dev_priv,
+                       struct intel_shared_dpll *pll,
+                       bool state)
 {
        bool cur_state;
        struct intel_dpll_hw_state hw_state;
@@ -942,8 +960,6 @@ static void assert_shared_dpll(struct drm_i915_private *dev_priv,
             "%s assertion failure (expected %s, current %s)\n",
             pll->name, state_string(state), state_string(cur_state));
 }
-#define assert_shared_dpll_enabled(d, p) assert_shared_dpll(d, p, true)
-#define assert_shared_dpll_disabled(d, p) assert_shared_dpll(d, p, false)
 
 static void assert_fdi_tx(struct drm_i915_private *dev_priv,
                          enum pipe pipe, bool state)
@@ -1007,15 +1023,19 @@ static void assert_fdi_tx_pll_enabled(struct drm_i915_private *dev_priv,
        WARN(!(val & FDI_TX_PLL_ENABLE), "FDI TX PLL assertion failure, should be active but is disabled\n");
 }
 
-static void assert_fdi_rx_pll_enabled(struct drm_i915_private *dev_priv,
-                                     enum pipe pipe)
+void assert_fdi_rx_pll(struct drm_i915_private *dev_priv,
+                      enum pipe pipe, bool state)
 {
        int reg;
        u32 val;
+       bool cur_state;
 
        reg = FDI_RX_CTL(pipe);
        val = I915_READ(reg);
-       WARN(!(val & FDI_RX_PLL_ENABLE), "FDI RX PLL assertion failure, should be active but is disabled\n");
+       cur_state = !!(val & FDI_RX_PLL_ENABLE);
+       WARN(cur_state != state,
+            "FDI RX PLL assertion failure (expected %s, current %s)\n",
+            state_string(state), state_string(cur_state));
 }
 
 static void assert_panel_unlocked(struct drm_i915_private *dev_priv,
@@ -1111,7 +1131,7 @@ static void assert_planes_disabled(struct drm_i915_private *dev_priv,
        }
 
        /* Need to check both planes against the pipe */
-       for (i = 0; i < INTEL_INFO(dev)->num_pipes; i++) {
+       for_each_pipe(i) {
                reg = DSPCNTR(i);
                val = I915_READ(reg);
                cur_pipe = (val & DISPPLANE_SEL_PIPE_MASK) >>
@@ -1301,51 +1321,92 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv,
        assert_pch_hdmi_disabled(dev_priv, pipe, PCH_HDMID);
 }
 
-/**
- * intel_enable_pll - enable a PLL
- * @dev_priv: i915 private structure
- * @pipe: pipe PLL to enable
- *
- * Enable @pipe's PLL so we can start pumping pixels from a plane.  Check to
- * make sure the PLL reg is writable first though, since the panel write
- * protect mechanism may be enabled.
- *
- * Note!  This is for pre-ILK only.
- *
- * Unfortunately needed by dvo_ns2501 since the dvo depends on it running.
- */
-static void intel_enable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
+static void vlv_enable_pll(struct intel_crtc *crtc)
 {
-       int reg;
-       u32 val;
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int reg = DPLL(crtc->pipe);
+       u32 dpll = crtc->config.dpll_hw_state.dpll;
 
-       assert_pipe_disabled(dev_priv, pipe);
+       assert_pipe_disabled(dev_priv, crtc->pipe);
 
        /* No really, not for ILK+ */
-       BUG_ON(!IS_VALLEYVIEW(dev_priv->dev) && dev_priv->info->gen >= 5);
+       BUG_ON(!IS_VALLEYVIEW(dev_priv->dev));
 
        /* PLL is protected by panel, make sure we can write it */
        if (IS_MOBILE(dev_priv->dev) && !IS_I830(dev_priv->dev))
-               assert_panel_unlocked(dev_priv, pipe);
+               assert_panel_unlocked(dev_priv, crtc->pipe);
 
-       reg = DPLL(pipe);
-       val = I915_READ(reg);
-       val |= DPLL_VCO_ENABLE;
+       I915_WRITE(reg, dpll);
+       POSTING_READ(reg);
+       udelay(150);
+
+       if (wait_for(((I915_READ(reg) & DPLL_LOCK_VLV) == DPLL_LOCK_VLV), 1))
+               DRM_ERROR("DPLL %d failed to lock\n", crtc->pipe);
+
+       I915_WRITE(DPLL_MD(crtc->pipe), crtc->config.dpll_hw_state.dpll_md);
+       POSTING_READ(DPLL_MD(crtc->pipe));
 
        /* We do this three times for luck */
-       I915_WRITE(reg, val);
+       I915_WRITE(reg, dpll);
        POSTING_READ(reg);
        udelay(150); /* wait for warmup */
-       I915_WRITE(reg, val);
+       I915_WRITE(reg, dpll);
        POSTING_READ(reg);
        udelay(150); /* wait for warmup */
-       I915_WRITE(reg, val);
+       I915_WRITE(reg, dpll);
+       POSTING_READ(reg);
+       udelay(150); /* wait for warmup */
+}
+
+static void i9xx_enable_pll(struct intel_crtc *crtc)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int reg = DPLL(crtc->pipe);
+       u32 dpll = crtc->config.dpll_hw_state.dpll;
+
+       assert_pipe_disabled(dev_priv, crtc->pipe);
+
+       /* No really, not for ILK+ */
+       BUG_ON(dev_priv->info->gen >= 5);
+
+       /* PLL is protected by panel, make sure we can write it */
+       if (IS_MOBILE(dev) && !IS_I830(dev))
+               assert_panel_unlocked(dev_priv, crtc->pipe);
+
+       I915_WRITE(reg, dpll);
+
+       /* Wait for the clocks to stabilize. */
+       POSTING_READ(reg);
+       udelay(150);
+
+       if (INTEL_INFO(dev)->gen >= 4) {
+               I915_WRITE(DPLL_MD(crtc->pipe),
+                          crtc->config.dpll_hw_state.dpll_md);
+       } else {
+               /* The pixel multiplier can only be updated once the
+                * DPLL is enabled and the clocks are stable.
+                *
+                * So write it again.
+                */
+               I915_WRITE(reg, dpll);
+       }
+
+       /* We do this three times for luck */
+       I915_WRITE(reg, dpll);
+       POSTING_READ(reg);
+       udelay(150); /* wait for warmup */
+       I915_WRITE(reg, dpll);
+       POSTING_READ(reg);
+       udelay(150); /* wait for warmup */
+       I915_WRITE(reg, dpll);
        POSTING_READ(reg);
        udelay(150); /* wait for warmup */
 }
 
 /**
- * intel_disable_pll - disable a PLL
+ * i9xx_disable_pll - disable a PLL
  * @dev_priv: i915 private structure
  * @pipe: pipe PLL to disable
  *
@@ -1353,11 +1414,8 @@ static void intel_enable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
  *
  * Note!  This is for pre-ILK only.
  */
-static void intel_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
+static void i9xx_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
 {
-       int reg;
-       u32 val;
-
        /* Don't disable pipe A or pipe A PLLs if needed */
        if (pipe == PIPE_A && (dev_priv->quirks & QUIRK_PIPEA_FORCE))
                return;
@@ -1365,11 +1423,8 @@ static void intel_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
        /* Make sure the pipe isn't still relying on us */
        assert_pipe_disabled(dev_priv, pipe);
 
-       reg = DPLL(pipe);
-       val = I915_READ(reg);
-       val &= ~DPLL_VCO_ENABLE;
-       I915_WRITE(reg, val);
-       POSTING_READ(reg);
+       I915_WRITE(DPLL(pipe), 0);
+       POSTING_READ(DPLL(pipe));
 }
 
 void vlv_wait_port_ready(struct drm_i915_private *dev_priv, int port)
@@ -1942,16 +1997,17 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
                intel_crtc->dspaddr_offset = linear_offset;
        }
 
-       DRM_DEBUG_KMS("Writing base %08X %08lX %d %d %d\n",
-                     obj->gtt_offset, linear_offset, x, y, fb->pitches[0]);
+       DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n",
+                     i915_gem_obj_ggtt_offset(obj), linear_offset, x, y,
+                     fb->pitches[0]);
        I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]);
        if (INTEL_INFO(dev)->gen >= 4) {
                I915_MODIFY_DISPBASE(DSPSURF(plane),
-                                    obj->gtt_offset + intel_crtc->dspaddr_offset);
+                                    i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
                I915_WRITE(DSPTILEOFF(plane), (y << 16) | x);
                I915_WRITE(DSPLINOFF(plane), linear_offset);
        } else
-               I915_WRITE(DSPADDR(plane), obj->gtt_offset + linear_offset);
+               I915_WRITE(DSPADDR(plane), i915_gem_obj_ggtt_offset(obj) + linear_offset);
        POSTING_READ(reg);
 
        return 0;
@@ -2031,11 +2087,12 @@ static int ironlake_update_plane(struct drm_crtc *crtc,
                                               fb->pitches[0]);
        linear_offset -= intel_crtc->dspaddr_offset;
 
-       DRM_DEBUG_KMS("Writing base %08X %08lX %d %d %d\n",
-                     obj->gtt_offset, linear_offset, x, y, fb->pitches[0]);
+       DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n",
+                     i915_gem_obj_ggtt_offset(obj), linear_offset, x, y,
+                     fb->pitches[0]);
        I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]);
        I915_MODIFY_DISPBASE(DSPSURF(plane),
-                            obj->gtt_offset + intel_crtc->dspaddr_offset);
+                            i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
        if (IS_HASWELL(dev)) {
                I915_WRITE(DSPOFFSET(plane), (y << 16) | x);
        } else {
@@ -2183,6 +2240,20 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
                return ret;
        }
 
+       /* Update pipe size and adjust fitter if needed */
+       if (i915_fastboot) {
+               I915_WRITE(PIPESRC(intel_crtc->pipe),
+                          ((crtc->mode.hdisplay - 1) << 16) |
+                          (crtc->mode.vdisplay - 1));
+               if (!intel_crtc->config.pch_pfit.size &&
+                   (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) ||
+                    intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))) {
+                       I915_WRITE(PF_CTL(intel_crtc->pipe), 0);
+                       I915_WRITE(PF_WIN_POS(intel_crtc->pipe), 0);
+                       I915_WRITE(PF_WIN_SZ(intel_crtc->pipe), 0);
+               }
+       }
+
        ret = dev_priv->display.update_plane(crtc, fb, x, y);
        if (ret) {
                intel_unpin_fb_obj(to_intel_framebuffer(fb)->obj);
@@ -2203,6 +2274,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
        }
 
        intel_update_fbc(dev);
+       intel_edp_psr_update(dev);
        mutex_unlock(&dev->struct_mutex);
 
        intel_crtc_update_sarea_pos(crtc, x, y);
@@ -2927,15 +2999,8 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
        /* For PCH output, training FDI link */
        dev_priv->display.fdi_link_train(crtc);
 
-       /* XXX: pch pll's can be enabled any time before we enable the PCH
-        * transcoder, and we actually should do this to not upset any PCH
-        * transcoder that already use the clock when we share it.
-        *
-        * Note that enable_shared_dpll tries to do the right thing, but
-        * get_shared_dpll unconditionally resets the pll - we need that to have
-        * the right LVDS enable sequence. */
-       ironlake_enable_shared_dpll(intel_crtc);
-
+       /* We need to program the right clock selection before writing the pixel
+        * mutliplier into the DPLL. */
        if (HAS_PCH_CPT(dev)) {
                u32 sel;
 
@@ -2949,6 +3014,15 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
                I915_WRITE(PCH_DPLL_SEL, temp);
        }
 
+       /* XXX: pch pll's can be enabled any time before we enable the PCH
+        * transcoder, and we actually should do this to not upset any PCH
+        * transcoder that already use the clock when we share it.
+        *
+        * Note that enable_shared_dpll tries to do the right thing, but
+        * get_shared_dpll unconditionally resets the pll - we need that to have
+        * the right LVDS enable sequence. */
+       ironlake_enable_shared_dpll(intel_crtc);
+
        /* set transcoder timing, panel must allow it */
        assert_panel_unlocked(dev_priv, pipe);
        ironlake_pch_transcoder_set_timings(intel_crtc, pipe);
@@ -3031,7 +3105,7 @@ static void intel_put_shared_dpll(struct intel_crtc *crtc)
        crtc->config.shared_dpll = DPLL_ID_PRIVATE;
 }
 
-static struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc, u32 dpll, u32 fp)
+static struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc)
 {
        struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
        struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc);
@@ -3045,7 +3119,7 @@ static struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc,
 
        if (HAS_PCH_IBX(dev_priv->dev)) {
                /* Ironlake PCH has a fixed PLL->PCH pipe mapping. */
-               i = crtc->pipe;
+               i = (enum intel_dpll_id) crtc->pipe;
                pll = &dev_priv->shared_dplls[i];
 
                DRM_DEBUG_KMS("CRTC:%d using pre-allocated %s\n",
@@ -3061,8 +3135,8 @@ static struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc,
                if (pll->refcount == 0)
                        continue;
 
-               if (dpll == (I915_READ(PCH_DPLL(pll->id)) & 0x7fffffff) &&
-                   fp == I915_READ(PCH_FP0(pll->id))) {
+               if (memcmp(&crtc->config.dpll_hw_state, &pll->hw_state,
+                          sizeof(pll->hw_state)) == 0) {
                        DRM_DEBUG_KMS("CRTC:%d sharing existing %s (refcount %d, ative %d)\n",
                                      crtc->base.base.id,
                                      pll->name, pll->refcount, pll->active);
@@ -3096,13 +3170,7 @@ found:
                WARN_ON(pll->on);
                assert_shared_dpll_disabled(dev_priv, pll);
 
-               /* Wait for the clocks to stabilize before rewriting the regs */
-               I915_WRITE(PCH_DPLL(pll->id), dpll & ~DPLL_VCO_ENABLE);
-               POSTING_READ(PCH_DPLL(pll->id));
-               udelay(150);
-
-               I915_WRITE(PCH_FP0(pll->id), fp);
-               I915_WRITE(PCH_DPLL(pll->id), dpll & ~DPLL_VCO_ENABLE);
+               pll->mode_set(dev_priv, pll);
        }
        pll->refcount++;
 
@@ -3174,7 +3242,6 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
        struct intel_encoder *encoder;
        int pipe = intel_crtc->pipe;
        int plane = intel_crtc->plane;
-       u32 temp;
 
        WARN_ON(!crtc->enabled);
 
@@ -3188,12 +3255,9 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
 
        intel_update_watermarks(dev);
 
-       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
-               temp = I915_READ(PCH_LVDS);
-               if ((temp & LVDS_PORT_EN) == 0)
-                       I915_WRITE(PCH_LVDS, temp | LVDS_PORT_EN);
-       }
-
+       for_each_encoder_on_crtc(dev, crtc, encoder)
+               if (encoder->pre_enable)
+                       encoder->pre_enable(encoder);
 
        if (intel_crtc->config.has_pch_encoder) {
                /* Note: FDI PLL enabling _must_ be done before we enable the
@@ -3205,10 +3269,6 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
                assert_fdi_rx_disabled(dev_priv, pipe);
        }
 
-       for_each_encoder_on_crtc(dev, crtc, encoder)
-               if (encoder->pre_enable)
-                       encoder->pre_enable(encoder);
-
        ironlake_pfit_enable(intel_crtc);
 
        /*
@@ -3389,7 +3449,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
        intel_crtc_wait_for_pending_flips(crtc);
        drm_vblank_off(dev, pipe);
 
-       if (dev_priv->cfb_plane == plane)
+       if (dev_priv->fbc.plane == plane)
                intel_disable_fbc(dev);
 
        intel_crtc_update_cursor(crtc, false);
@@ -3462,7 +3522,7 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
        drm_vblank_off(dev, pipe);
 
        /* FBC must be disabled before disabling the plane on HSW. */
-       if (dev_priv->cfb_plane == plane)
+       if (dev_priv->fbc.plane == plane)
                intel_disable_fbc(dev);
 
        hsw_disable_ips(intel_crtc);
@@ -3599,7 +3659,7 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
                if (encoder->pre_pll_enable)
                        encoder->pre_pll_enable(encoder);
 
-       intel_enable_pll(dev_priv, pipe);
+       vlv_enable_pll(intel_crtc);
 
        for_each_encoder_on_crtc(dev, crtc, encoder)
                if (encoder->pre_enable)
@@ -3640,12 +3700,12 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
        intel_crtc->active = true;
        intel_update_watermarks(dev);
 
-       intel_enable_pll(dev_priv, pipe);
-
        for_each_encoder_on_crtc(dev, crtc, encoder)
                if (encoder->pre_enable)
                        encoder->pre_enable(encoder);
 
+       i9xx_enable_pll(intel_crtc);
+
        i9xx_pfit_enable(intel_crtc);
 
        intel_crtc_load_lut(crtc);
@@ -3701,7 +3761,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
        intel_crtc_wait_for_pending_flips(crtc);
        drm_vblank_off(dev, pipe);
 
-       if (dev_priv->cfb_plane == plane)
+       if (dev_priv->fbc.plane == plane)
                intel_disable_fbc(dev);
 
        intel_crtc_dpms_overlay(intel_crtc, false);
@@ -3717,7 +3777,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
                if (encoder->post_disable)
                        encoder->post_disable(encoder);
 
-       intel_disable_pll(dev_priv, pipe);
+       i9xx_disable_pll(dev_priv, pipe);
 
        intel_crtc->active = false;
        intel_update_fbc(dev);
@@ -4048,12 +4108,6 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc,
                        return -EINVAL;
        }
 
-       /* All interlaced capable intel hw wants timings in frames. Note though
-        * that intel_lvds_mode_fixup does some funny tricks with the crtc
-        * timings, so we need to be careful not to clobber these.*/
-       if (!pipe_config->timings_set)
-               drm_mode_set_crtcinfo(adjusted_mode, 0);
-
        /* Cantiga+ cannot handle modes with a hsync front porch of 0.
         * WaPruneModeWithIncorrectHsyncOffset:ctg,elk,ilk,snb,ivb,vlv,hsw.
         */
@@ -4103,6 +4157,30 @@ static int i9xx_misc_get_display_clock_speed(struct drm_device *dev)
        return 200000;
 }
 
+static int pnv_get_display_clock_speed(struct drm_device *dev)
+{
+       u16 gcfgc = 0;
+
+       pci_read_config_word(dev->pdev, GCFGC, &gcfgc);
+
+       switch (gcfgc & GC_DISPLAY_CLOCK_MASK) {
+       case GC_DISPLAY_CLOCK_267_MHZ_PNV:
+               return 267000;
+       case GC_DISPLAY_CLOCK_333_MHZ_PNV:
+               return 333000;
+       case GC_DISPLAY_CLOCK_444_MHZ_PNV:
+               return 444000;
+       case GC_DISPLAY_CLOCK_200_MHZ_PNV:
+               return 200000;
+       default:
+               DRM_ERROR("Unknown pnv display core clock 0x%04x\n", gcfgc);
+       case GC_DISPLAY_CLOCK_133_MHZ_PNV:
+               return 133000;
+       case GC_DISPLAY_CLOCK_167_MHZ_PNV:
+               return 167000;
+       }
+}
+
 static int i915gm_get_display_clock_speed(struct drm_device *dev)
 {
        u16 gcfgc = 0;
@@ -4266,14 +4344,17 @@ static void i9xx_update_pll_dividers(struct intel_crtc *crtc,
        }
 
        I915_WRITE(FP0(pipe), fp);
+       crtc->config.dpll_hw_state.fp0 = fp;
 
        crtc->lowfreq_avail = false;
        if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS) &&
            reduced_clock && i915_powersave) {
                I915_WRITE(FP1(pipe), fp2);
+               crtc->config.dpll_hw_state.fp1 = fp2;
                crtc->lowfreq_avail = true;
        } else {
                I915_WRITE(FP1(pipe), fp);
+               crtc->config.dpll_hw_state.fp1 = fp;
        }
 }
 
@@ -4351,7 +4432,6 @@ static void vlv_update_pll(struct intel_crtc *crtc)
 {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_encoder *encoder;
        int pipe = crtc->pipe;
        u32 dpll, mdiv;
        u32 bestn, bestm1, bestm2, bestp1, bestp2;
@@ -4407,7 +4487,7 @@ static void vlv_update_pll(struct intel_crtc *crtc)
            intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_ANALOG) ||
            intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI))
                vlv_dpio_write(dev_priv, DPIO_LPF_COEFF(pipe),
-                                0x005f0021);
+                                0x009f0003);
        else
                vlv_dpio_write(dev_priv, DPIO_LPF_COEFF(pipe),
                                 0x00d0000f);
@@ -4440,10 +4520,6 @@ static void vlv_update_pll(struct intel_crtc *crtc)
 
        vlv_dpio_write(dev_priv, DPIO_PLL_CML(pipe), 0x87871000);
 
-       for_each_encoder_on_crtc(dev, &crtc->base, encoder)
-               if (encoder->pre_pll_enable)
-                       encoder->pre_pll_enable(encoder);
-
        /* Enable DPIO clock input */
        dpll = DPLL_EXT_BUFFER_ENABLE_VLV | DPLL_REFA_CLK_ENABLE_VLV |
                DPLL_VGA_MODE_DIS | DPLL_INTEGRATED_CLOCK_VLV;
@@ -4451,17 +4527,11 @@ static void vlv_update_pll(struct intel_crtc *crtc)
                dpll |= DPLL_INTEGRATED_CRI_CLK_VLV;
 
        dpll |= DPLL_VCO_ENABLE;
-       I915_WRITE(DPLL(pipe), dpll);
-       POSTING_READ(DPLL(pipe));
-       udelay(150);
-
-       if (wait_for(((I915_READ(DPLL(pipe)) & DPLL_LOCK_VLV) == DPLL_LOCK_VLV), 1))
-               DRM_ERROR("DPLL %d failed to lock\n", pipe);
+       crtc->config.dpll_hw_state.dpll = dpll;
 
        dpll_md = (crtc->config.pixel_multiplier - 1)
                << DPLL_MD_UDI_MULTIPLIER_SHIFT;
-       I915_WRITE(DPLL_MD(pipe), dpll_md);
-       POSTING_READ(DPLL_MD(pipe));
+       crtc->config.dpll_hw_state.dpll_md = dpll_md;
 
        if (crtc->config.has_dp_encoder)
                intel_dp_set_m_n(crtc);
@@ -4475,8 +4545,6 @@ static void i9xx_update_pll(struct intel_crtc *crtc,
 {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_encoder *encoder;
-       int pipe = crtc->pipe;
        u32 dpll;
        bool is_sdvo;
        struct dpll *clock = &crtc->config.dpll;
@@ -4499,10 +4567,10 @@ static void i9xx_update_pll(struct intel_crtc *crtc,
        }
 
        if (is_sdvo)
-               dpll |= DPLL_DVO_HIGH_SPEED;
+               dpll |= DPLL_SDVO_HIGH_SPEED;
 
        if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT))
-               dpll |= DPLL_DVO_HIGH_SPEED;
+               dpll |= DPLL_SDVO_HIGH_SPEED;
 
        /* compute bitmask from p1 value */
        if (IS_PINEVIEW(dev))
@@ -4538,35 +4606,16 @@ static void i9xx_update_pll(struct intel_crtc *crtc,
                dpll |= PLL_REF_INPUT_DREFCLK;
 
        dpll |= DPLL_VCO_ENABLE;
-       I915_WRITE(DPLL(pipe), dpll & ~DPLL_VCO_ENABLE);
-       POSTING_READ(DPLL(pipe));
-       udelay(150);
-
-       for_each_encoder_on_crtc(dev, &crtc->base, encoder)
-               if (encoder->pre_pll_enable)
-                       encoder->pre_pll_enable(encoder);
-
-       if (crtc->config.has_dp_encoder)
-               intel_dp_set_m_n(crtc);
-
-       I915_WRITE(DPLL(pipe), dpll);
-
-       /* Wait for the clocks to stabilize. */
-       POSTING_READ(DPLL(pipe));
-       udelay(150);
+       crtc->config.dpll_hw_state.dpll = dpll;
 
        if (INTEL_INFO(dev)->gen >= 4) {
                u32 dpll_md = (crtc->config.pixel_multiplier - 1)
                        << DPLL_MD_UDI_MULTIPLIER_SHIFT;
-               I915_WRITE(DPLL_MD(pipe), dpll_md);
-       } else {
-               /* The pixel multiplier can only be updated once the
-                * DPLL is enabled and the clocks are stable.
-                *
-                * So write it again.
-                */
-               I915_WRITE(DPLL(pipe), dpll);
+               crtc->config.dpll_hw_state.dpll_md = dpll_md;
        }
+
+       if (crtc->config.has_dp_encoder)
+               intel_dp_set_m_n(crtc);
 }
 
 static void i8xx_update_pll(struct intel_crtc *crtc,
@@ -4575,8 +4624,6 @@ static void i8xx_update_pll(struct intel_crtc *crtc,
 {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_encoder *encoder;
-       int pipe = crtc->pipe;
        u32 dpll;
        struct dpll *clock = &crtc->config.dpll;
 
@@ -4595,6 +4642,9 @@ static void i8xx_update_pll(struct intel_crtc *crtc,
                        dpll |= PLL_P2_DIVIDE_BY_4;
        }
 
+       if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DVO))
+               dpll |= DPLL_DVO_2X_MODE;
+
        if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS) &&
                 intel_panel_use_ssc(dev_priv) && num_connectors < 2)
                dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
@@ -4602,26 +4652,7 @@ static void i8xx_update_pll(struct intel_crtc *crtc,
                dpll |= PLL_REF_INPUT_DREFCLK;
 
        dpll |= DPLL_VCO_ENABLE;
-       I915_WRITE(DPLL(pipe), dpll & ~DPLL_VCO_ENABLE);
-       POSTING_READ(DPLL(pipe));
-       udelay(150);
-
-       for_each_encoder_on_crtc(dev, &crtc->base, encoder)
-               if (encoder->pre_pll_enable)
-                       encoder->pre_pll_enable(encoder);
-
-       I915_WRITE(DPLL(pipe), dpll);
-
-       /* Wait for the clocks to stabilize. */
-       POSTING_READ(DPLL(pipe));
-       udelay(150);
-
-       /* The pixel multiplier can only be updated once the
-        * DPLL is enabled and the clocks are stable.
-        *
-        * So write it again.
-        */
-       I915_WRITE(DPLL(pipe), dpll);
+       crtc->config.dpll_hw_state.dpll = dpll;
 }
 
 static void intel_set_pipe_timings(struct intel_crtc *intel_crtc)
@@ -4727,6 +4758,27 @@ static void intel_get_pipe_timings(struct intel_crtc *crtc,
        pipe_config->requested_mode.hdisplay = ((tmp >> 16) & 0xffff) + 1;
 }
 
+static void intel_crtc_mode_from_pipe_config(struct intel_crtc *intel_crtc,
+                                            struct intel_crtc_config *pipe_config)
+{
+       struct drm_crtc *crtc = &intel_crtc->base;
+
+       crtc->mode.hdisplay = pipe_config->adjusted_mode.crtc_hdisplay;
+       crtc->mode.htotal = pipe_config->adjusted_mode.crtc_htotal;
+       crtc->mode.hsync_start = pipe_config->adjusted_mode.crtc_hsync_start;
+       crtc->mode.hsync_end = pipe_config->adjusted_mode.crtc_hsync_end;
+
+       crtc->mode.vdisplay = pipe_config->adjusted_mode.crtc_vdisplay;
+       crtc->mode.vtotal = pipe_config->adjusted_mode.crtc_vtotal;
+       crtc->mode.vsync_start = pipe_config->adjusted_mode.crtc_vsync_start;
+       crtc->mode.vsync_end = pipe_config->adjusted_mode.crtc_vsync_end;
+
+       crtc->mode.flags = pipe_config->adjusted_mode.flags;
+
+       crtc->mode.clock = pipe_config->adjusted_mode.clock;
+       crtc->mode.flags |= pipe_config->adjusted_mode.flags;
+}
+
 static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc)
 {
        struct drm_device *dev = intel_crtc->base.dev;
@@ -4939,7 +4991,7 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t tmp;
 
-       pipe_config->cpu_transcoder = crtc->pipe;
+       pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe;
        pipe_config->shared_dpll = DPLL_ID_PRIVATE;
 
        tmp = I915_READ(PIPECONF(crtc->pipe));
@@ -4955,6 +5007,7 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
                pipe_config->pixel_multiplier =
                        ((tmp & DPLL_MD_UDI_MULTIPLIER_MASK)
                         >> DPLL_MD_UDI_MULTIPLIER_SHIFT) + 1;
+               pipe_config->dpll_hw_state.dpll_md = tmp;
        } else if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) {
                tmp = I915_READ(DPLL(crtc->pipe));
                pipe_config->pixel_multiplier =
@@ -4966,6 +5019,16 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
                 * function. */
                pipe_config->pixel_multiplier = 1;
        }
+       pipe_config->dpll_hw_state.dpll = I915_READ(DPLL(crtc->pipe));
+       if (!IS_VALLEYVIEW(dev)) {
+               pipe_config->dpll_hw_state.fp0 = I915_READ(FP0(crtc->pipe));
+               pipe_config->dpll_hw_state.fp1 = I915_READ(FP1(crtc->pipe));
+       } else {
+               /* Mask out read-only status bits. */
+               pipe_config->dpll_hw_state.dpll &= ~(DPLL_LOCK_VLV |
+                                                    DPLL_PORTC_READY_MASK |
+                                                    DPLL_PORTB_READY_MASK);
+       }
 
        return true;
 }
@@ -5119,74 +5182,37 @@ static void ironlake_init_pch_refclk(struct drm_device *dev)
        BUG_ON(val != final);
 }
 
-/* Sequence to enable CLKOUT_DP for FDI usage and configure PCH FDI I/O. */
-static void lpt_init_pch_refclk(struct drm_device *dev)
+static void lpt_reset_fdi_mphy(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_mode_config *mode_config = &dev->mode_config;
-       struct intel_encoder *encoder;
-       bool has_vga = false;
-       bool is_sdv = false;
-       u32 tmp;
-
-       list_for_each_entry(encoder, &mode_config->encoder_list, base.head) {
-               switch (encoder->type) {
-               case INTEL_OUTPUT_ANALOG:
-                       has_vga = true;
-                       break;
-               }
-       }
-
-       if (!has_vga)
-               return;
+       uint32_t tmp;
 
-       mutex_lock(&dev_priv->dpio_lock);
+       tmp = I915_READ(SOUTH_CHICKEN2);
+       tmp |= FDI_MPHY_IOSFSB_RESET_CTL;
+       I915_WRITE(SOUTH_CHICKEN2, tmp);
 
-       /* XXX: Rip out SDV support once Haswell ships for real. */
-       if (IS_HASWELL(dev) && (dev->pci_device & 0xFF00) == 0x0C00)
-               is_sdv = true;
+       if (wait_for_atomic_us(I915_READ(SOUTH_CHICKEN2) &
+                              FDI_MPHY_IOSFSB_RESET_STATUS, 100))
+               DRM_ERROR("FDI mPHY reset assert timeout\n");
 
-       tmp = intel_sbi_read(dev_priv, SBI_SSCCTL, SBI_ICLK);
-       tmp &= ~SBI_SSCCTL_DISABLE;
-       tmp |= SBI_SSCCTL_PATHALT;
-       intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);
-
-       udelay(24);
-
-       tmp = intel_sbi_read(dev_priv, SBI_SSCCTL, SBI_ICLK);
-       tmp &= ~SBI_SSCCTL_PATHALT;
-       intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);
+       tmp = I915_READ(SOUTH_CHICKEN2);
+       tmp &= ~FDI_MPHY_IOSFSB_RESET_CTL;
+       I915_WRITE(SOUTH_CHICKEN2, tmp);
 
-       if (!is_sdv) {
-               tmp = I915_READ(SOUTH_CHICKEN2);
-               tmp |= FDI_MPHY_IOSFSB_RESET_CTL;
-               I915_WRITE(SOUTH_CHICKEN2, tmp);
-
-               if (wait_for_atomic_us(I915_READ(SOUTH_CHICKEN2) &
-                                      FDI_MPHY_IOSFSB_RESET_STATUS, 100))
-                       DRM_ERROR("FDI mPHY reset assert timeout\n");
-
-               tmp = I915_READ(SOUTH_CHICKEN2);
-               tmp &= ~FDI_MPHY_IOSFSB_RESET_CTL;
-               I915_WRITE(SOUTH_CHICKEN2, tmp);
+       if (wait_for_atomic_us((I915_READ(SOUTH_CHICKEN2) &
+                               FDI_MPHY_IOSFSB_RESET_STATUS) == 0, 100))
+               DRM_ERROR("FDI mPHY reset de-assert timeout\n");
+}
 
-               if (wait_for_atomic_us((I915_READ(SOUTH_CHICKEN2) &
-                                       FDI_MPHY_IOSFSB_RESET_STATUS) == 0,
-                                      100))
-                       DRM_ERROR("FDI mPHY reset de-assert timeout\n");
-       }
+/* WaMPhyProgramming:hsw */
+static void lpt_program_fdi_mphy(struct drm_i915_private *dev_priv)
+{
+       uint32_t tmp;
 
        tmp = intel_sbi_read(dev_priv, 0x8008, SBI_MPHY);
        tmp &= ~(0xFF << 24);
        tmp |= (0x12 << 24);
        intel_sbi_write(dev_priv, 0x8008, tmp, SBI_MPHY);
 
-       if (is_sdv) {
-               tmp = intel_sbi_read(dev_priv, 0x800C, SBI_MPHY);
-               tmp |= 0x7FFF;
-               intel_sbi_write(dev_priv, 0x800C, tmp, SBI_MPHY);
-       }
-
        tmp = intel_sbi_read(dev_priv, 0x2008, SBI_MPHY);
        tmp |= (1 << 11);
        intel_sbi_write(dev_priv, 0x2008, tmp, SBI_MPHY);
@@ -5195,24 +5221,6 @@ static void lpt_init_pch_refclk(struct drm_device *dev)
        tmp |= (1 << 11);
        intel_sbi_write(dev_priv, 0x2108, tmp, SBI_MPHY);
 
-       if (is_sdv) {
-               tmp = intel_sbi_read(dev_priv, 0x2038, SBI_MPHY);
-               tmp |= (0x3F << 24) | (0xF << 20) | (0xF << 16);
-               intel_sbi_write(dev_priv, 0x2038, tmp, SBI_MPHY);
-
-               tmp = intel_sbi_read(dev_priv, 0x2138, SBI_MPHY);
-               tmp |= (0x3F << 24) | (0xF << 20) | (0xF << 16);
-               intel_sbi_write(dev_priv, 0x2138, tmp, SBI_MPHY);
-
-               tmp = intel_sbi_read(dev_priv, 0x203C, SBI_MPHY);
-               tmp |= (0x3F << 8);
-               intel_sbi_write(dev_priv, 0x203C, tmp, SBI_MPHY);
-
-               tmp = intel_sbi_read(dev_priv, 0x213C, SBI_MPHY);
-               tmp |= (0x3F << 8);
-               intel_sbi_write(dev_priv, 0x213C, tmp, SBI_MPHY);
-       }
-
        tmp = intel_sbi_read(dev_priv, 0x206C, SBI_MPHY);
        tmp |= (1 << 24) | (1 << 21) | (1 << 18);
        intel_sbi_write(dev_priv, 0x206C, tmp, SBI_MPHY);
@@ -5221,17 +5229,15 @@ static void lpt_init_pch_refclk(struct drm_device *dev)
        tmp |= (1 << 24) | (1 << 21) | (1 << 18);
        intel_sbi_write(dev_priv, 0x216C, tmp, SBI_MPHY);
 
-       if (!is_sdv) {
-               tmp = intel_sbi_read(dev_priv, 0x2080, SBI_MPHY);
-               tmp &= ~(7 << 13);
-               tmp |= (5 << 13);
-               intel_sbi_write(dev_priv, 0x2080, tmp, SBI_MPHY);
+       tmp = intel_sbi_read(dev_priv, 0x2080, SBI_MPHY);
+       tmp &= ~(7 << 13);
+       tmp |= (5 << 13);
+       intel_sbi_write(dev_priv, 0x2080, tmp, SBI_MPHY);
 
-               tmp = intel_sbi_read(dev_priv, 0x2180, SBI_MPHY);
-               tmp &= ~(7 << 13);
-               tmp |= (5 << 13);
-               intel_sbi_write(dev_priv, 0x2180, tmp, SBI_MPHY);
-       }
+       tmp = intel_sbi_read(dev_priv, 0x2180, SBI_MPHY);
+       tmp &= ~(7 << 13);
+       tmp |= (5 << 13);
+       intel_sbi_write(dev_priv, 0x2180, tmp, SBI_MPHY);
 
        tmp = intel_sbi_read(dev_priv, 0x208C, SBI_MPHY);
        tmp &= ~0xFF;
@@ -5253,34 +5259,120 @@ static void lpt_init_pch_refclk(struct drm_device *dev)
        tmp |= (0x1C << 16);
        intel_sbi_write(dev_priv, 0x2198, tmp, SBI_MPHY);
 
-       if (!is_sdv) {
-               tmp = intel_sbi_read(dev_priv, 0x20C4, SBI_MPHY);
-               tmp |= (1 << 27);
-               intel_sbi_write(dev_priv, 0x20C4, tmp, SBI_MPHY);
+       tmp = intel_sbi_read(dev_priv, 0x20C4, SBI_MPHY);
+       tmp |= (1 << 27);
+       intel_sbi_write(dev_priv, 0x20C4, tmp, SBI_MPHY);
+
+       tmp = intel_sbi_read(dev_priv, 0x21C4, SBI_MPHY);
+       tmp |= (1 << 27);
+       intel_sbi_write(dev_priv, 0x21C4, tmp, SBI_MPHY);
+
+       tmp = intel_sbi_read(dev_priv, 0x20EC, SBI_MPHY);
+       tmp &= ~(0xF << 28);
+       tmp |= (4 << 28);
+       intel_sbi_write(dev_priv, 0x20EC, tmp, SBI_MPHY);
+
+       tmp = intel_sbi_read(dev_priv, 0x21EC, SBI_MPHY);
+       tmp &= ~(0xF << 28);
+       tmp |= (4 << 28);
+       intel_sbi_write(dev_priv, 0x21EC, tmp, SBI_MPHY);
+}
+
+/* Implements 3 different sequences from BSpec chapter "Display iCLK
+ * Programming" based on the parameters passed:
+ * - Sequence to enable CLKOUT_DP
+ * - Sequence to enable CLKOUT_DP without spread
+ * - Sequence to enable CLKOUT_DP for FDI usage and configure PCH FDI I/O
+ */
+static void lpt_enable_clkout_dp(struct drm_device *dev, bool with_spread,
+                                bool with_fdi)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t reg, tmp;
+
+       if (WARN(with_fdi && !with_spread, "FDI requires downspread\n"))
+               with_spread = true;
+       if (WARN(dev_priv->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE &&
+                with_fdi, "LP PCH doesn't have FDI\n"))
+               with_fdi = false;
+
+       mutex_lock(&dev_priv->dpio_lock);
+
+       tmp = intel_sbi_read(dev_priv, SBI_SSCCTL, SBI_ICLK);
+       tmp &= ~SBI_SSCCTL_DISABLE;
+       tmp |= SBI_SSCCTL_PATHALT;
+       intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);
 
-               tmp = intel_sbi_read(dev_priv, 0x21C4, SBI_MPHY);
-               tmp |= (1 << 27);
-               intel_sbi_write(dev_priv, 0x21C4, tmp, SBI_MPHY);
+       udelay(24);
 
-               tmp = intel_sbi_read(dev_priv, 0x20EC, SBI_MPHY);
-               tmp &= ~(0xF << 28);
-               tmp |= (4 << 28);
-               intel_sbi_write(dev_priv, 0x20EC, tmp, SBI_MPHY);
+       if (with_spread) {
+               tmp = intel_sbi_read(dev_priv, SBI_SSCCTL, SBI_ICLK);
+               tmp &= ~SBI_SSCCTL_PATHALT;
+               intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);
 
-               tmp = intel_sbi_read(dev_priv, 0x21EC, SBI_MPHY);
-               tmp &= ~(0xF << 28);
-               tmp |= (4 << 28);
-               intel_sbi_write(dev_priv, 0x21EC, tmp, SBI_MPHY);
+               if (with_fdi) {
+                       lpt_reset_fdi_mphy(dev_priv);
+                       lpt_program_fdi_mphy(dev_priv);
+               }
        }
 
-       /* ULT uses SBI_GEN0, but ULT doesn't have VGA, so we don't care. */
-       tmp = intel_sbi_read(dev_priv, SBI_DBUFF0, SBI_ICLK);
-       tmp |= SBI_DBUFF0_ENABLE;
-       intel_sbi_write(dev_priv, SBI_DBUFF0, tmp, SBI_ICLK);
+       reg = (dev_priv->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) ?
+              SBI_GEN0 : SBI_DBUFF0;
+       tmp = intel_sbi_read(dev_priv, reg, SBI_ICLK);
+       tmp |= SBI_GEN0_CFG_BUFFENABLE_DISABLE;
+       intel_sbi_write(dev_priv, reg, tmp, SBI_ICLK);
+
+       mutex_unlock(&dev_priv->dpio_lock);
+}
+
+/* Sequence to disable CLKOUT_DP */
+static void lpt_disable_clkout_dp(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t reg, tmp;
+
+       mutex_lock(&dev_priv->dpio_lock);
+
+       reg = (dev_priv->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) ?
+              SBI_GEN0 : SBI_DBUFF0;
+       tmp = intel_sbi_read(dev_priv, reg, SBI_ICLK);
+       tmp &= ~SBI_GEN0_CFG_BUFFENABLE_DISABLE;
+       intel_sbi_write(dev_priv, reg, tmp, SBI_ICLK);
+
+       tmp = intel_sbi_read(dev_priv, SBI_SSCCTL, SBI_ICLK);
+       if (!(tmp & SBI_SSCCTL_DISABLE)) {
+               if (!(tmp & SBI_SSCCTL_PATHALT)) {
+                       tmp |= SBI_SSCCTL_PATHALT;
+                       intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);
+                       udelay(32);
+               }
+               tmp |= SBI_SSCCTL_DISABLE;
+               intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);
+       }
 
        mutex_unlock(&dev_priv->dpio_lock);
 }
 
+static void lpt_init_pch_refclk(struct drm_device *dev)
+{
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct intel_encoder *encoder;
+       bool has_vga = false;
+
+       list_for_each_entry(encoder, &mode_config->encoder_list, base.head) {
+               switch (encoder->type) {
+               case INTEL_OUTPUT_ANALOG:
+                       has_vga = true;
+                       break;
+               }
+       }
+
+       if (has_vga)
+               lpt_enable_clkout_dp(dev, true, true);
+       else
+               lpt_disable_clkout_dp(dev);
+}
+
 /*
  * Initialize reference clocks when the driver loads
  */
@@ -5610,9 +5702,9 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc,
                << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
 
        if (is_sdvo)
-               dpll |= DPLL_DVO_HIGH_SPEED;
+               dpll |= DPLL_SDVO_HIGH_SPEED;
        if (intel_crtc->config.has_dp_encoder)
-               dpll |= DPLL_DVO_HIGH_SPEED;
+               dpll |= DPLL_SDVO_HIGH_SPEED;
 
        /* compute bitmask from p1 value */
        dpll |= (1 << (intel_crtc->config.dpll.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
@@ -5708,7 +5800,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
                else
                        intel_crtc->config.dpll_hw_state.fp1 = fp;
 
-               pll = intel_get_shared_dpll(intel_crtc, dpll, fp);
+               pll = intel_get_shared_dpll(intel_crtc);
                if (pll == NULL) {
                        DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
                                         pipe_name(pipe));
@@ -5720,10 +5812,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
        if (intel_crtc->config.has_dp_encoder)
                intel_dp_set_m_n(intel_crtc);
 
-       for_each_encoder_on_crtc(dev, crtc, encoder)
-               if (encoder->pre_pll_enable)
-                       encoder->pre_pll_enable(encoder);
-
        if (is_lvds && has_reduced_clock && i915_powersave)
                intel_crtc->lowfreq_avail = true;
        else
@@ -5732,23 +5820,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
        if (intel_crtc->config.has_pch_encoder) {
                pll = intel_crtc_to_shared_dpll(intel_crtc);
 
-               I915_WRITE(PCH_DPLL(pll->id), dpll);
-
-               /* Wait for the clocks to stabilize. */
-               POSTING_READ(PCH_DPLL(pll->id));
-               udelay(150);
-
-               /* The pixel multiplier can only be updated once the
-                * DPLL is enabled and the clocks are stable.
-                *
-                * So write it again.
-                */
-               I915_WRITE(PCH_DPLL(pll->id), dpll);
-
-               if (has_reduced_clock)
-                       I915_WRITE(PCH_FP1(pll->id), fp2);
-               else
-                       I915_WRITE(PCH_FP1(pll->id), fp);
        }
 
        intel_set_pipe_timings(intel_crtc);
@@ -5820,7 +5891,7 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t tmp;
 
-       pipe_config->cpu_transcoder = crtc->pipe;
+       pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe;
        pipe_config->shared_dpll = DPLL_ID_PRIVATE;
 
        tmp = I915_READ(PIPECONF(crtc->pipe));
@@ -5838,12 +5909,9 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
 
                ironlake_get_fdi_m_n_config(crtc, pipe_config);
 
-               /* XXX: Can't properly read out the pch dpll pixel multiplier
-                * since we don't have state tracking for pch clocks yet. */
-               pipe_config->pixel_multiplier = 1;
-
                if (HAS_PCH_IBX(dev_priv->dev)) {
-                       pipe_config->shared_dpll = crtc->pipe;
+                       pipe_config->shared_dpll =
+                               (enum intel_dpll_id) crtc->pipe;
                } else {
                        tmp = I915_READ(PCH_DPLL_SEL);
                        if (tmp & TRANS_DPLLB_SEL(crtc->pipe))
@@ -5856,6 +5924,11 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
 
                WARN_ON(!pll->get_hw_state(dev_priv, pll,
                                           &pipe_config->dpll_hw_state));
+
+               tmp = pipe_config->dpll_hw_state.dpll;
+               pipe_config->pixel_multiplier =
+                       ((tmp & PLL_REF_SDVO_HDMI_MULTIPLIER_MASK)
+                        >> PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT) + 1;
        } else {
                pipe_config->pixel_multiplier = 1;
        }
@@ -5867,6 +5940,142 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
        return true;
 }
 
+static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv)
+{
+       struct drm_device *dev = dev_priv->dev;
+       struct intel_ddi_plls *plls = &dev_priv->ddi_plls;
+       struct intel_crtc *crtc;
+       unsigned long irqflags;
+       uint32_t val, pch_hpd_mask;
+
+       pch_hpd_mask = SDE_PORTB_HOTPLUG_CPT | SDE_PORTC_HOTPLUG_CPT;
+       if (!(dev_priv->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE))
+               pch_hpd_mask |= SDE_PORTD_HOTPLUG_CPT | SDE_CRT_HOTPLUG_CPT;
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head)
+               WARN(crtc->base.enabled, "CRTC for pipe %c enabled\n",
+                    pipe_name(crtc->pipe));
+
+       WARN(I915_READ(HSW_PWR_WELL_DRIVER), "Power well on\n");
+       WARN(plls->spll_refcount, "SPLL enabled\n");
+       WARN(plls->wrpll1_refcount, "WRPLL1 enabled\n");
+       WARN(plls->wrpll2_refcount, "WRPLL2 enabled\n");
+       WARN(I915_READ(PCH_PP_STATUS) & PP_ON, "Panel power on\n");
+       WARN(I915_READ(BLC_PWM_CPU_CTL2) & BLM_PWM_ENABLE,
+            "CPU PWM1 enabled\n");
+       WARN(I915_READ(HSW_BLC_PWM2_CTL) & BLM_PWM_ENABLE,
+            "CPU PWM2 enabled\n");
+       WARN(I915_READ(BLC_PWM_PCH_CTL1) & BLM_PCH_PWM_ENABLE,
+            "PCH PWM1 enabled\n");
+       WARN(I915_READ(UTIL_PIN_CTL) & UTIL_PIN_ENABLE,
+            "Utility pin enabled\n");
+       WARN(I915_READ(PCH_GTC_CTL) & PCH_GTC_ENABLE, "PCH GTC enabled\n");
+
+       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+       val = I915_READ(DEIMR);
+       WARN((val & ~DE_PCH_EVENT_IVB) != val,
+            "Unexpected DEIMR bits enabled: 0x%x\n", val);
+       val = I915_READ(SDEIMR);
+       WARN((val & ~pch_hpd_mask) != val,
+            "Unexpected SDEIMR bits enabled: 0x%x\n", val);
+       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+}
+
+/*
+ * This function implements pieces of two sequences from BSpec:
+ * - Sequence for display software to disable LCPLL
+ * - Sequence for display software to allow package C8+
+ * The steps implemented here are just the steps that actually touch the LCPLL
+ * register. Callers should take care of disabling all the display engine
+ * functions, doing the mode unset, fixing interrupts, etc.
+ */
+void hsw_disable_lcpll(struct drm_i915_private *dev_priv,
+                      bool switch_to_fclk, bool allow_power_down)
+{
+       uint32_t val;
+
+       assert_can_disable_lcpll(dev_priv);
+
+       val = I915_READ(LCPLL_CTL);
+
+       if (switch_to_fclk) {
+               val |= LCPLL_CD_SOURCE_FCLK;
+               I915_WRITE(LCPLL_CTL, val);
+
+               if (wait_for_atomic_us(I915_READ(LCPLL_CTL) &
+                                      LCPLL_CD_SOURCE_FCLK_DONE, 1))
+                       DRM_ERROR("Switching to FCLK failed\n");
+
+               val = I915_READ(LCPLL_CTL);
+       }
+
+       val |= LCPLL_PLL_DISABLE;
+       I915_WRITE(LCPLL_CTL, val);
+       POSTING_READ(LCPLL_CTL);
+
+       if (wait_for((I915_READ(LCPLL_CTL) & LCPLL_PLL_LOCK) == 0, 1))
+               DRM_ERROR("LCPLL still locked\n");
+
+       val = I915_READ(D_COMP);
+       val |= D_COMP_COMP_DISABLE;
+       I915_WRITE(D_COMP, val);
+       POSTING_READ(D_COMP);
+       ndelay(100);
+
+       if (wait_for((I915_READ(D_COMP) & D_COMP_RCOMP_IN_PROGRESS) == 0, 1))
+               DRM_ERROR("D_COMP RCOMP still in progress\n");
+
+       if (allow_power_down) {
+               val = I915_READ(LCPLL_CTL);
+               val |= LCPLL_POWER_DOWN_ALLOW;
+               I915_WRITE(LCPLL_CTL, val);
+               POSTING_READ(LCPLL_CTL);
+       }
+}
+
+/*
+ * Fully restores LCPLL, disallowing power down and switching back to LCPLL
+ * source.
+ */
+void hsw_restore_lcpll(struct drm_i915_private *dev_priv)
+{
+       uint32_t val;
+
+       val = I915_READ(LCPLL_CTL);
+
+       if ((val & (LCPLL_PLL_LOCK | LCPLL_PLL_DISABLE | LCPLL_CD_SOURCE_FCLK |
+                   LCPLL_POWER_DOWN_ALLOW)) == LCPLL_PLL_LOCK)
+               return;
+
+       if (val & LCPLL_POWER_DOWN_ALLOW) {
+               val &= ~LCPLL_POWER_DOWN_ALLOW;
+               I915_WRITE(LCPLL_CTL, val);
+       }
+
+       val = I915_READ(D_COMP);
+       val |= D_COMP_COMP_FORCE;
+       val &= ~D_COMP_COMP_DISABLE;
+       I915_WRITE(D_COMP, val);
+       I915_READ(D_COMP);
+
+       val = I915_READ(LCPLL_CTL);
+       val &= ~LCPLL_PLL_DISABLE;
+       I915_WRITE(LCPLL_CTL, val);
+
+       if (wait_for(I915_READ(LCPLL_CTL) & LCPLL_PLL_LOCK, 5))
+               DRM_ERROR("LCPLL not locked yet\n");
+
+       if (val & LCPLL_CD_SOURCE_FCLK) {
+               val = I915_READ(LCPLL_CTL);
+               val &= ~LCPLL_CD_SOURCE_FCLK;
+               I915_WRITE(LCPLL_CTL, val);
+
+               if (wait_for_atomic_us((I915_READ(LCPLL_CTL) &
+                                       LCPLL_CD_SOURCE_FCLK_DONE) == 0, 1))
+                       DRM_ERROR("Switching back to LCPLL failed\n");
+       }
+}
+
 static void haswell_modeset_global_resources(struct drm_device *dev)
 {
        bool enable = false;
@@ -5935,7 +6144,7 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
        enum intel_display_power_domain pfit_domain;
        uint32_t tmp;
 
-       pipe_config->cpu_transcoder = crtc->pipe;
+       pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe;
        pipe_config->shared_dpll = DPLL_ID_PRIVATE;
 
        tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP));
@@ -6005,11 +6214,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_encoder_helper_funcs *encoder_funcs;
        struct intel_encoder *encoder;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct drm_display_mode *adjusted_mode =
-               &intel_crtc->config.adjusted_mode;
        struct drm_display_mode *mode = &intel_crtc->config.requested_mode;
        int pipe = intel_crtc->pipe;
        int ret;
@@ -6028,12 +6234,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        encoder->base.base.id,
                        drm_get_encoder_name(&encoder->base),
                        mode->base.id, mode->name);
-               if (encoder->mode_set) {
-                       encoder->mode_set(encoder);
-               } else {
-                       encoder_funcs = encoder->base.helper_private;
-                       encoder_funcs->mode_set(&encoder->base, mode, adjusted_mode);
-               }
+               encoder->mode_set(encoder);
        }
 
        return 0;
@@ -6548,7 +6749,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
                        goto fail_unpin;
                }
 
-               addr = obj->gtt_offset;
+               addr = i915_gem_obj_ggtt_offset(obj);
        } else {
                int align = IS_I830(dev) ? 16 * 1024 : 256;
                ret = i915_gem_attach_phys_object(dev, obj,
@@ -6875,11 +7076,12 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
 }
 
 /* Returns the clock of the currently programmed mode of the given pipe. */
-static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
+static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
+                               struct intel_crtc_config *pipe_config)
 {
+       struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int pipe = intel_crtc->pipe;
+       int pipe = pipe_config->cpu_transcoder;
        u32 dpll = I915_READ(DPLL(pipe));
        u32 fp;
        intel_clock_t clock;
@@ -6918,7 +7120,8 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
                default:
                        DRM_DEBUG_KMS("Unknown DPLL mode %08x in programmed "
                                  "mode\n", (int)(dpll & DPLL_MODE_MASK));
-                       return 0;
+                       pipe_config->adjusted_mode.clock = 0;
+                       return;
                }
 
                if (IS_PINEVIEW(dev))
@@ -6955,12 +7158,55 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
                }
        }
 
-       /* XXX: It would be nice to validate the clocks, but we can't reuse
-        * i830PllIsValid() because it relies on the xf86_config connector
-        * configuration being accurate, which it isn't necessarily.
+       pipe_config->adjusted_mode.clock = clock.dot *
+               pipe_config->pixel_multiplier;
+}
+
+static void ironlake_crtc_clock_get(struct intel_crtc *crtc,
+                                   struct intel_crtc_config *pipe_config)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       enum transcoder cpu_transcoder = pipe_config->cpu_transcoder;
+       int link_freq, repeat;
+       u64 clock;
+       u32 link_m, link_n;
+
+       repeat = pipe_config->pixel_multiplier;
+
+       /*
+        * The calculation for the data clock is:
+        * pixel_clock = ((m/n)*(link_clock * nr_lanes * repeat))/bpp
+        * But we want to avoid losing precison if possible, so:
+        * pixel_clock = ((m * link_clock * nr_lanes * repeat)/(n*bpp))
+        *
+        * and the link clock is simpler:
+        * link_clock = (m * link_clock * repeat) / n
         */
 
-       return clock.dot;
+       /*
+        * We need to get the FDI or DP link clock here to derive
+        * the M/N dividers.
+        *
+        * For FDI, we read it from the BIOS or use a fixed 2.7GHz.
+        * For DP, it's either 1.62GHz or 2.7GHz.
+        * We do our calculations in 10*MHz since we don't need much precison.
+        */
+       if (pipe_config->has_pch_encoder)
+               link_freq = intel_fdi_link_freq(dev) * 10000;
+       else
+               link_freq = pipe_config->port_clock;
+
+       link_m = I915_READ(PIPE_LINK_M1(cpu_transcoder));
+       link_n = I915_READ(PIPE_LINK_N1(cpu_transcoder));
+
+       if (!link_m || !link_n)
+               return;
+
+       clock = ((u64)link_m * (u64)link_freq * (u64)repeat);
+       do_div(clock, link_n);
+
+       pipe_config->adjusted_mode.clock = clock;
 }
 
 /** Returns the currently programmed mode of the given pipe. */
@@ -6971,6 +7217,7 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
        struct drm_display_mode *mode;
+       struct intel_crtc_config pipe_config;
        int htot = I915_READ(HTOTAL(cpu_transcoder));
        int hsync = I915_READ(HSYNC(cpu_transcoder));
        int vtot = I915_READ(VTOTAL(cpu_transcoder));
@@ -6980,7 +7227,18 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
        if (!mode)
                return NULL;
 
-       mode->clock = intel_crtc_clock_get(dev, crtc);
+       /*
+        * Construct a pipe_config sufficient for getting the clock info
+        * back out of crtc_clock_get.
+        *
+        * Note, if LVDS ever uses a non-1 pixel multiplier, we'll need
+        * to use a real value here instead.
+        */
+       pipe_config.cpu_transcoder = (enum transcoder) intel_crtc->pipe;
+       pipe_config.pixel_multiplier = 1;
+       i9xx_crtc_clock_get(intel_crtc, &pipe_config);
+
+       mode->clock = pipe_config.adjusted_mode.clock;
        mode->hdisplay = (htot & 0xffff) + 1;
        mode->htotal = ((htot & 0xffff0000) >> 16) + 1;
        mode->hsync_start = (hsync & 0xffff) + 1;
@@ -7263,7 +7521,7 @@ static int intel_gen2_queue_flip(struct drm_device *dev,
        intel_ring_emit(ring, MI_DISPLAY_FLIP |
                        MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
        intel_ring_emit(ring, fb->pitches[0]);
-       intel_ring_emit(ring, obj->gtt_offset + intel_crtc->dspaddr_offset);
+       intel_ring_emit(ring, i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
        intel_ring_emit(ring, 0); /* aux display base address, unused */
 
        intel_mark_page_flip_active(intel_crtc);
@@ -7304,7 +7562,7 @@ static int intel_gen3_queue_flip(struct drm_device *dev,
        intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 |
                        MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
        intel_ring_emit(ring, fb->pitches[0]);
-       intel_ring_emit(ring, obj->gtt_offset + intel_crtc->dspaddr_offset);
+       intel_ring_emit(ring, i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
        intel_ring_emit(ring, MI_NOOP);
 
        intel_mark_page_flip_active(intel_crtc);
@@ -7344,7 +7602,7 @@ static int intel_gen4_queue_flip(struct drm_device *dev,
                        MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
        intel_ring_emit(ring, fb->pitches[0]);
        intel_ring_emit(ring,
-                       (obj->gtt_offset + intel_crtc->dspaddr_offset) |
+                       (i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset) |
                        obj->tiling_mode);
 
        /* XXX Enabling the panel-fitter across page-flip is so far
@@ -7387,7 +7645,7 @@ static int intel_gen6_queue_flip(struct drm_device *dev,
        intel_ring_emit(ring, MI_DISPLAY_FLIP |
                        MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
        intel_ring_emit(ring, fb->pitches[0] | obj->tiling_mode);
-       intel_ring_emit(ring, obj->gtt_offset + intel_crtc->dspaddr_offset);
+       intel_ring_emit(ring, i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
 
        /* Contrary to the suggestions in the documentation,
         * "Enable Panel Fitter" does not seem to be required when page
@@ -7452,7 +7710,7 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
 
        intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 | plane_bit);
        intel_ring_emit(ring, (fb->pitches[0] | obj->tiling_mode));
-       intel_ring_emit(ring, obj->gtt_offset + intel_crtc->dspaddr_offset);
+       intel_ring_emit(ring, i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
        intel_ring_emit(ring, (MI_NOOP));
 
        intel_mark_page_flip_active(intel_crtc);
@@ -7789,7 +8047,6 @@ intel_modeset_pipe_config(struct drm_crtc *crtc,
                          struct drm_display_mode *mode)
 {
        struct drm_device *dev = crtc->dev;
-       struct drm_encoder_helper_funcs *encoder_funcs;
        struct intel_encoder *encoder;
        struct intel_crtc_config *pipe_config;
        int plane_bpp, ret = -EINVAL;
@@ -7806,7 +8063,8 @@ intel_modeset_pipe_config(struct drm_crtc *crtc,
 
        drm_mode_copy(&pipe_config->adjusted_mode, mode);
        drm_mode_copy(&pipe_config->requested_mode, mode);
-       pipe_config->cpu_transcoder = to_intel_crtc(crtc)->pipe;
+       pipe_config->cpu_transcoder =
+               (enum transcoder) to_intel_crtc(crtc)->pipe;
        pipe_config->shared_dpll = DPLL_ID_PRIVATE;
 
        /* Compute a starting value for pipe_config->pipe_bpp taking the source
@@ -7823,6 +8081,9 @@ encoder_retry:
        pipe_config->port_clock = 0;
        pipe_config->pixel_multiplier = 1;
 
+       /* Fill in default crtc timings, allow encoders to overwrite them. */
+       drm_mode_set_crtcinfo(&pipe_config->adjusted_mode, 0);
+
        /* Pass our mode to the connectors and the CRTC to give them a chance to
         * adjust it according to limitations or connector properties, and also
         * a chance to reject the mode entirely.
@@ -7833,20 +8094,8 @@ encoder_retry:
                if (&encoder->new_crtc->base != crtc)
                        continue;
 
-               if (encoder->compute_config) {
-                       if (!(encoder->compute_config(encoder, pipe_config))) {
-                               DRM_DEBUG_KMS("Encoder config failure\n");
-                               goto fail;
-                       }
-
-                       continue;
-               }
-
-               encoder_funcs = encoder->base.helper_private;
-               if (!(encoder_funcs->mode_fixup(&encoder->base,
-                                               &pipe_config->requested_mode,
-                                               &pipe_config->adjusted_mode))) {
-                       DRM_DEBUG_KMS("Encoder fixup failed\n");
+               if (!(encoder->compute_config(encoder, pipe_config))) {
+                       DRM_DEBUG_KMS("Encoder config failure\n");
                        goto fail;
                }
        }
@@ -8041,6 +8290,28 @@ intel_modeset_update_state(struct drm_device *dev, unsigned prepare_pipes)
 
 }
 
+static bool intel_fuzzy_clock_check(struct intel_crtc_config *cur,
+                                   struct intel_crtc_config *new)
+{
+       int clock1, clock2, diff;
+
+       clock1 = cur->adjusted_mode.clock;
+       clock2 = new->adjusted_mode.clock;
+
+       if (clock1 == clock2)
+               return true;
+
+       if (!clock1 || !clock2)
+               return false;
+
+       diff = abs(clock1 - clock2);
+
+       if (((((diff + clock1 + clock2) * 100)) / (clock1 + clock2)) < 105)
+               return true;
+
+       return false;
+}
+
 #define for_each_intel_crtc_masked(dev, mask, intel_crtc) \
        list_for_each_entry((intel_crtc), \
                            &(dev)->mode_config.crtc_list, \
@@ -8072,7 +8343,7 @@ intel_pipe_config_compare(struct drm_device *dev,
 
 #define PIPE_CONF_CHECK_FLAGS(name, mask)      \
        if ((current_config->name ^ pipe_config->name) & (mask)) { \
-               DRM_ERROR("mismatch in " #name " " \
+               DRM_ERROR("mismatch in " #name "(" #mask ") "      \
                          "(expected %i, found %i)\n", \
                          current_config->name & (mask), \
                          pipe_config->name & (mask)); \
@@ -8106,8 +8377,7 @@ intel_pipe_config_compare(struct drm_device *dev,
        PIPE_CONF_CHECK_I(adjusted_mode.crtc_vsync_start);
        PIPE_CONF_CHECK_I(adjusted_mode.crtc_vsync_end);
 
-       if (!HAS_PCH_SPLIT(dev))
-               PIPE_CONF_CHECK_I(pixel_multiplier);
+       PIPE_CONF_CHECK_I(pixel_multiplier);
 
        PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags,
                              DRM_MODE_FLAG_INTERLACE);
@@ -8138,6 +8408,7 @@ intel_pipe_config_compare(struct drm_device *dev,
 
        PIPE_CONF_CHECK_I(shared_dpll);
        PIPE_CONF_CHECK_X(dpll_hw_state.dpll);
+       PIPE_CONF_CHECK_X(dpll_hw_state.dpll_md);
        PIPE_CONF_CHECK_X(dpll_hw_state.fp0);
        PIPE_CONF_CHECK_X(dpll_hw_state.fp1);
 
@@ -8146,6 +8417,15 @@ intel_pipe_config_compare(struct drm_device *dev,
 #undef PIPE_CONF_CHECK_FLAGS
 #undef PIPE_CONF_QUIRK
 
+       if (!IS_HASWELL(dev)) {
+               if (!intel_fuzzy_clock_check(current_config, pipe_config)) {
+                       DRM_ERROR("mismatch in clock (expected %d, found %d)\n",
+                                 current_config->adjusted_mode.clock,
+                                 pipe_config->adjusted_mode.clock);
+                       return false;
+               }
+       }
+
        return true;
 }
 
@@ -8275,6 +8555,9 @@ check_crtc_state(struct drm_device *dev)
                                encoder->get_config(encoder, &pipe_config);
                }
 
+               if (dev_priv->display.get_clock)
+                       dev_priv->display.get_clock(crtc, &pipe_config);
+
                WARN(crtc->active != active,
                     "crtc active state doesn't match with hw state "
                     "(expected %i, found %i)\n", crtc->active, active);
@@ -8571,8 +8854,16 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set,
        } else if (set->crtc->fb != set->fb) {
                /* If we have no fb then treat it as a full mode set */
                if (set->crtc->fb == NULL) {
-                       DRM_DEBUG_KMS("crtc has no fb, full mode set\n");
-                       config->mode_changed = true;
+                       struct intel_crtc *intel_crtc =
+                               to_intel_crtc(set->crtc);
+
+                       if (intel_crtc->active && i915_fastboot) {
+                               DRM_DEBUG_KMS("crtc has no fb, will flip\n");
+                               config->fb_changed = true;
+                       } else {
+                               DRM_DEBUG_KMS("inactive crtc, full mode set\n");
+                               config->mode_changed = true;
+                       }
                } else if (set->fb == NULL) {
                        config->mode_changed = true;
                } else if (set->fb->pixel_format !=
@@ -8802,19 +9093,32 @@ static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv,
        return val & DPLL_VCO_ENABLE;
 }
 
+static void ibx_pch_dpll_mode_set(struct drm_i915_private *dev_priv,
+                                 struct intel_shared_dpll *pll)
+{
+       I915_WRITE(PCH_FP0(pll->id), pll->hw_state.fp0);
+       I915_WRITE(PCH_FP1(pll->id), pll->hw_state.fp1);
+}
+
 static void ibx_pch_dpll_enable(struct drm_i915_private *dev_priv,
                                struct intel_shared_dpll *pll)
 {
-       uint32_t reg, val;
-
        /* PCH refclock must be enabled first */
        assert_pch_refclk_enabled(dev_priv);
 
-       reg = PCH_DPLL(pll->id);
-       val = I915_READ(reg);
-       val |= DPLL_VCO_ENABLE;
-       I915_WRITE(reg, val);
-       POSTING_READ(reg);
+       I915_WRITE(PCH_DPLL(pll->id), pll->hw_state.dpll);
+
+       /* Wait for the clocks to stabilize. */
+       POSTING_READ(PCH_DPLL(pll->id));
+       udelay(150);
+
+       /* The pixel multiplier can only be updated once the
+        * DPLL is enabled and the clocks are stable.
+        *
+        * So write it again.
+        */
+       I915_WRITE(PCH_DPLL(pll->id), pll->hw_state.dpll);
+       POSTING_READ(PCH_DPLL(pll->id));
        udelay(200);
 }
 
@@ -8823,7 +9127,6 @@ static void ibx_pch_dpll_disable(struct drm_i915_private *dev_priv,
 {
        struct drm_device *dev = dev_priv->dev;
        struct intel_crtc *crtc;
-       uint32_t reg, val;
 
        /* Make sure no transcoder isn't still depending on us. */
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) {
@@ -8831,11 +9134,8 @@ static void ibx_pch_dpll_disable(struct drm_i915_private *dev_priv,
                        assert_pch_transcoder_disabled(dev_priv, crtc->pipe);
        }
 
-       reg = PCH_DPLL(pll->id);
-       val = I915_READ(reg);
-       val &= ~DPLL_VCO_ENABLE;
-       I915_WRITE(reg, val);
-       POSTING_READ(reg);
+       I915_WRITE(PCH_DPLL(pll->id), 0);
+       POSTING_READ(PCH_DPLL(pll->id));
        udelay(200);
 }
 
@@ -8854,6 +9154,7 @@ static void ibx_pch_dpll_init(struct drm_device *dev)
        for (i = 0; i < dev_priv->num_shared_dpll; i++) {
                dev_priv->shared_dplls[i].id = i;
                dev_priv->shared_dplls[i].name = ibx_pch_dpll_names[i];
+               dev_priv->shared_dplls[i].mode_set = ibx_pch_dpll_mode_set;
                dev_priv->shared_dplls[i].enable = ibx_pch_dpll_enable;
                dev_priv->shared_dplls[i].disable = ibx_pch_dpll_disable;
                dev_priv->shared_dplls[i].get_hw_state =
@@ -9270,6 +9571,7 @@ static void intel_init_display(struct drm_device *dev)
                dev_priv->display.update_plane = ironlake_update_plane;
        } else if (HAS_PCH_SPLIT(dev)) {
                dev_priv->display.get_pipe_config = ironlake_get_pipe_config;
+               dev_priv->display.get_clock = ironlake_crtc_clock_get;
                dev_priv->display.crtc_mode_set = ironlake_crtc_mode_set;
                dev_priv->display.crtc_enable = ironlake_crtc_enable;
                dev_priv->display.crtc_disable = ironlake_crtc_disable;
@@ -9277,6 +9579,7 @@ static void intel_init_display(struct drm_device *dev)
                dev_priv->display.update_plane = ironlake_update_plane;
        } else if (IS_VALLEYVIEW(dev)) {
                dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
+               dev_priv->display.get_clock = i9xx_crtc_clock_get;
                dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set;
                dev_priv->display.crtc_enable = valleyview_crtc_enable;
                dev_priv->display.crtc_disable = i9xx_crtc_disable;
@@ -9284,6 +9587,7 @@ static void intel_init_display(struct drm_device *dev)
                dev_priv->display.update_plane = i9xx_update_plane;
        } else {
                dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
+               dev_priv->display.get_clock = i9xx_crtc_clock_get;
                dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set;
                dev_priv->display.crtc_enable = i9xx_crtc_enable;
                dev_priv->display.crtc_disable = i9xx_crtc_disable;
@@ -9301,9 +9605,12 @@ static void intel_init_display(struct drm_device *dev)
        else if (IS_I915G(dev))
                dev_priv->display.get_display_clock_speed =
                        i915_get_display_clock_speed;
-       else if (IS_I945GM(dev) || IS_845G(dev) || IS_PINEVIEW_M(dev))
+       else if (IS_I945GM(dev) || IS_845G(dev))
                dev_priv->display.get_display_clock_speed =
                        i9xx_misc_get_display_clock_speed;
+       else if (IS_PINEVIEW(dev))
+               dev_priv->display.get_display_clock_speed =
+                       pnv_get_display_clock_speed;
        else if (IS_I915GM(dev))
                dev_priv->display.get_display_clock_speed =
                        i915gm_get_display_clock_speed;
@@ -9584,7 +9891,7 @@ void intel_modeset_init(struct drm_device *dev)
                      INTEL_INFO(dev)->num_pipes,
                      INTEL_INFO(dev)->num_pipes > 1 ? "s" : "");
 
-       for (i = 0; i < INTEL_INFO(dev)->num_pipes; i++) {
+       for_each_pipe(i) {
                intel_crtc_init(dev, i);
                for (j = 0; j < dev_priv->num_plane; j++) {
                        ret = intel_plane_init(dev, i, j);
@@ -9860,6 +10167,15 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
                              pipe);
        }
 
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list,
+                           base.head) {
+               if (!crtc->active)
+                       continue;
+               if (dev_priv->display.get_clock)
+                       dev_priv->display.get_clock(crtc,
+                                                   &crtc->config);
+       }
+
        list_for_each_entry(connector, &dev->mode_config.connector_list,
                            base.head) {
                if (connector->get_hw_state(connector)) {
@@ -9891,6 +10207,22 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
 
        intel_modeset_readout_hw_state(dev);
 
+       /*
+        * Now that we have the config, copy it to each CRTC struct
+        * Note that this could go away if we move to using crtc_config
+        * checking everywhere.
+        */
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list,
+                           base.head) {
+               if (crtc->active && i915_fastboot) {
+                       intel_crtc_mode_from_pipe_config(crtc, &crtc->config);
+
+                       DRM_DEBUG_KMS("[CRTC:%d] found active mode: ",
+                                     crtc->base.base.id);
+                       drm_mode_debug_printmodeline(&crtc->base.mode);
+               }
+       }
+
        /* HW state is read out, now we need to sanitize this mess. */
        list_for_each_entry(encoder, &dev->mode_config.encoder_list,
                            base.head) {
@@ -10033,9 +10365,6 @@ int intel_modeset_vga_set_state(struct drm_device *dev, bool state)
        return 0;
 }
 
-#ifdef CONFIG_DEBUG_FS
-#include <linux/seq_file.h>
-
 struct intel_display_error_state {
 
        u32 power_well_driver;
@@ -10127,8 +10456,7 @@ intel_display_capture_error_state(struct drm_device *dev)
         * well was on, so here we have to clear the FPGA_DBG_RM_NOCLAIM bit to
         * prevent the next I915_WRITE from detecting it and printing an error
         * message. */
-       if (HAS_POWER_WELL(dev))
-               I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
+       intel_uncore_clear_errors(dev);
 
        return error;
 }
@@ -10179,4 +10507,3 @@ intel_display_print_error_state(struct drm_i915_error_state_buf *m,
                err_printf(m, "  BASE: %08x\n", error->cursor[i].base);
        }
 }
-#endif
index 26e162bb3a5158d5da3f1b5e9b2614c7515ede6b..9282321e154c1c1c37e7ce848d722017fd13eb36 100644 (file)
@@ -276,29 +276,13 @@ intel_dp_aux_wait_done(struct intel_dp *intel_dp, bool has_aux_irq)
        return status;
 }
 
-static int
-intel_dp_aux_ch(struct intel_dp *intel_dp,
-               uint8_t *send, int send_bytes,
-               uint8_t *recv, int recv_size)
+static uint32_t get_aux_clock_divider(struct intel_dp *intel_dp,
+                                     int index)
 {
        struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
        struct drm_device *dev = intel_dig_port->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       uint32_t ch_ctl = intel_dp->aux_ch_ctl_reg;
-       uint32_t ch_data = ch_ctl + 4;
-       int i, ret, recv_bytes;
-       uint32_t status;
-       uint32_t aux_clock_divider;
-       int try, precharge;
-       bool has_aux_irq = INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev);
 
-       /* dp aux is extremely sensitive to irq latency, hence request the
-        * lowest possible wakeup latency and so prevent the cpu from going into
-        * deep sleep states.
-        */
-       pm_qos_update_request(&dev_priv->pm_qos, 0);
-
-       intel_dp_check_edp(intel_dp);
        /* The clock divider is based off the hrawclk,
         * and would like to run at 2MHz. So, take the
         * hrawclk value and divide by 2 and use that
@@ -307,23 +291,53 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
         * clock divider.
         */
        if (IS_VALLEYVIEW(dev)) {
-               aux_clock_divider = 100;
+               return index ? 0 : 100;
        } else if (intel_dig_port->port == PORT_A) {
+               if (index)
+                       return 0;
                if (HAS_DDI(dev))
-                       aux_clock_divider = DIV_ROUND_CLOSEST(
-                               intel_ddi_get_cdclk_freq(dev_priv), 2000);
+                       return DIV_ROUND_CLOSEST(intel_ddi_get_cdclk_freq(dev_priv), 2000);
                else if (IS_GEN6(dev) || IS_GEN7(dev))
-                       aux_clock_divider = 200; /* SNB & IVB eDP input clock at 400Mhz */
+                       return 200; /* SNB & IVB eDP input clock at 400Mhz */
                else
-                       aux_clock_divider = 225; /* eDP input clock at 450Mhz */
+                       return 225; /* eDP input clock at 450Mhz */
        } else if (dev_priv->pch_id == INTEL_PCH_LPT_DEVICE_ID_TYPE) {
                /* Workaround for non-ULT HSW */
-               aux_clock_divider = 74;
+               switch (index) {
+               case 0: return 63;
+               case 1: return 72;
+               default: return 0;
+               }
        } else if (HAS_PCH_SPLIT(dev)) {
-               aux_clock_divider = DIV_ROUND_UP(intel_pch_rawclk(dev), 2);
+               return index ? 0 : DIV_ROUND_UP(intel_pch_rawclk(dev), 2);
        } else {
-               aux_clock_divider = intel_hrawclk(dev) / 2;
+               return index ? 0 :intel_hrawclk(dev) / 2;
        }
+}
+
+static int
+intel_dp_aux_ch(struct intel_dp *intel_dp,
+               uint8_t *send, int send_bytes,
+               uint8_t *recv, int recv_size)
+{
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       struct drm_device *dev = intel_dig_port->base.base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t ch_ctl = intel_dp->aux_ch_ctl_reg;
+       uint32_t ch_data = ch_ctl + 4;
+       uint32_t aux_clock_divider;
+       int i, ret, recv_bytes;
+       uint32_t status;
+       int try, precharge, clock = 0;
+       bool has_aux_irq = INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev);
+
+       /* dp aux is extremely sensitive to irq latency, hence request the
+        * lowest possible wakeup latency and so prevent the cpu from going into
+        * deep sleep states.
+        */
+       pm_qos_update_request(&dev_priv->pm_qos, 0);
+
+       intel_dp_check_edp(intel_dp);
 
        if (IS_GEN6(dev))
                precharge = 3;
@@ -345,37 +359,41 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
                goto out;
        }
 
-       /* Must try at least 3 times according to DP spec */
-       for (try = 0; try < 5; try++) {
-               /* Load the send data into the aux channel data registers */
-               for (i = 0; i < send_bytes; i += 4)
-                       I915_WRITE(ch_data + i,
-                                  pack_aux(send + i, send_bytes - i));
-
-               /* Send the command and wait for it to complete */
-               I915_WRITE(ch_ctl,
-                          DP_AUX_CH_CTL_SEND_BUSY |
-                          (has_aux_irq ? DP_AUX_CH_CTL_INTERRUPT : 0) |
-                          DP_AUX_CH_CTL_TIME_OUT_400us |
-                          (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
-                          (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
-                          (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT) |
-                          DP_AUX_CH_CTL_DONE |
-                          DP_AUX_CH_CTL_TIME_OUT_ERROR |
-                          DP_AUX_CH_CTL_RECEIVE_ERROR);
-
-               status = intel_dp_aux_wait_done(intel_dp, has_aux_irq);
-
-               /* Clear done status and any errors */
-               I915_WRITE(ch_ctl,
-                          status |
-                          DP_AUX_CH_CTL_DONE |
-                          DP_AUX_CH_CTL_TIME_OUT_ERROR |
-                          DP_AUX_CH_CTL_RECEIVE_ERROR);
-
-               if (status & (DP_AUX_CH_CTL_TIME_OUT_ERROR |
-                             DP_AUX_CH_CTL_RECEIVE_ERROR))
-                       continue;
+       while ((aux_clock_divider = get_aux_clock_divider(intel_dp, clock++))) {
+               /* Must try at least 3 times according to DP spec */
+               for (try = 0; try < 5; try++) {
+                       /* Load the send data into the aux channel data registers */
+                       for (i = 0; i < send_bytes; i += 4)
+                               I915_WRITE(ch_data + i,
+                                          pack_aux(send + i, send_bytes - i));
+
+                       /* Send the command and wait for it to complete */
+                       I915_WRITE(ch_ctl,
+                                  DP_AUX_CH_CTL_SEND_BUSY |
+                                  (has_aux_irq ? DP_AUX_CH_CTL_INTERRUPT : 0) |
+                                  DP_AUX_CH_CTL_TIME_OUT_400us |
+                                  (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
+                                  (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
+                                  (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT) |
+                                  DP_AUX_CH_CTL_DONE |
+                                  DP_AUX_CH_CTL_TIME_OUT_ERROR |
+                                  DP_AUX_CH_CTL_RECEIVE_ERROR);
+
+                       status = intel_dp_aux_wait_done(intel_dp, has_aux_irq);
+
+                       /* Clear done status and any errors */
+                       I915_WRITE(ch_ctl,
+                                  status |
+                                  DP_AUX_CH_CTL_DONE |
+                                  DP_AUX_CH_CTL_TIME_OUT_ERROR |
+                                  DP_AUX_CH_CTL_RECEIVE_ERROR);
+
+                       if (status & (DP_AUX_CH_CTL_TIME_OUT_ERROR |
+                                     DP_AUX_CH_CTL_RECEIVE_ERROR))
+                               continue;
+                       if (status & DP_AUX_CH_CTL_DONE)
+                               break;
+               }
                if (status & DP_AUX_CH_CTL_DONE)
                        break;
        }
@@ -710,8 +728,11 @@ intel_dp_compute_config(struct intel_encoder *encoder,
        /* Walk through all bpp values. Luckily they're all nicely spaced with 2
         * bpc in between. */
        bpp = pipe_config->pipe_bpp;
-       if (is_edp(intel_dp) && dev_priv->vbt.edp_bpp)
+       if (is_edp(intel_dp) && dev_priv->vbt.edp_bpp) {
+               DRM_DEBUG_KMS("clamping bpp for eDP panel to BIOS-provided %i\n",
+                             dev_priv->vbt.edp_bpp);
                bpp = min_t(int, bpp, dev_priv->vbt.edp_bpp);
+       }
 
        for (; bpp >= 6*3; bpp -= 2*3) {
                mode_rate = intel_dp_link_required(adjusted_mode->clock, bpp);
@@ -812,15 +833,14 @@ static void ironlake_set_pll_cpu_edp(struct intel_dp *intel_dp)
        udelay(500);
 }
 
-static void
-intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
-                 struct drm_display_mode *adjusted_mode)
+static void intel_dp_mode_set(struct intel_encoder *encoder)
 {
-       struct drm_device *dev = encoder->dev;
+       struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
        enum port port = dp_to_dig_port(intel_dp)->port;
-       struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
+       struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
+       struct drm_display_mode *adjusted_mode = &crtc->config.adjusted_mode;
 
        /*
         * There are four kinds of DP registers:
@@ -852,7 +872,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
                DRM_DEBUG_DRIVER("Enabling DP audio on pipe %c\n",
                                 pipe_name(crtc->pipe));
                intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE;
-               intel_write_eld(encoder, adjusted_mode);
+               intel_write_eld(&encoder->base, adjusted_mode);
        }
 
        intel_dp_init_link_config(intel_dp);
@@ -1360,6 +1380,266 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
        }
 
        pipe_config->adjusted_mode.flags |= flags;
+
+       if (dp_to_dig_port(intel_dp)->port == PORT_A) {
+               if ((I915_READ(DP_A) & DP_PLL_FREQ_MASK) == DP_PLL_FREQ_160MHZ)
+                       pipe_config->port_clock = 162000;
+               else
+                       pipe_config->port_clock = 270000;
+       }
+}
+
+static bool is_edp_psr(struct intel_dp *intel_dp)
+{
+       return is_edp(intel_dp) &&
+               intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED;
+}
+
+static bool intel_edp_is_psr_enabled(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (!IS_HASWELL(dev))
+               return false;
+
+       return I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE;
+}
+
+static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
+                                   struct edp_vsc_psr *vsc_psr)
+{
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       struct drm_device *dev = dig_port->base.base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *crtc = to_intel_crtc(dig_port->base.base.crtc);
+       u32 ctl_reg = HSW_TVIDEO_DIP_CTL(crtc->config.cpu_transcoder);
+       u32 data_reg = HSW_TVIDEO_DIP_VSC_DATA(crtc->config.cpu_transcoder);
+       uint32_t *data = (uint32_t *) vsc_psr;
+       unsigned int i;
+
+       /* As per BSPec (Pipe Video Data Island Packet), we need to disable
+          the video DIP being updated before program video DIP data buffer
+          registers for DIP being updated. */
+       I915_WRITE(ctl_reg, 0);
+       POSTING_READ(ctl_reg);
+
+       for (i = 0; i < VIDEO_DIP_VSC_DATA_SIZE; i += 4) {
+               if (i < sizeof(struct edp_vsc_psr))
+                       I915_WRITE(data_reg + i, *data++);
+               else
+                       I915_WRITE(data_reg + i, 0);
+       }
+
+       I915_WRITE(ctl_reg, VIDEO_DIP_ENABLE_VSC_HSW);
+       POSTING_READ(ctl_reg);
+}
+
+static void intel_edp_psr_setup(struct intel_dp *intel_dp)
+{
+       struct drm_device *dev = intel_dp_to_dev(intel_dp);
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct edp_vsc_psr psr_vsc;
+
+       if (intel_dp->psr_setup_done)
+               return;
+
+       /* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
+       memset(&psr_vsc, 0, sizeof(psr_vsc));
+       psr_vsc.sdp_header.HB0 = 0;
+       psr_vsc.sdp_header.HB1 = 0x7;
+       psr_vsc.sdp_header.HB2 = 0x2;
+       psr_vsc.sdp_header.HB3 = 0x8;
+       intel_edp_psr_write_vsc(intel_dp, &psr_vsc);
+
+       /* Avoid continuous PSR exit by masking memup and hpd */
+       I915_WRITE(EDP_PSR_DEBUG_CTL, EDP_PSR_DEBUG_MASK_MEMUP |
+                  EDP_PSR_DEBUG_MASK_HPD);
+
+       intel_dp->psr_setup_done = true;
+}
+
+static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
+{
+       struct drm_device *dev = intel_dp_to_dev(intel_dp);
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t aux_clock_divider = get_aux_clock_divider(intel_dp, 0);
+       int precharge = 0x3;
+       int msg_size = 5;       /* Header(4) + Message(1) */
+
+       /* Enable PSR in sink */
+       if (intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT)
+               intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG,
+                                           DP_PSR_ENABLE &
+                                           ~DP_PSR_MAIN_LINK_ACTIVE);
+       else
+               intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG,
+                                           DP_PSR_ENABLE |
+                                           DP_PSR_MAIN_LINK_ACTIVE);
+
+       /* Setup AUX registers */
+       I915_WRITE(EDP_PSR_AUX_DATA1, EDP_PSR_DPCD_COMMAND);
+       I915_WRITE(EDP_PSR_AUX_DATA2, EDP_PSR_DPCD_NORMAL_OPERATION);
+       I915_WRITE(EDP_PSR_AUX_CTL,
+                  DP_AUX_CH_CTL_TIME_OUT_400us |
+                  (msg_size << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
+                  (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
+                  (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT));
+}
+
+static void intel_edp_psr_enable_source(struct intel_dp *intel_dp)
+{
+       struct drm_device *dev = intel_dp_to_dev(intel_dp);
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t max_sleep_time = 0x1f;
+       uint32_t idle_frames = 1;
+       uint32_t val = 0x0;
+
+       if (intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT) {
+               val |= EDP_PSR_LINK_STANDBY;
+               val |= EDP_PSR_TP2_TP3_TIME_0us;
+               val |= EDP_PSR_TP1_TIME_0us;
+               val |= EDP_PSR_SKIP_AUX_EXIT;
+       } else
+               val |= EDP_PSR_LINK_DISABLE;
+
+       I915_WRITE(EDP_PSR_CTL, val |
+                  EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES |
+                  max_sleep_time << EDP_PSR_MAX_SLEEP_TIME_SHIFT |
+                  idle_frames << EDP_PSR_IDLE_FRAME_SHIFT |
+                  EDP_PSR_ENABLE);
+}
+
+static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
+{
+       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+       struct drm_device *dev = dig_port->base.base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_crtc *crtc = dig_port->base.base.crtc;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct drm_i915_gem_object *obj = to_intel_framebuffer(crtc->fb)->obj;
+       struct intel_encoder *intel_encoder = &dp_to_dig_port(intel_dp)->base;
+
+       if (!IS_HASWELL(dev)) {
+               DRM_DEBUG_KMS("PSR not supported on this platform\n");
+               dev_priv->no_psr_reason = PSR_NO_SOURCE;
+               return false;
+       }
+
+       if ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
+           (dig_port->port != PORT_A)) {
+               DRM_DEBUG_KMS("HSW ties PSR to DDI A (eDP)\n");
+               dev_priv->no_psr_reason = PSR_HSW_NOT_DDIA;
+               return false;
+       }
+
+       if (!is_edp_psr(intel_dp)) {
+               DRM_DEBUG_KMS("PSR not supported by this panel\n");
+               dev_priv->no_psr_reason = PSR_NO_SINK;
+               return false;
+       }
+
+       if (!i915_enable_psr) {
+               DRM_DEBUG_KMS("PSR disable by flag\n");
+               dev_priv->no_psr_reason = PSR_MODULE_PARAM;
+               return false;
+       }
+
+       if (!intel_crtc->active || !crtc->fb || !crtc->mode.clock) {
+               DRM_DEBUG_KMS("crtc not active for PSR\n");
+               dev_priv->no_psr_reason = PSR_CRTC_NOT_ACTIVE;
+               return false;
+       }
+
+       if (obj->tiling_mode != I915_TILING_X ||
+           obj->fence_reg == I915_FENCE_REG_NONE) {
+               DRM_DEBUG_KMS("PSR condition failed: fb not tiled or fenced\n");
+               dev_priv->no_psr_reason = PSR_NOT_TILED;
+               return false;
+       }
+
+       if (I915_READ(SPRCTL(intel_crtc->pipe)) & SPRITE_ENABLE) {
+               DRM_DEBUG_KMS("PSR condition failed: Sprite is Enabled\n");
+               dev_priv->no_psr_reason = PSR_SPRITE_ENABLED;
+               return false;
+       }
+
+       if (I915_READ(HSW_STEREO_3D_CTL(intel_crtc->config.cpu_transcoder)) &
+           S3D_ENABLE) {
+               DRM_DEBUG_KMS("PSR condition failed: Stereo 3D is Enabled\n");
+               dev_priv->no_psr_reason = PSR_S3D_ENABLED;
+               return false;
+       }
+
+       if (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) {
+               DRM_DEBUG_KMS("PSR condition failed: Interlaced is Enabled\n");
+               dev_priv->no_psr_reason = PSR_INTERLACED_ENABLED;
+               return false;
+       }
+
+       return true;
+}
+
+static void intel_edp_psr_do_enable(struct intel_dp *intel_dp)
+{
+       struct drm_device *dev = intel_dp_to_dev(intel_dp);
+
+       if (!intel_edp_psr_match_conditions(intel_dp) ||
+           intel_edp_is_psr_enabled(dev))
+               return;
+
+       /* Setup PSR once */
+       intel_edp_psr_setup(intel_dp);
+
+       /* Enable PSR on the panel */
+       intel_edp_psr_enable_sink(intel_dp);
+
+       /* Enable PSR on the host */
+       intel_edp_psr_enable_source(intel_dp);
+}
+
+void intel_edp_psr_enable(struct intel_dp *intel_dp)
+{
+       struct drm_device *dev = intel_dp_to_dev(intel_dp);
+
+       if (intel_edp_psr_match_conditions(intel_dp) &&
+           !intel_edp_is_psr_enabled(dev))
+               intel_edp_psr_do_enable(intel_dp);
+}
+
+void intel_edp_psr_disable(struct intel_dp *intel_dp)
+{
+       struct drm_device *dev = intel_dp_to_dev(intel_dp);
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (!intel_edp_is_psr_enabled(dev))
+               return;
+
+       I915_WRITE(EDP_PSR_CTL, I915_READ(EDP_PSR_CTL) & ~EDP_PSR_ENABLE);
+
+       /* Wait till PSR is idle */
+       if (_wait_for((I915_READ(EDP_PSR_STATUS_CTL) &
+                      EDP_PSR_STATUS_STATE_MASK) == 0, 2000, 10))
+               DRM_ERROR("Timed out waiting for PSR Idle State\n");
+}
+
+void intel_edp_psr_update(struct drm_device *dev)
+{
+       struct intel_encoder *encoder;
+       struct intel_dp *intel_dp = NULL;
+
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head)
+               if (encoder->type == INTEL_OUTPUT_EDP) {
+                       intel_dp = enc_to_intel_dp(&encoder->base);
+
+                       if (!is_edp_psr(intel_dp))
+                               return;
+
+                       if (!intel_edp_psr_match_conditions(intel_dp))
+                               intel_edp_psr_disable(intel_dp);
+                       else
+                               if (!intel_edp_is_psr_enabled(dev))
+                                       intel_edp_psr_do_enable(intel_dp);
+               }
 }
 
 static void intel_disable_dp(struct intel_encoder *encoder)
@@ -2275,6 +2555,13 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
        if (intel_dp->dpcd[DP_DPCD_REV] == 0)
                return false; /* DPCD not present */
 
+       /* Check if the panel supports PSR */
+       memset(intel_dp->psr_dpcd, 0, sizeof(intel_dp->psr_dpcd));
+       intel_dp_aux_native_read_retry(intel_dp, DP_PSR_SUPPORT,
+                                      intel_dp->psr_dpcd,
+                                      sizeof(intel_dp->psr_dpcd));
+       if (is_edp_psr(intel_dp))
+               DRM_DEBUG_KMS("Detected EDP PSR Panel.\n");
        if (!(intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] &
              DP_DWN_STRM_PORT_PRESENT))
                return true; /* native DP sink */
@@ -2542,6 +2829,9 @@ intel_dp_detect(struct drm_connector *connector, bool force)
        enum drm_connector_status status;
        struct edid *edid = NULL;
 
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
+                     connector->base.id, drm_get_connector_name(connector));
+
        intel_dp->has_audio = false;
 
        if (HAS_PCH_SPLIT(dev))
@@ -2735,10 +3025,6 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder)
        kfree(intel_dig_port);
 }
 
-static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = {
-       .mode_set = intel_dp_mode_set,
-};
-
 static const struct drm_connector_funcs intel_dp_connector_funcs = {
        .dpms = intel_connector_dpms,
        .detect = intel_dp_detect,
@@ -3166,6 +3452,8 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
        WARN(error, "intel_dp_i2c_init failed with error %d for port %c\n",
             error, port_name(port));
 
+       intel_dp->psr_setup_done = false;
+
        if (!intel_edp_init_connector(intel_dp, intel_connector)) {
                i2c_del_adapter(&intel_dp->adapter);
                if (is_edp(intel_dp)) {
@@ -3216,9 +3504,9 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
 
        drm_encoder_init(dev, &intel_encoder->base, &intel_dp_enc_funcs,
                         DRM_MODE_ENCODER_TMDS);
-       drm_encoder_helper_add(&intel_encoder->base, &intel_dp_helper_funcs);
 
        intel_encoder->compute_config = intel_dp_compute_config;
+       intel_encoder->mode_set = intel_dp_mode_set;
        intel_encoder->enable = intel_enable_dp;
        intel_encoder->pre_enable = intel_pre_enable_dp;
        intel_encoder->disable = intel_disable_dp;
index b7d6e09456ce372f8a87e8f3b1ebd75df1779e70..474797be1fc2bdf15e1f137c28d2e748754ad677 100644 (file)
@@ -208,10 +208,6 @@ struct intel_crtc_config {
 
        struct drm_display_mode requested_mode;
        struct drm_display_mode adjusted_mode;
-       /* This flag must be set by the encoder's compute_config callback if it
-        * changes the crtc timings in the mode to prevent the crtc fixup from
-        * overwriting them.  Currently only lvds needs that. */
-       bool timings_set;
        /* Whether to set up the PCH/FDI. Note that we never allow sharing
         * between pch encoders and cpu encoders. */
        bool has_pch_encoder;
@@ -487,6 +483,7 @@ struct intel_dp {
        uint8_t link_bw;
        uint8_t lane_count;
        uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
+       uint8_t psr_dpcd[EDP_PSR_RECEIVER_CAP_SIZE];
        uint8_t downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
        struct i2c_adapter adapter;
        struct i2c_algo_dp_aux_data algo;
@@ -498,6 +495,7 @@ struct intel_dp {
        int backlight_off_delay;
        struct delayed_work panel_vdd_work;
        bool want_panel_vdd;
+       bool psr_setup_done;
        struct intel_connector *attached_connector;
 };
 
@@ -549,13 +547,6 @@ struct intel_unpin_work {
        bool enable_stall_check;
 };
 
-struct intel_fbc_work {
-       struct delayed_work work;
-       struct drm_crtc *crtc;
-       struct drm_framebuffer *fb;
-       int interval;
-};
-
 int intel_pch_rawclk(struct drm_device *dev);
 
 int intel_connector_update_modes(struct drm_connector *connector,
@@ -747,6 +738,22 @@ extern int intel_overlay_attrs(struct drm_device *dev, void *data,
 extern void intel_fb_output_poll_changed(struct drm_device *dev);
 extern void intel_fb_restore_mode(struct drm_device *dev);
 
+struct intel_shared_dpll *
+intel_crtc_to_shared_dpll(struct intel_crtc *crtc);
+
+void assert_shared_dpll(struct drm_i915_private *dev_priv,
+                       struct intel_shared_dpll *pll,
+                       bool state);
+#define assert_shared_dpll_enabled(d, p) assert_shared_dpll(d, p, true)
+#define assert_shared_dpll_disabled(d, p) assert_shared_dpll(d, p, false)
+void assert_pll(struct drm_i915_private *dev_priv,
+               enum pipe pipe, bool state);
+#define assert_pll_enabled(d, p) assert_pll(d, p, true)
+#define assert_pll_disabled(d, p) assert_pll(d, p, false)
+void assert_fdi_rx_pll(struct drm_i915_private *dev_priv,
+                      enum pipe pipe, bool state);
+#define assert_fdi_rx_pll_enabled(d, p) assert_fdi_rx_pll(d, p, true)
+#define assert_fdi_rx_pll_disabled(d, p) assert_fdi_rx_pll(d, p, false)
 extern void assert_pipe(struct drm_i915_private *dev_priv, enum pipe pipe,
                        bool state);
 #define assert_pipe_enabled(d, p) assert_pipe(d, p, true)
@@ -780,7 +787,6 @@ extern int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
 extern void intel_init_pm(struct drm_device *dev);
 /* FBC */
 extern bool intel_fbc_enabled(struct drm_device *dev);
-extern void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval);
 extern void intel_update_fbc(struct drm_device *dev);
 /* IPS */
 extern void intel_gpu_ips_init(struct drm_i915_private *dev_priv);
@@ -796,7 +802,6 @@ extern void intel_init_power_well(struct drm_device *dev);
 extern void intel_set_power_well(struct drm_device *dev, bool enable);
 extern void intel_enable_gt_powersave(struct drm_device *dev);
 extern void intel_disable_gt_powersave(struct drm_device *dev);
-extern void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv);
 extern void ironlake_teardown_rc6(struct drm_device *dev);
 
 extern bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
@@ -825,4 +830,11 @@ extern bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
                                                 enum transcoder pch_transcoder,
                                                 bool enable);
 
+extern void intel_edp_psr_enable(struct intel_dp *intel_dp);
+extern void intel_edp_psr_disable(struct intel_dp *intel_dp);
+extern void intel_edp_psr_update(struct drm_device *dev);
+extern void hsw_disable_lcpll(struct drm_i915_private *dev_priv,
+                             bool switch_to_fclk, bool allow_power_down);
+extern void hsw_restore_lcpll(struct drm_i915_private *dev_priv);
+
 #endif /* __INTEL_DRV_H__ */
index eb2020eb2b7ea1c60dde15062c426182e30d9d05..406303b509c1c0afeed4be9379060e5417e212e0 100644 (file)
@@ -100,15 +100,14 @@ struct intel_dvo {
        bool panel_wants_dither;
 };
 
-static struct intel_dvo *enc_to_intel_dvo(struct drm_encoder *encoder)
+static struct intel_dvo *enc_to_dvo(struct intel_encoder *encoder)
 {
-       return container_of(encoder, struct intel_dvo, base.base);
+       return container_of(encoder, struct intel_dvo, base);
 }
 
 static struct intel_dvo *intel_attached_dvo(struct drm_connector *connector)
 {
-       return container_of(intel_attached_encoder(connector),
-                           struct intel_dvo, base);
+       return enc_to_dvo(intel_attached_encoder(connector));
 }
 
 static bool intel_dvo_connector_get_hw_state(struct intel_connector *connector)
@@ -123,7 +122,7 @@ static bool intel_dvo_get_hw_state(struct intel_encoder *encoder,
 {
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_dvo *intel_dvo = enc_to_intel_dvo(&encoder->base);
+       struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
        u32 tmp;
 
        tmp = I915_READ(intel_dvo->dev.dvo_reg);
@@ -140,7 +139,7 @@ static void intel_dvo_get_config(struct intel_encoder *encoder,
                                 struct intel_crtc_config *pipe_config)
 {
        struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
-       struct intel_dvo *intel_dvo = enc_to_intel_dvo(&encoder->base);
+       struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
        u32 tmp, flags = 0;
 
        tmp = I915_READ(intel_dvo->dev.dvo_reg);
@@ -159,7 +158,7 @@ static void intel_dvo_get_config(struct intel_encoder *encoder,
 static void intel_disable_dvo(struct intel_encoder *encoder)
 {
        struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
-       struct intel_dvo *intel_dvo = enc_to_intel_dvo(&encoder->base);
+       struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
        u32 dvo_reg = intel_dvo->dev.dvo_reg;
        u32 temp = I915_READ(dvo_reg);
 
@@ -171,7 +170,7 @@ static void intel_disable_dvo(struct intel_encoder *encoder)
 static void intel_enable_dvo(struct intel_encoder *encoder)
 {
        struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
-       struct intel_dvo *intel_dvo = enc_to_intel_dvo(&encoder->base);
+       struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
        u32 dvo_reg = intel_dvo->dev.dvo_reg;
        u32 temp = I915_READ(dvo_reg);
 
@@ -241,11 +240,11 @@ static int intel_dvo_mode_valid(struct drm_connector *connector,
        return intel_dvo->dev.dev_ops->mode_valid(&intel_dvo->dev, mode);
 }
 
-static bool intel_dvo_mode_fixup(struct drm_encoder *encoder,
-                                const struct drm_display_mode *mode,
-                                struct drm_display_mode *adjusted_mode)
+static bool intel_dvo_compute_config(struct intel_encoder *encoder,
+                                    struct intel_crtc_config *pipe_config)
 {
-       struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
+       struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
+       struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
 
        /* If we have timings from the BIOS for the panel, put them in
         * to the adjusted mode.  The CRTC will be set up for this mode,
@@ -267,23 +266,23 @@ static bool intel_dvo_mode_fixup(struct drm_encoder *encoder,
        }
 
        if (intel_dvo->dev.dev_ops->mode_fixup)
-               return intel_dvo->dev.dev_ops->mode_fixup(&intel_dvo->dev, mode, adjusted_mode);
+               return intel_dvo->dev.dev_ops->mode_fixup(&intel_dvo->dev,
+                                                         &pipe_config->requested_mode,
+                                                         adjusted_mode);
 
        return true;
 }
 
-static void intel_dvo_mode_set(struct drm_encoder *encoder,
-                              struct drm_display_mode *mode,
-                              struct drm_display_mode *adjusted_mode)
+static void intel_dvo_mode_set(struct intel_encoder *encoder)
 {
-       struct drm_device *dev = encoder->dev;
+       struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
-       struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
-       int pipe = intel_crtc->pipe;
+       struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
+       struct drm_display_mode *adjusted_mode = &crtc->config.adjusted_mode;
+       struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
+       int pipe = crtc->pipe;
        u32 dvo_val;
        u32 dvo_reg = intel_dvo->dev.dvo_reg, dvo_srcdim_reg;
-       int dpll_reg = DPLL(pipe);
 
        switch (dvo_reg) {
        case DVOA:
@@ -298,7 +297,9 @@ static void intel_dvo_mode_set(struct drm_encoder *encoder,
                break;
        }
 
-       intel_dvo->dev.dev_ops->mode_set(&intel_dvo->dev, mode, adjusted_mode);
+       intel_dvo->dev.dev_ops->mode_set(&intel_dvo->dev,
+                                        &crtc->config.requested_mode,
+                                        adjusted_mode);
 
        /* Save the data order, since I don't know what it should be set to. */
        dvo_val = I915_READ(dvo_reg) &
@@ -314,8 +315,6 @@ static void intel_dvo_mode_set(struct drm_encoder *encoder,
        if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
                dvo_val |= DVO_VSYNC_ACTIVE_HIGH;
 
-       I915_WRITE(dpll_reg, I915_READ(dpll_reg) | DPLL_DVO_HIGH_SPEED);
-
        /*I915_WRITE(DVOB_SRCDIM,
          (adjusted_mode->hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) |
          (adjusted_mode->VDisplay << DVO_SRCDIM_VERTICAL_SHIFT));*/
@@ -335,6 +334,8 @@ static enum drm_connector_status
 intel_dvo_detect(struct drm_connector *connector, bool force)
 {
        struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
+                     connector->base.id, drm_get_connector_name(connector));
        return intel_dvo->dev.dev_ops->detect(&intel_dvo->dev);
 }
 
@@ -372,11 +373,6 @@ static void intel_dvo_destroy(struct drm_connector *connector)
        kfree(connector);
 }
 
-static const struct drm_encoder_helper_funcs intel_dvo_helper_funcs = {
-       .mode_fixup = intel_dvo_mode_fixup,
-       .mode_set = intel_dvo_mode_set,
-};
-
 static const struct drm_connector_funcs intel_dvo_connector_funcs = {
        .dpms = intel_dvo_dpms,
        .detect = intel_dvo_detect,
@@ -392,7 +388,7 @@ static const struct drm_connector_helper_funcs intel_dvo_connector_helper_funcs
 
 static void intel_dvo_enc_destroy(struct drm_encoder *encoder)
 {
-       struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
+       struct intel_dvo *intel_dvo = enc_to_dvo(to_intel_encoder(encoder));
 
        if (intel_dvo->dev.dev_ops->destroy)
                intel_dvo->dev.dev_ops->destroy(&intel_dvo->dev);
@@ -471,6 +467,8 @@ void intel_dvo_init(struct drm_device *dev)
        intel_encoder->enable = intel_enable_dvo;
        intel_encoder->get_hw_state = intel_dvo_get_hw_state;
        intel_encoder->get_config = intel_dvo_get_config;
+       intel_encoder->compute_config = intel_dvo_compute_config;
+       intel_encoder->mode_set = intel_dvo_mode_set;
        intel_connector->get_hw_state = intel_dvo_connector_get_hw_state;
 
        /* Now, try to find a controller */
@@ -537,9 +535,6 @@ void intel_dvo_init(struct drm_device *dev)
                connector->interlace_allowed = false;
                connector->doublescan_allowed = false;
 
-               drm_encoder_helper_add(&intel_encoder->base,
-                                      &intel_dvo_helper_funcs);
-
                intel_connector_attach_encoder(intel_connector, intel_encoder);
                if (dvo->type == INTEL_DVO_CHIP_LVDS) {
                        /* For our LVDS chipsets, we should hopefully be able
index dff669e2387f4e5aa8fd84433935e4603ec43992..f3c97e05b0d845b5c046726c2014ad6d741d6b5e 100644 (file)
@@ -139,11 +139,11 @@ static int intelfb_create(struct drm_fb_helper *helper,
        info->apertures->ranges[0].base = dev->mode_config.fb_base;
        info->apertures->ranges[0].size = dev_priv->gtt.mappable_end;
 
-       info->fix.smem_start = dev->mode_config.fb_base + obj->gtt_offset;
+       info->fix.smem_start = dev->mode_config.fb_base + i915_gem_obj_ggtt_offset(obj);
        info->fix.smem_len = size;
 
        info->screen_base =
-               ioremap_wc(dev_priv->gtt.mappable_base + obj->gtt_offset,
+               ioremap_wc(dev_priv->gtt.mappable_base + i915_gem_obj_ggtt_offset(obj),
                           size);
        if (!info->screen_base) {
                ret = -ENOSPC;
@@ -166,9 +166,9 @@ static int intelfb_create(struct drm_fb_helper *helper,
 
        /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
 
-       DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08x, bo %p\n",
+       DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08lx, bo %p\n",
                      fb->width, fb->height,
-                     obj->gtt_offset, obj);
+                     i915_gem_obj_ggtt_offset(obj), obj);
 
 
        mutex_unlock(&dev->struct_mutex);
index 2fd3fd5b943ee57aff93415c707798d9069cea7e..e82cd816bde92985d876c691d21bc275950c1483 100644 (file)
@@ -591,14 +591,13 @@ static void hsw_set_infoframes(struct drm_encoder *encoder,
        intel_hdmi_set_spd_infoframe(encoder);
 }
 
-static void intel_hdmi_mode_set(struct drm_encoder *encoder,
-                               struct drm_display_mode *mode,
-                               struct drm_display_mode *adjusted_mode)
+static void intel_hdmi_mode_set(struct intel_encoder *encoder)
 {
-       struct drm_device *dev = encoder->dev;
+       struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
-       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+       struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
+       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
+       struct drm_display_mode *adjusted_mode = &crtc->config.adjusted_mode;
        u32 hdmi_val;
 
        hdmi_val = SDVO_ENCODING_HDMI;
@@ -609,7 +608,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
        if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
                hdmi_val |= SDVO_HSYNC_ACTIVE_HIGH;
 
-       if (intel_crtc->config.pipe_bpp > 24)
+       if (crtc->config.pipe_bpp > 24)
                hdmi_val |= HDMI_COLOR_FORMAT_12bpc;
        else
                hdmi_val |= SDVO_COLOR_FORMAT_8bpc;
@@ -620,21 +619,21 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
 
        if (intel_hdmi->has_audio) {
                DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n",
-                                pipe_name(intel_crtc->pipe));
+                                pipe_name(crtc->pipe));
                hdmi_val |= SDVO_AUDIO_ENABLE;
                hdmi_val |= HDMI_MODE_SELECT_HDMI;
-               intel_write_eld(encoder, adjusted_mode);
+               intel_write_eld(&encoder->base, adjusted_mode);
        }
 
        if (HAS_PCH_CPT(dev))
-               hdmi_val |= SDVO_PIPE_SEL_CPT(intel_crtc->pipe);
+               hdmi_val |= SDVO_PIPE_SEL_CPT(crtc->pipe);
        else
-               hdmi_val |= SDVO_PIPE_SEL(intel_crtc->pipe);
+               hdmi_val |= SDVO_PIPE_SEL(crtc->pipe);
 
        I915_WRITE(intel_hdmi->hdmi_reg, hdmi_val);
        POSTING_READ(intel_hdmi->hdmi_reg);
 
-       intel_hdmi->set_infoframes(encoder, adjusted_mode);
+       intel_hdmi->set_infoframes(&encoder->base, adjusted_mode);
 }
 
 static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder,
@@ -879,6 +878,9 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
        struct edid *edid;
        enum drm_connector_status status = connector_status_disconnected;
 
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
+                     connector->base.id, drm_get_connector_name(connector));
+
        intel_hdmi->has_hdmi_sink = false;
        intel_hdmi->has_audio = false;
        intel_hdmi->rgb_quant_range_selectable = false;
@@ -1113,10 +1115,6 @@ static void intel_hdmi_destroy(struct drm_connector *connector)
        kfree(connector);
 }
 
-static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = {
-       .mode_set = intel_hdmi_mode_set,
-};
-
 static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
        .dpms = intel_connector_dpms,
        .detect = intel_hdmi_detect,
@@ -1239,9 +1237,9 @@ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port)
 
        drm_encoder_init(dev, &intel_encoder->base, &intel_hdmi_enc_funcs,
                         DRM_MODE_ENCODER_TMDS);
-       drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs);
 
        intel_encoder->compute_config = intel_hdmi_compute_config;
+       intel_encoder->mode_set = intel_hdmi_mode_set;
        intel_encoder->enable = intel_enable_hdmi;
        intel_encoder->disable = intel_disable_hdmi;
        intel_encoder->get_hw_state = intel_hdmi_get_hw_state;
index 61348eae2f0436a05f7b5d88fec4242db918655d..4d33278e31fb805dae4430a5ab493f801a1c6ced 100644 (file)
@@ -122,17 +122,25 @@ static void intel_lvds_get_config(struct intel_encoder *encoder,
  * This is an exception to the general rule that mode_set doesn't turn
  * things on.
  */
-static void intel_pre_pll_enable_lvds(struct intel_encoder *encoder)
+static void intel_pre_enable_lvds(struct intel_encoder *encoder)
 {
        struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
+       struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
        struct drm_display_mode *fixed_mode =
                lvds_encoder->attached_connector->base.panel.fixed_mode;
-       int pipe = intel_crtc->pipe;
+       int pipe = crtc->pipe;
        u32 temp;
 
+       if (HAS_PCH_SPLIT(dev)) {
+               assert_fdi_rx_pll_disabled(dev_priv, pipe);
+               assert_shared_dpll_disabled(dev_priv,
+                                           intel_crtc_to_shared_dpll(crtc));
+       } else {
+               assert_pll_disabled(dev_priv, pipe);
+       }
+
        temp = I915_READ(lvds_encoder->reg);
        temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
 
@@ -149,7 +157,7 @@ static void intel_pre_pll_enable_lvds(struct intel_encoder *encoder)
 
        /* set the corresponsding LVDS_BORDER bit */
        temp &= ~LVDS_BORDER_ENABLE;
-       temp |= intel_crtc->config.gmch_pfit.lvds_border_bits;
+       temp |= crtc->config.gmch_pfit.lvds_border_bits;
        /* Set the B0-B3 data pairs corresponding to whether we're going to
         * set the DPLLs for dual-channel mode or not.
         */
@@ -169,8 +177,7 @@ static void intel_pre_pll_enable_lvds(struct intel_encoder *encoder)
        if (INTEL_INFO(dev)->gen == 4) {
                /* Bspec wording suggests that LVDS port dithering only exists
                 * for 18bpp panels. */
-               if (intel_crtc->config.dither &&
-                   intel_crtc->config.pipe_bpp == 18)
+               if (crtc->config.dither && crtc->config.pipe_bpp == 18)
                        temp |= LVDS_ENABLE_DITHER;
                else
                        temp &= ~LVDS_ENABLE_DITHER;
@@ -312,14 +319,12 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder,
        return true;
 }
 
-static void intel_lvds_mode_set(struct drm_encoder *encoder,
-                               struct drm_display_mode *mode,
-                               struct drm_display_mode *adjusted_mode)
+static void intel_lvds_mode_set(struct intel_encoder *encoder)
 {
        /*
-        * The LVDS pin pair will already have been turned on in the
-        * intel_crtc_mode_set since it has a large impact on the DPLL
-        * settings.
+        * We don't do anything here, the LVDS port is fully set up in the pre
+        * enable hook - the ordering constraints for enabling the lvds port vs.
+        * enabling the display pll are too strict.
         */
 }
 
@@ -336,6 +341,9 @@ intel_lvds_detect(struct drm_connector *connector, bool force)
        struct drm_device *dev = connector->dev;
        enum drm_connector_status status;
 
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
+                     connector->base.id, drm_get_connector_name(connector));
+
        status = intel_panel_detect(dev);
        if (status != connector_status_unknown)
                return status;
@@ -497,10 +505,6 @@ static int intel_lvds_set_property(struct drm_connector *connector,
        return 0;
 }
 
-static const struct drm_encoder_helper_funcs intel_lvds_helper_funcs = {
-       .mode_set = intel_lvds_mode_set,
-};
-
 static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs = {
        .get_modes = intel_lvds_get_modes,
        .mode_valid = intel_lvds_mode_valid,
@@ -959,8 +963,9 @@ void intel_lvds_init(struct drm_device *dev)
                         DRM_MODE_ENCODER_LVDS);
 
        intel_encoder->enable = intel_enable_lvds;
-       intel_encoder->pre_pll_enable = intel_pre_pll_enable_lvds;
+       intel_encoder->pre_enable = intel_pre_enable_lvds;
        intel_encoder->compute_config = intel_lvds_compute_config;
+       intel_encoder->mode_set = intel_lvds_mode_set;
        intel_encoder->disable = intel_disable_lvds;
        intel_encoder->get_hw_state = intel_lvds_get_hw_state;
        intel_encoder->get_config = intel_lvds_get_config;
@@ -977,7 +982,6 @@ void intel_lvds_init(struct drm_device *dev)
        else
                intel_encoder->crtc_mask = (1 << 1);
 
-       drm_encoder_helper_add(encoder, &intel_lvds_helper_funcs);
        drm_connector_helper_add(connector, &intel_lvds_connector_helper_funcs);
        connector->display_info.subpixel_order = SubPixelHorizontalRGB;
        connector->interlace_allowed = false;
index a3698812e9c7831f75048508b4b38ebf93ecce33..9ec5a4e12af2b150717e58b2a42fefece28053e9 100644 (file)
@@ -196,7 +196,7 @@ intel_overlay_map_regs(struct intel_overlay *overlay)
                regs = (struct overlay_registers __iomem *)overlay->reg_bo->phys_obj->handle->vaddr;
        else
                regs = io_mapping_map_wc(dev_priv->gtt.mappable,
-                                        overlay->reg_bo->gtt_offset);
+                                        i915_gem_obj_ggtt_offset(overlay->reg_bo));
 
        return regs;
 }
@@ -740,7 +740,7 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
        swidth = params->src_w;
        swidthsw = calc_swidthsw(overlay->dev, params->offset_Y, tmp_width);
        sheight = params->src_h;
-       iowrite32(new_bo->gtt_offset + params->offset_Y, &regs->OBUF_0Y);
+       iowrite32(i915_gem_obj_ggtt_offset(new_bo) + params->offset_Y, &regs->OBUF_0Y);
        ostride = params->stride_Y;
 
        if (params->format & I915_OVERLAY_YUV_PLANAR) {
@@ -754,8 +754,8 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
                                      params->src_w/uv_hscale);
                swidthsw |= max_t(u32, tmp_U, tmp_V) << 16;
                sheight |= (params->src_h/uv_vscale) << 16;
-               iowrite32(new_bo->gtt_offset + params->offset_U, &regs->OBUF_0U);
-               iowrite32(new_bo->gtt_offset + params->offset_V, &regs->OBUF_0V);
+               iowrite32(i915_gem_obj_ggtt_offset(new_bo) + params->offset_U, &regs->OBUF_0U);
+               iowrite32(i915_gem_obj_ggtt_offset(new_bo) + params->offset_V, &regs->OBUF_0V);
                ostride |= params->stride_UV << 16;
        }
 
@@ -1333,7 +1333,9 @@ void intel_setup_overlay(struct drm_device *dev)
 
        overlay->dev = dev;
 
-       reg_bo = i915_gem_object_create_stolen(dev, PAGE_SIZE);
+       reg_bo = NULL;
+       if (!OVERLAY_NEEDS_PHYSICAL(dev))
+               reg_bo = i915_gem_object_create_stolen(dev, PAGE_SIZE);
        if (reg_bo == NULL)
                reg_bo = i915_gem_alloc_object(dev, PAGE_SIZE);
        if (reg_bo == NULL)
@@ -1355,7 +1357,7 @@ void intel_setup_overlay(struct drm_device *dev)
                        DRM_ERROR("failed to pin overlay register bo\n");
                        goto out_free_bo;
                }
-               overlay->flip_addr = reg_bo->gtt_offset;
+               overlay->flip_addr = i915_gem_obj_ggtt_offset(reg_bo);
 
                ret = i915_gem_object_set_to_gtt_domain(reg_bo, true);
                if (ret) {
@@ -1412,9 +1414,6 @@ void intel_cleanup_overlay(struct drm_device *dev)
        kfree(dev_priv->overlay);
 }
 
-#ifdef CONFIG_DEBUG_FS
-#include <linux/seq_file.h>
-
 struct intel_overlay_error_state {
        struct overlay_registers regs;
        unsigned long base;
@@ -1435,7 +1434,7 @@ intel_overlay_map_regs_atomic(struct intel_overlay *overlay)
                        overlay->reg_bo->phys_obj->handle->vaddr;
        else
                regs = io_mapping_map_atomic_wc(dev_priv->gtt.mappable,
-                                               overlay->reg_bo->gtt_offset);
+                                               i915_gem_obj_ggtt_offset(overlay->reg_bo));
 
        return regs;
 }
@@ -1468,7 +1467,7 @@ intel_overlay_capture_error_state(struct drm_device *dev)
        if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))
                error->base = (__force long)overlay->reg_bo->phys_obj->handle->vaddr;
        else
-               error->base = overlay->reg_bo->gtt_offset;
+               error->base = i915_gem_obj_ggtt_offset(overlay->reg_bo);
 
        regs = intel_overlay_map_regs_atomic(overlay);
        if (!regs)
@@ -1537,4 +1536,3 @@ intel_overlay_print_error_state(struct drm_i915_error_state_buf *m,
        P(UVSCALEV);
 #undef P
 }
-#endif
index 67e2c1f1c9a8309b809c35f32395e26e67236992..01b5a519c43c0bc2dbb59a1a5100259e653fcaa6 100644 (file)
@@ -194,9 +194,6 @@ void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc,
            adjusted_mode->vdisplay == mode->vdisplay)
                goto out;
 
-       drm_mode_set_crtcinfo(adjusted_mode, 0);
-       pipe_config->timings_set = true;
-
        switch (fitting_mode) {
        case DRM_MODE_SCALE_CENTER:
                /*
index 51a2a60f5bfc2b08fc2151f35e27c67477c2bf9c..0a5ba92a4b126b5346a4f666145760ffed65db80 100644 (file)
@@ -30,8 +30,7 @@
 #include "intel_drv.h"
 #include "../../../platform/x86/intel_ips.h"
 #include <linux/module.h>
-
-#define FORCEWAKE_ACK_TIMEOUT_MS 2
+#include <drm/i915_powerwell.h>
 
 /* FBC, or Frame Buffer Compression, is a technique employed to compress the
  * framebuffer contents in-memory, aiming at reducing the required bandwidth
@@ -86,7 +85,7 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
        int plane, i;
        u32 fbc_ctl, fbc_ctl2;
 
-       cfb_pitch = dev_priv->cfb_size / FBC_LL_SIZE;
+       cfb_pitch = dev_priv->fbc.size / FBC_LL_SIZE;
        if (fb->pitches[0] < cfb_pitch)
                cfb_pitch = fb->pitches[0];
 
@@ -217,7 +216,7 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
                   (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) |
                   (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT));
        I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y);
-       I915_WRITE(ILK_FBC_RT_BASE, obj->gtt_offset | ILK_FBC_RT_VALID);
+       I915_WRITE(ILK_FBC_RT_BASE, i915_gem_obj_ggtt_offset(obj) | ILK_FBC_RT_VALID);
        /* enable it... */
        I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
 
@@ -274,7 +273,7 @@ static void gen7_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
        struct drm_i915_gem_object *obj = intel_fb->obj;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
-       I915_WRITE(IVB_FBC_RT_BASE, obj->gtt_offset);
+       I915_WRITE(IVB_FBC_RT_BASE, i915_gem_obj_ggtt_offset(obj));
 
        I915_WRITE(ILK_DPFC_CONTROL, DPFC_CTL_EN | DPFC_CTL_LIMIT_1X |
                   IVB_DPFC_CTL_FENCE_EN |
@@ -325,7 +324,7 @@ static void intel_fbc_work_fn(struct work_struct *__work)
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        mutex_lock(&dev->struct_mutex);
-       if (work == dev_priv->fbc_work) {
+       if (work == dev_priv->fbc.fbc_work) {
                /* Double check that we haven't switched fb without cancelling
                 * the prior work.
                 */
@@ -333,12 +332,12 @@ static void intel_fbc_work_fn(struct work_struct *__work)
                        dev_priv->display.enable_fbc(work->crtc,
                                                     work->interval);
 
-                       dev_priv->cfb_plane = to_intel_crtc(work->crtc)->plane;
-                       dev_priv->cfb_fb = work->crtc->fb->base.id;
-                       dev_priv->cfb_y = work->crtc->y;
+                       dev_priv->fbc.plane = to_intel_crtc(work->crtc)->plane;
+                       dev_priv->fbc.fb_id = work->crtc->fb->base.id;
+                       dev_priv->fbc.y = work->crtc->y;
                }
 
-               dev_priv->fbc_work = NULL;
+               dev_priv->fbc.fbc_work = NULL;
        }
        mutex_unlock(&dev->struct_mutex);
 
@@ -347,28 +346,28 @@ static void intel_fbc_work_fn(struct work_struct *__work)
 
 static void intel_cancel_fbc_work(struct drm_i915_private *dev_priv)
 {
-       if (dev_priv->fbc_work == NULL)
+       if (dev_priv->fbc.fbc_work == NULL)
                return;
 
        DRM_DEBUG_KMS("cancelling pending FBC enable\n");
 
        /* Synchronisation is provided by struct_mutex and checking of
-        * dev_priv->fbc_work, so we can perform the cancellation
+        * dev_priv->fbc.fbc_work, so we can perform the cancellation
         * entirely asynchronously.
         */
-       if (cancel_delayed_work(&dev_priv->fbc_work->work))
+       if (cancel_delayed_work(&dev_priv->fbc.fbc_work->work))
                /* tasklet was killed before being run, clean up */
-               kfree(dev_priv->fbc_work);
+               kfree(dev_priv->fbc.fbc_work);
 
        /* Mark the work as no longer wanted so that if it does
         * wake-up (because the work was already running and waiting
         * for our mutex), it will discover that is no longer
         * necessary to run.
         */
-       dev_priv->fbc_work = NULL;
+       dev_priv->fbc.fbc_work = NULL;
 }
 
-void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
+static void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 {
        struct intel_fbc_work *work;
        struct drm_device *dev = crtc->dev;
@@ -381,6 +380,7 @@ void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 
        work = kzalloc(sizeof *work, GFP_KERNEL);
        if (work == NULL) {
+               DRM_ERROR("Failed to allocate FBC work structure\n");
                dev_priv->display.enable_fbc(crtc, interval);
                return;
        }
@@ -390,9 +390,7 @@ void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
        work->interval = interval;
        INIT_DELAYED_WORK(&work->work, intel_fbc_work_fn);
 
-       dev_priv->fbc_work = work;
-
-       DRM_DEBUG_KMS("scheduling delayed FBC enable\n");
+       dev_priv->fbc.fbc_work = work;
 
        /* Delay the actual enabling to let pageflipping cease and the
         * display to settle before starting the compression. Note that
@@ -404,6 +402,8 @@ void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
         * following the termination of the page-flipping sequence
         * and indeed performing the enable as a co-routine and not
         * waiting synchronously upon the vblank.
+        *
+        * WaFbcWaitForVBlankBeforeEnable:ilk,snb
         */
        schedule_delayed_work(&work->work, msecs_to_jiffies(50));
 }
@@ -418,7 +418,7 @@ void intel_disable_fbc(struct drm_device *dev)
                return;
 
        dev_priv->display.disable_fbc(dev);
-       dev_priv->cfb_plane = -1;
+       dev_priv->fbc.plane = -1;
 }
 
 /**
@@ -448,7 +448,6 @@ void intel_update_fbc(struct drm_device *dev)
        struct drm_framebuffer *fb;
        struct intel_framebuffer *intel_fb;
        struct drm_i915_gem_object *obj;
-       int enable_fbc;
        unsigned int max_hdisplay, max_vdisplay;
 
        if (!i915_powersave)
@@ -471,7 +470,8 @@ void intel_update_fbc(struct drm_device *dev)
                    !to_intel_crtc(tmp_crtc)->primary_disabled) {
                        if (crtc) {
                                DRM_DEBUG_KMS("more than one pipe active, disabling compression\n");
-                               dev_priv->no_fbc_reason = FBC_MULTIPLE_PIPES;
+                               dev_priv->fbc.no_fbc_reason =
+                                       FBC_MULTIPLE_PIPES;
                                goto out_disable;
                        }
                        crtc = tmp_crtc;
@@ -480,7 +480,7 @@ void intel_update_fbc(struct drm_device *dev)
 
        if (!crtc || crtc->fb == NULL) {
                DRM_DEBUG_KMS("no output, disabling\n");
-               dev_priv->no_fbc_reason = FBC_NO_OUTPUT;
+               dev_priv->fbc.no_fbc_reason = FBC_NO_OUTPUT;
                goto out_disable;
        }
 
@@ -489,23 +489,22 @@ void intel_update_fbc(struct drm_device *dev)
        intel_fb = to_intel_framebuffer(fb);
        obj = intel_fb->obj;
 
-       enable_fbc = i915_enable_fbc;
-       if (enable_fbc < 0) {
-               DRM_DEBUG_KMS("fbc set to per-chip default\n");
-               enable_fbc = 1;
-               if (INTEL_INFO(dev)->gen <= 7 && !IS_HASWELL(dev))
-                       enable_fbc = 0;
+       if (i915_enable_fbc < 0 &&
+           INTEL_INFO(dev)->gen <= 7 && !IS_HASWELL(dev)) {
+               DRM_DEBUG_KMS("disabled per chip default\n");
+               dev_priv->fbc.no_fbc_reason = FBC_CHIP_DEFAULT;
+               goto out_disable;
        }
-       if (!enable_fbc) {
+       if (!i915_enable_fbc) {
                DRM_DEBUG_KMS("fbc disabled per module param\n");
-               dev_priv->no_fbc_reason = FBC_MODULE_PARAM;
+               dev_priv->fbc.no_fbc_reason = FBC_MODULE_PARAM;
                goto out_disable;
        }
        if ((crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) ||
            (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)) {
                DRM_DEBUG_KMS("mode incompatible with compression, "
                              "disabling\n");
-               dev_priv->no_fbc_reason = FBC_UNSUPPORTED_MODE;
+               dev_priv->fbc.no_fbc_reason = FBC_UNSUPPORTED_MODE;
                goto out_disable;
        }
 
@@ -519,13 +518,13 @@ void intel_update_fbc(struct drm_device *dev)
        if ((crtc->mode.hdisplay > max_hdisplay) ||
            (crtc->mode.vdisplay > max_vdisplay)) {
                DRM_DEBUG_KMS("mode too large for compression, disabling\n");
-               dev_priv->no_fbc_reason = FBC_MODE_TOO_LARGE;
+               dev_priv->fbc.no_fbc_reason = FBC_MODE_TOO_LARGE;
                goto out_disable;
        }
        if ((IS_I915GM(dev) || IS_I945GM(dev) || IS_HASWELL(dev)) &&
            intel_crtc->plane != 0) {
                DRM_DEBUG_KMS("plane not 0, disabling compression\n");
-               dev_priv->no_fbc_reason = FBC_BAD_PLANE;
+               dev_priv->fbc.no_fbc_reason = FBC_BAD_PLANE;
                goto out_disable;
        }
 
@@ -535,7 +534,7 @@ void intel_update_fbc(struct drm_device *dev)
        if (obj->tiling_mode != I915_TILING_X ||
            obj->fence_reg == I915_FENCE_REG_NONE) {
                DRM_DEBUG_KMS("framebuffer not tiled or fenced, disabling compression\n");
-               dev_priv->no_fbc_reason = FBC_NOT_TILED;
+               dev_priv->fbc.no_fbc_reason = FBC_NOT_TILED;
                goto out_disable;
        }
 
@@ -545,7 +544,7 @@ void intel_update_fbc(struct drm_device *dev)
 
        if (i915_gem_stolen_setup_compression(dev, intel_fb->obj->base.size)) {
                DRM_DEBUG_KMS("framebuffer too large, disabling compression\n");
-               dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
+               dev_priv->fbc.no_fbc_reason = FBC_STOLEN_TOO_SMALL;
                goto out_disable;
        }
 
@@ -554,9 +553,9 @@ void intel_update_fbc(struct drm_device *dev)
         * cannot be unpinned (and have its GTT offset and fence revoked)
         * without first being decoupled from the scanout and FBC disabled.
         */
-       if (dev_priv->cfb_plane == intel_crtc->plane &&
-           dev_priv->cfb_fb == fb->base.id &&
-           dev_priv->cfb_y == crtc->y)
+       if (dev_priv->fbc.plane == intel_crtc->plane &&
+           dev_priv->fbc.fb_id == fb->base.id &&
+           dev_priv->fbc.y == crtc->y)
                return;
 
        if (intel_fbc_enabled(dev)) {
@@ -2468,8 +2467,8 @@ static void hsw_compute_wm_results(struct drm_device *dev,
 
 /* Find the result with the highest level enabled. Check for enable_fbc_wm in
  * case both are at the same level. Prefer r1 in case they're the same. */
-struct hsw_wm_values *hsw_find_best_result(struct hsw_wm_values *r1,
-                                          struct hsw_wm_values *r2)
+static struct hsw_wm_values *hsw_find_best_result(struct hsw_wm_values *r1,
+                                                 struct hsw_wm_values *r2)
 {
        int i, val_r1 = 0, val_r2 = 0;
 
@@ -3076,19 +3075,12 @@ void gen6_set_rps(struct drm_device *dev, u8 val)
  */
 static void vlv_update_rps_cur_delay(struct drm_i915_private *dev_priv)
 {
-       unsigned long timeout = jiffies + msecs_to_jiffies(10);
        u32 pval;
 
        WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
 
-       do {
-               pval = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
-               if (time_after(jiffies, timeout)) {
-                       DRM_DEBUG_DRIVER("timed out waiting for Punit\n");
-                       break;
-               }
-               udelay(10);
-       } while (pval & 1);
+       if (wait_for(((pval = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS)) & GENFREQSTATUS) == 0, 10))
+               DRM_DEBUG_DRIVER("timed out waiting for Punit\n");
 
        pval >>= 8;
 
@@ -3129,13 +3121,10 @@ void valleyview_set_rps(struct drm_device *dev, u8 val)
        trace_intel_gpu_freq_change(vlv_gpu_freq(dev_priv->mem_freq, val));
 }
 
-
-static void gen6_disable_rps(struct drm_device *dev)
+static void gen6_disable_rps_interrupts(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       I915_WRITE(GEN6_RC_CONTROL, 0);
-       I915_WRITE(GEN6_RPNSWREQ, 1 << 31);
        I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
        I915_WRITE(GEN6_PMIER, I915_READ(GEN6_PMIER) & ~GEN6_PM_RPS_EVENTS);
        /* Complete PM interrupt masking here doesn't race with the rps work
@@ -3143,30 +3132,30 @@ static void gen6_disable_rps(struct drm_device *dev)
         * register (PMIMR) to mask PM interrupts. The only risk is in leaving
         * stale bits in PMIIR and PMIMR which gen6_enable_rps will clean up. */
 
-       spin_lock_irq(&dev_priv->rps.lock);
+       spin_lock_irq(&dev_priv->irq_lock);
        dev_priv->rps.pm_iir = 0;
-       spin_unlock_irq(&dev_priv->rps.lock);
+       spin_unlock_irq(&dev_priv->irq_lock);
 
        I915_WRITE(GEN6_PMIIR, GEN6_PM_RPS_EVENTS);
 }
 
-static void valleyview_disable_rps(struct drm_device *dev)
+static void gen6_disable_rps(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        I915_WRITE(GEN6_RC_CONTROL, 0);
-       I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
-       I915_WRITE(GEN6_PMIER, 0);
-       /* Complete PM interrupt masking here doesn't race with the rps work
-        * item again unmasking PM interrupts because that is using a different
-        * register (PMIMR) to mask PM interrupts. The only risk is in leaving
-        * stale bits in PMIIR and PMIMR which gen6_enable_rps will clean up. */
+       I915_WRITE(GEN6_RPNSWREQ, 1 << 31);
 
-       spin_lock_irq(&dev_priv->rps.lock);
-       dev_priv->rps.pm_iir = 0;
-       spin_unlock_irq(&dev_priv->rps.lock);
+       gen6_disable_rps_interrupts(dev);
+}
 
-       I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR));
+static void valleyview_disable_rps(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       I915_WRITE(GEN6_RC_CONTROL, 0);
+
+       gen6_disable_rps_interrupts(dev);
 
        if (dev_priv->vlv_pctx) {
                drm_gem_object_unreference(&dev_priv->vlv_pctx->base);
@@ -3176,6 +3165,10 @@ static void valleyview_disable_rps(struct drm_device *dev)
 
 int intel_enable_rc6(const struct drm_device *dev)
 {
+       /* No RC6 before Ironlake */
+       if (INTEL_INFO(dev)->gen < 5)
+               return 0;
+
        /* Respect the kernel parameter if it is set */
        if (i915_enable_rc6 >= 0)
                return i915_enable_rc6;
@@ -3199,6 +3192,19 @@ int intel_enable_rc6(const struct drm_device *dev)
        return (INTEL_RC6_ENABLE | INTEL_RC6p_ENABLE);
 }
 
+static 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);
+       I915_WRITE(GEN6_PMIMR, I915_READ(GEN6_PMIMR) & ~GEN6_PM_RPS_EVENTS);
+       I915_WRITE(GEN6_PMIIR, GEN6_PM_RPS_EVENTS);
+       spin_unlock_irq(&dev_priv->irq_lock);
+       /* unmask all PM interrupts */
+       I915_WRITE(GEN6_PMINTRMSK, 0);
+}
+
 static void gen6_enable_rps(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3327,17 +3333,7 @@ static void gen6_enable_rps(struct drm_device *dev)
 
        gen6_set_rps(dev_priv->dev, (gt_perf_status & 0xff00) >> 8);
 
-       /* requires MSI enabled */
-       I915_WRITE(GEN6_PMIER, I915_READ(GEN6_PMIER) | GEN6_PM_RPS_EVENTS);
-       spin_lock_irq(&dev_priv->rps.lock);
-       /* FIXME: Our interrupt enabling sequence is bonghits.
-        * dev_priv->rps.pm_iir really should be 0 here. */
-       dev_priv->rps.pm_iir = 0;
-       I915_WRITE(GEN6_PMIMR, I915_READ(GEN6_PMIMR) & ~GEN6_PM_RPS_EVENTS);
-       I915_WRITE(GEN6_PMIIR, GEN6_PM_RPS_EVENTS);
-       spin_unlock_irq(&dev_priv->rps.lock);
-       /* unmask all PM interrupts */
-       I915_WRITE(GEN6_PMINTRMSK, 0);
+       gen6_enable_rps_interrupts(dev);
 
        rc6vids = 0;
        ret = sandybridge_pcode_read(dev_priv, GEN6_PCODE_READ_RC6VIDS, &rc6vids);
@@ -3482,7 +3478,7 @@ static void valleyview_setup_pctx(struct drm_device *dev)
                pcbr_offset = (pcbr & (~4095)) - dev_priv->mm.stolen_base;
                pctx = i915_gem_object_create_stolen_for_preallocated(dev_priv->dev,
                                                                      pcbr_offset,
-                                                                     -1,
+                                                                     I915_GTT_OFFSET_NONE,
                                                                      pctx_size);
                goto out;
        }
@@ -3607,14 +3603,7 @@ static void valleyview_enable_rps(struct drm_device *dev)
 
        valleyview_set_rps(dev_priv->dev, dev_priv->rps.rpe_delay);
 
-       /* requires MSI enabled */
-       I915_WRITE(GEN6_PMIER, GEN6_PM_RPS_EVENTS);
-       spin_lock_irq(&dev_priv->rps.lock);
-       WARN_ON(dev_priv->rps.pm_iir != 0);
-       I915_WRITE(GEN6_PMIMR, 0);
-       spin_unlock_irq(&dev_priv->rps.lock);
-       /* enable all PM interrupts */
-       I915_WRITE(GEN6_PMINTRMSK, 0);
+       gen6_enable_rps_interrupts(dev);
 
        gen6_gt_force_wake_put(dev_priv);
 }
@@ -3708,7 +3697,7 @@ static void ironlake_enable_rc6(struct drm_device *dev)
 
        intel_ring_emit(ring, MI_SUSPEND_FLUSH | MI_SUSPEND_FLUSH_EN);
        intel_ring_emit(ring, MI_SET_CONTEXT);
-       intel_ring_emit(ring, dev_priv->ips.renderctx->gtt_offset |
+       intel_ring_emit(ring, i915_gem_obj_ggtt_offset(dev_priv->ips.renderctx) |
                        MI_MM_SPACE_GTT |
                        MI_SAVE_EXT_STATE_EN |
                        MI_RESTORE_EXT_STATE_EN |
@@ -3731,7 +3720,7 @@ static void ironlake_enable_rc6(struct drm_device *dev)
                return;
        }
 
-       I915_WRITE(PWRCTXA, dev_priv->ips.pwrctx->gtt_offset | PWRCTX_EN);
+       I915_WRITE(PWRCTXA, i915_gem_obj_ggtt_offset(dev_priv->ips.pwrctx) | PWRCTX_EN);
        I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT);
 }
 
@@ -4429,7 +4418,10 @@ static void ironlake_init_clock_gating(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t dspclk_gate = ILK_VRHUNIT_CLOCK_GATE_DISABLE;
 
-       /* Required for FBC */
+       /*
+        * Required for FBC
+        * WaFbcDisableDpfcClockGating:ilk
+        */
        dspclk_gate |= ILK_DPFCRUNIT_CLOCK_GATE_DISABLE |
                   ILK_DPFCUNIT_CLOCK_GATE_DISABLE |
                   ILK_DPFDUNIT_CLOCK_GATE_ENABLE;
@@ -4466,6 +4458,7 @@ static void ironlake_init_clock_gating(struct drm_device *dev)
         * The bit 7,8,9 of 0x42020.
         */
        if (IS_IRONLAKE_M(dev)) {
+               /* WaFbcAsynchFlipDisableFbcQueue:ilk */
                I915_WRITE(ILK_DISPLAY_CHICKEN1,
                           I915_READ(ILK_DISPLAY_CHICKEN1) |
                           ILK_FBCQ_DIS);
@@ -4602,6 +4595,8 @@ static void gen6_init_clock_gating(struct drm_device *dev)
         * The bit5 and bit7 of 0x42020
         * The bit14 of 0x70180
         * The bit14 of 0x71180
+        *
+        * WaFbcAsynchFlipDisableFbcQueue:snb
         */
        I915_WRITE(ILK_DISPLAY_CHICKEN1,
                   I915_READ(ILK_DISPLAY_CHICKEN1) |
@@ -5292,254 +5287,6 @@ void intel_init_pm(struct drm_device *dev)
        }
 }
 
-static void __gen6_gt_wait_for_thread_c0(struct drm_i915_private *dev_priv)
-{
-       u32 gt_thread_status_mask;
-
-       if (IS_HASWELL(dev_priv->dev))
-               gt_thread_status_mask = GEN6_GT_THREAD_STATUS_CORE_MASK_HSW;
-       else
-               gt_thread_status_mask = GEN6_GT_THREAD_STATUS_CORE_MASK;
-
-       /* w/a for a sporadic read returning 0 by waiting for the GT
-        * thread to wake up.
-        */
-       if (wait_for_atomic_us((I915_READ_NOTRACE(GEN6_GT_THREAD_STATUS_REG) & gt_thread_status_mask) == 0, 500))
-               DRM_ERROR("GT thread status wait timed out\n");
-}
-
-static void __gen6_gt_force_wake_reset(struct drm_i915_private *dev_priv)
-{
-       I915_WRITE_NOTRACE(FORCEWAKE, 0);
-       POSTING_READ(ECOBUS); /* something from same cacheline, but !FORCEWAKE */
-}
-
-static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
-{
-       if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK) & 1) == 0,
-                           FORCEWAKE_ACK_TIMEOUT_MS))
-               DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n");
-
-       I915_WRITE_NOTRACE(FORCEWAKE, 1);
-       POSTING_READ(ECOBUS); /* something from same cacheline, but !FORCEWAKE */
-
-       if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK) & 1),
-                           FORCEWAKE_ACK_TIMEOUT_MS))
-               DRM_ERROR("Timed out waiting for forcewake to ack request.\n");
-
-       /* WaRsForcewakeWaitTC0:snb */
-       __gen6_gt_wait_for_thread_c0(dev_priv);
-}
-
-static void __gen6_gt_force_wake_mt_reset(struct drm_i915_private *dev_priv)
-{
-       I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_DISABLE(0xffff));
-       /* something from same cacheline, but !FORCEWAKE_MT */
-       POSTING_READ(ECOBUS);
-}
-
-static void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv)
-{
-       u32 forcewake_ack;
-
-       if (IS_HASWELL(dev_priv->dev))
-               forcewake_ack = FORCEWAKE_ACK_HSW;
-       else
-               forcewake_ack = FORCEWAKE_MT_ACK;
-
-       if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & FORCEWAKE_KERNEL) == 0,
-                           FORCEWAKE_ACK_TIMEOUT_MS))
-               DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n");
-
-       I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL));
-       /* something from same cacheline, but !FORCEWAKE_MT */
-       POSTING_READ(ECOBUS);
-
-       if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & FORCEWAKE_KERNEL),
-                           FORCEWAKE_ACK_TIMEOUT_MS))
-               DRM_ERROR("Timed out waiting for forcewake to ack request.\n");
-
-       /* WaRsForcewakeWaitTC0:ivb,hsw */
-       __gen6_gt_wait_for_thread_c0(dev_priv);
-}
-
-/*
- * Generally this is called implicitly by the register read function. However,
- * if some sequence requires the GT to not power down then this function should
- * be called at the beginning of the sequence followed by a call to
- * gen6_gt_force_wake_put() at the end of the sequence.
- */
-void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
-{
-       unsigned long irqflags;
-
-       spin_lock_irqsave(&dev_priv->gt_lock, irqflags);
-       if (dev_priv->forcewake_count++ == 0)
-               dev_priv->gt.force_wake_get(dev_priv);
-       spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags);
-}
-
-void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv)
-{
-       u32 gtfifodbg;
-       gtfifodbg = I915_READ_NOTRACE(GTFIFODBG);
-       if (WARN(gtfifodbg & GT_FIFO_CPU_ERROR_MASK,
-            "MMIO read or write has been dropped %x\n", gtfifodbg))
-               I915_WRITE_NOTRACE(GTFIFODBG, GT_FIFO_CPU_ERROR_MASK);
-}
-
-static void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
-{
-       I915_WRITE_NOTRACE(FORCEWAKE, 0);
-       /* something from same cacheline, but !FORCEWAKE */
-       POSTING_READ(ECOBUS);
-       gen6_gt_check_fifodbg(dev_priv);
-}
-
-static void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv)
-{
-       I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL));
-       /* something from same cacheline, but !FORCEWAKE_MT */
-       POSTING_READ(ECOBUS);
-       gen6_gt_check_fifodbg(dev_priv);
-}
-
-/*
- * see gen6_gt_force_wake_get()
- */
-void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
-{
-       unsigned long irqflags;
-
-       spin_lock_irqsave(&dev_priv->gt_lock, irqflags);
-       if (--dev_priv->forcewake_count == 0)
-               dev_priv->gt.force_wake_put(dev_priv);
-       spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags);
-}
-
-int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv)
-{
-       int ret = 0;
-
-       if (dev_priv->gt_fifo_count < GT_FIFO_NUM_RESERVED_ENTRIES) {
-               int loop = 500;
-               u32 fifo = I915_READ_NOTRACE(GT_FIFO_FREE_ENTRIES);
-               while (fifo <= GT_FIFO_NUM_RESERVED_ENTRIES && loop--) {
-                       udelay(10);
-                       fifo = I915_READ_NOTRACE(GT_FIFO_FREE_ENTRIES);
-               }
-               if (WARN_ON(loop < 0 && fifo <= GT_FIFO_NUM_RESERVED_ENTRIES))
-                       ++ret;
-               dev_priv->gt_fifo_count = fifo;
-       }
-       dev_priv->gt_fifo_count--;
-
-       return ret;
-}
-
-static void vlv_force_wake_reset(struct drm_i915_private *dev_priv)
-{
-       I915_WRITE_NOTRACE(FORCEWAKE_VLV, _MASKED_BIT_DISABLE(0xffff));
-       /* something from same cacheline, but !FORCEWAKE_VLV */
-       POSTING_READ(FORCEWAKE_ACK_VLV);
-}
-
-static void vlv_force_wake_get(struct drm_i915_private *dev_priv)
-{
-       if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK_VLV) & FORCEWAKE_KERNEL) == 0,
-                           FORCEWAKE_ACK_TIMEOUT_MS))
-               DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n");
-
-       I915_WRITE_NOTRACE(FORCEWAKE_VLV, _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL));
-       I915_WRITE_NOTRACE(FORCEWAKE_MEDIA_VLV,
-                          _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL));
-
-       if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK_VLV) & FORCEWAKE_KERNEL),
-                           FORCEWAKE_ACK_TIMEOUT_MS))
-               DRM_ERROR("Timed out waiting for GT to ack forcewake request.\n");
-
-       if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK_MEDIA_VLV) &
-                            FORCEWAKE_KERNEL),
-                           FORCEWAKE_ACK_TIMEOUT_MS))
-               DRM_ERROR("Timed out waiting for media to ack forcewake request.\n");
-
-       /* WaRsForcewakeWaitTC0:vlv */
-       __gen6_gt_wait_for_thread_c0(dev_priv);
-}
-
-static void vlv_force_wake_put(struct drm_i915_private *dev_priv)
-{
-       I915_WRITE_NOTRACE(FORCEWAKE_VLV, _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL));
-       I915_WRITE_NOTRACE(FORCEWAKE_MEDIA_VLV,
-                          _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL));
-       /* The below doubles as a POSTING_READ */
-       gen6_gt_check_fifodbg(dev_priv);
-}
-
-void intel_gt_sanitize(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       if (IS_VALLEYVIEW(dev)) {
-               vlv_force_wake_reset(dev_priv);
-       } else if (INTEL_INFO(dev)->gen >= 6) {
-               __gen6_gt_force_wake_reset(dev_priv);
-               if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev))
-                       __gen6_gt_force_wake_mt_reset(dev_priv);
-       }
-
-       /* BIOS often leaves RC6 enabled, but disable it for hw init */
-       if (INTEL_INFO(dev)->gen >= 6)
-               intel_disable_gt_powersave(dev);
-}
-
-void intel_gt_init(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       if (IS_VALLEYVIEW(dev)) {
-               dev_priv->gt.force_wake_get = vlv_force_wake_get;
-               dev_priv->gt.force_wake_put = vlv_force_wake_put;
-       } else if (IS_HASWELL(dev)) {
-               dev_priv->gt.force_wake_get = __gen6_gt_force_wake_mt_get;
-               dev_priv->gt.force_wake_put = __gen6_gt_force_wake_mt_put;
-       } else if (IS_IVYBRIDGE(dev)) {
-               u32 ecobus;
-
-               /* IVB configs may use multi-threaded forcewake */
-
-               /* A small trick here - if the bios hasn't configured
-                * MT forcewake, and if the device is in RC6, then
-                * force_wake_mt_get will not wake the device and the
-                * ECOBUS read will return zero. Which will be
-                * (correctly) interpreted by the test below as MT
-                * forcewake being disabled.
-                */
-               mutex_lock(&dev->struct_mutex);
-               __gen6_gt_force_wake_mt_get(dev_priv);
-               ecobus = I915_READ_NOTRACE(ECOBUS);
-               __gen6_gt_force_wake_mt_put(dev_priv);
-               mutex_unlock(&dev->struct_mutex);
-
-               if (ecobus & FORCEWAKE_MT_ENABLE) {
-                       dev_priv->gt.force_wake_get =
-                                               __gen6_gt_force_wake_mt_get;
-                       dev_priv->gt.force_wake_put =
-                                               __gen6_gt_force_wake_mt_put;
-               } else {
-                       DRM_INFO("No MT forcewake available on Ivybridge, this can result in issues\n");
-                       DRM_INFO("when using vblank-synced partial screen updates.\n");
-                       dev_priv->gt.force_wake_get = __gen6_gt_force_wake_get;
-                       dev_priv->gt.force_wake_put = __gen6_gt_force_wake_put;
-               }
-       } else if (IS_GEN6(dev)) {
-               dev_priv->gt.force_wake_get = __gen6_gt_force_wake_get;
-               dev_priv->gt.force_wake_put = __gen6_gt_force_wake_put;
-       }
-       INIT_DELAYED_WORK(&dev_priv->rps.delayed_resume_work,
-                         intel_gen6_powersave_work);
-}
-
 int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u8 mbox, u32 *val)
 {
        WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
@@ -5642,3 +5389,11 @@ int vlv_freq_opcode(int ddr_freq, int val)
        return val;
 }
 
+void intel_pm_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       INIT_DELAYED_WORK(&dev_priv->rps.delayed_resume_work,
+                         intel_gen6_powersave_work);
+}
+
index 664118d8c1d6426353ed97bb61b1113369a7678a..8527ea05124be9d2566a23e974d60136fe478398 100644 (file)
@@ -440,14 +440,14 @@ static int init_ring_common(struct intel_ring_buffer *ring)
         * registers with the above sequence (the readback of the HEAD registers
         * also enforces ordering), otherwise the hw might lose the new ring
         * register values. */
-       I915_WRITE_START(ring, obj->gtt_offset);
+       I915_WRITE_START(ring, i915_gem_obj_ggtt_offset(obj));
        I915_WRITE_CTL(ring,
                        ((ring->size - PAGE_SIZE) & RING_NR_PAGES)
                        | RING_VALID);
 
        /* If the head is still not zero, the ring is dead */
        if (wait_for((I915_READ_CTL(ring) & RING_VALID) != 0 &&
-                    I915_READ_START(ring) == obj->gtt_offset &&
+                    I915_READ_START(ring) == i915_gem_obj_ggtt_offset(obj) &&
                     (I915_READ_HEAD(ring) & HEAD_ADDR) == 0, 50)) {
                DRM_ERROR("%s initialization failed "
                                "ctl %08x head %08x tail %08x start %08x\n",
@@ -505,7 +505,7 @@ init_pipe_control(struct intel_ring_buffer *ring)
        if (ret)
                goto err_unref;
 
-       pc->gtt_offset = obj->gtt_offset;
+       pc->gtt_offset = i915_gem_obj_ggtt_offset(obj);
        pc->cpu_page = kmap(sg_page(obj->pages->sgl));
        if (pc->cpu_page == NULL) {
                ret = -ENOMEM;
@@ -836,7 +836,7 @@ gen5_ring_get_irq(struct intel_ring_buffer *ring)
                return false;
 
        spin_lock_irqsave(&dev_priv->irq_lock, flags);
-       if (ring->irq_refcount.gt++ == 0) {
+       if (ring->irq_refcount++ == 0) {
                dev_priv->gt_irq_mask &= ~ring->irq_enable_mask;
                I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
                POSTING_READ(GTIMR);
@@ -854,7 +854,7 @@ gen5_ring_put_irq(struct intel_ring_buffer *ring)
        unsigned long flags;
 
        spin_lock_irqsave(&dev_priv->irq_lock, flags);
-       if (--ring->irq_refcount.gt == 0) {
+       if (--ring->irq_refcount == 0) {
                dev_priv->gt_irq_mask |= ring->irq_enable_mask;
                I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
                POSTING_READ(GTIMR);
@@ -873,7 +873,7 @@ i9xx_ring_get_irq(struct intel_ring_buffer *ring)
                return false;
 
        spin_lock_irqsave(&dev_priv->irq_lock, flags);
-       if (ring->irq_refcount.gt++ == 0) {
+       if (ring->irq_refcount++ == 0) {
                dev_priv->irq_mask &= ~ring->irq_enable_mask;
                I915_WRITE(IMR, dev_priv->irq_mask);
                POSTING_READ(IMR);
@@ -891,7 +891,7 @@ i9xx_ring_put_irq(struct intel_ring_buffer *ring)
        unsigned long flags;
 
        spin_lock_irqsave(&dev_priv->irq_lock, flags);
-       if (--ring->irq_refcount.gt == 0) {
+       if (--ring->irq_refcount == 0) {
                dev_priv->irq_mask |= ring->irq_enable_mask;
                I915_WRITE(IMR, dev_priv->irq_mask);
                POSTING_READ(IMR);
@@ -910,7 +910,7 @@ i8xx_ring_get_irq(struct intel_ring_buffer *ring)
                return false;
 
        spin_lock_irqsave(&dev_priv->irq_lock, flags);
-       if (ring->irq_refcount.gt++ == 0) {
+       if (ring->irq_refcount++ == 0) {
                dev_priv->irq_mask &= ~ring->irq_enable_mask;
                I915_WRITE16(IMR, dev_priv->irq_mask);
                POSTING_READ16(IMR);
@@ -928,7 +928,7 @@ i8xx_ring_put_irq(struct intel_ring_buffer *ring)
        unsigned long flags;
 
        spin_lock_irqsave(&dev_priv->irq_lock, flags);
-       if (--ring->irq_refcount.gt == 0) {
+       if (--ring->irq_refcount == 0) {
                dev_priv->irq_mask |= ring->irq_enable_mask;
                I915_WRITE16(IMR, dev_priv->irq_mask);
                POSTING_READ16(IMR);
@@ -1021,7 +1021,7 @@ gen6_ring_get_irq(struct intel_ring_buffer *ring)
        gen6_gt_force_wake_get(dev_priv);
 
        spin_lock_irqsave(&dev_priv->irq_lock, flags);
-       if (ring->irq_refcount.gt++ == 0) {
+       if (ring->irq_refcount++ == 0) {
                if (HAS_L3_GPU_CACHE(dev) && ring->id == RCS)
                        I915_WRITE_IMR(ring,
                                       ~(ring->irq_enable_mask |
@@ -1045,7 +1045,7 @@ gen6_ring_put_irq(struct intel_ring_buffer *ring)
        unsigned long flags;
 
        spin_lock_irqsave(&dev_priv->irq_lock, flags);
-       if (--ring->irq_refcount.gt == 0) {
+       if (--ring->irq_refcount == 0) {
                if (HAS_L3_GPU_CACHE(dev) && ring->id == RCS)
                        I915_WRITE_IMR(ring,
                                       ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT);
@@ -1070,14 +1070,14 @@ hsw_vebox_get_irq(struct intel_ring_buffer *ring)
        if (!dev->irq_enabled)
                return false;
 
-       spin_lock_irqsave(&dev_priv->rps.lock, flags);
-       if (ring->irq_refcount.pm++ == 0) {
+       spin_lock_irqsave(&dev_priv->irq_lock, flags);
+       if (ring->irq_refcount++ == 0) {
                u32 pm_imr = I915_READ(GEN6_PMIMR);
                I915_WRITE_IMR(ring, ~ring->irq_enable_mask);
                I915_WRITE(GEN6_PMIMR, pm_imr & ~ring->irq_enable_mask);
                POSTING_READ(GEN6_PMIMR);
        }
-       spin_unlock_irqrestore(&dev_priv->rps.lock, flags);
+       spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
 
        return true;
 }
@@ -1092,14 +1092,14 @@ hsw_vebox_put_irq(struct intel_ring_buffer *ring)
        if (!dev->irq_enabled)
                return;
 
-       spin_lock_irqsave(&dev_priv->rps.lock, flags);
-       if (--ring->irq_refcount.pm == 0) {
+       spin_lock_irqsave(&dev_priv->irq_lock, flags);
+       if (--ring->irq_refcount == 0) {
                u32 pm_imr = I915_READ(GEN6_PMIMR);
                I915_WRITE_IMR(ring, ~0);
                I915_WRITE(GEN6_PMIMR, pm_imr | ring->irq_enable_mask);
                POSTING_READ(GEN6_PMIMR);
        }
-       spin_unlock_irqrestore(&dev_priv->rps.lock, flags);
+       spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
 }
 
 static int
@@ -1144,7 +1144,7 @@ i830_dispatch_execbuffer(struct intel_ring_buffer *ring,
                intel_ring_advance(ring);
        } else {
                struct drm_i915_gem_object *obj = ring->private;
-               u32 cs_offset = obj->gtt_offset;
+               u32 cs_offset = i915_gem_obj_ggtt_offset(obj);
 
                if (len > I830_BATCH_LIMIT)
                        return -ENOSPC;
@@ -1229,7 +1229,7 @@ static int init_status_page(struct intel_ring_buffer *ring)
                goto err_unref;
        }
 
-       ring->status_page.gfx_addr = obj->gtt_offset;
+       ring->status_page.gfx_addr = i915_gem_obj_ggtt_offset(obj);
        ring->status_page.page_addr = kmap(sg_page(obj->pages->sgl));
        if (ring->status_page.page_addr == NULL) {
                ret = -ENOMEM;
@@ -1316,7 +1316,7 @@ static int intel_init_ring_buffer(struct drm_device *dev,
                goto err_unpin;
 
        ring->virtual_start =
-               ioremap_wc(dev_priv->gtt.mappable_base + obj->gtt_offset,
+               ioremap_wc(dev_priv->gtt.mappable_base + i915_gem_obj_ggtt_offset(obj),
                           ring->size);
        if (ring->virtual_start == NULL) {
                DRM_ERROR("Failed to map ringbuffer.\n");
@@ -2008,8 +2008,7 @@ int intel_init_vebox_ring_buffer(struct drm_device *dev)
        ring->add_request = gen6_add_request;
        ring->get_seqno = gen6_ring_get_seqno;
        ring->set_seqno = ring_set_seqno;
-       ring->irq_enable_mask = PM_VEBOX_USER_INTERRUPT |
-               PM_VEBOX_CS_ERROR_INTERRUPT;
+       ring->irq_enable_mask = PM_VEBOX_USER_INTERRUPT;
        ring->irq_get = hsw_vebox_get_irq;
        ring->irq_put = hsw_vebox_put_irq;
        ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer;
index 799f04c9da45a0bc30b19dd841547f75a6d4958e..6e38256d41e1241af7f0f380edcf0508ddee44b6 100644 (file)
@@ -78,10 +78,7 @@ struct  intel_ring_buffer {
         */
        u32             last_retired_head;
 
-       struct {
-               u32     gt; /*  protected by dev_priv->irq_lock */
-               u32     pm; /*  protected by dev_priv->rps.lock (sucks) */
-       } irq_refcount;
+       unsigned irq_refcount; /* protected by dev_priv->irq_lock */
        u32             irq_enable_mask;        /* bitmask to enable ring interrupt */
        u32             trace_irq_seqno;
        u32             sync_seqno[I915_NUM_RINGS-1];
index 2628d56224499307cffa4e409a646122a9578db0..47423f31f82be3e335ae0bf4081c4c256afa8d91 100644 (file)
@@ -202,15 +202,14 @@ struct intel_sdvo_connector {
        u32     cur_dot_crawl,  max_dot_crawl;
 };
 
-static struct intel_sdvo *to_intel_sdvo(struct drm_encoder *encoder)
+static struct intel_sdvo *to_sdvo(struct intel_encoder *encoder)
 {
-       return container_of(encoder, struct intel_sdvo, base.base);
+       return container_of(encoder, struct intel_sdvo, base);
 }
 
 static struct intel_sdvo *intel_attached_sdvo(struct drm_connector *connector)
 {
-       return container_of(intel_attached_encoder(connector),
-                           struct intel_sdvo, base);
+       return to_sdvo(intel_attached_encoder(connector));
 }
 
 static struct intel_sdvo_connector *to_intel_sdvo_connector(struct drm_connector *connector)
@@ -1084,7 +1083,7 @@ static void i9xx_adjust_sdvo_tv_clock(struct intel_crtc_config *pipe_config)
 static bool intel_sdvo_compute_config(struct intel_encoder *encoder,
                                      struct intel_crtc_config *pipe_config)
 {
-       struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
+       struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
        struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
        struct drm_display_mode *mode = &pipe_config->requested_mode;
 
@@ -1154,7 +1153,7 @@ static void intel_sdvo_mode_set(struct intel_encoder *intel_encoder)
        struct drm_display_mode *adjusted_mode =
                &intel_crtc->config.adjusted_mode;
        struct drm_display_mode *mode = &intel_crtc->config.requested_mode;
-       struct intel_sdvo *intel_sdvo = to_intel_sdvo(&intel_encoder->base);
+       struct intel_sdvo *intel_sdvo = to_sdvo(intel_encoder);
        u32 sdvox;
        struct intel_sdvo_in_out_map in_out;
        struct intel_sdvo_dtd input_dtd, output_dtd;
@@ -1292,7 +1291,7 @@ static bool intel_sdvo_get_hw_state(struct intel_encoder *encoder,
 {
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
+       struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
        u16 active_outputs = 0;
        u32 tmp;
 
@@ -1315,7 +1314,7 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder,
 {
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
+       struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
        struct intel_sdvo_dtd dtd;
        int encoder_pixel_multiplier = 0;
        u32 flags = 0, sdvox;
@@ -1357,22 +1356,21 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder,
        }
 
        /* Cross check the port pixel multiplier with the sdvo encoder state. */
-       intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_CLOCK_RATE_MULT, &val, 1);
-       switch (val) {
-       case SDVO_CLOCK_RATE_MULT_1X:
-               encoder_pixel_multiplier = 1;
-               break;
-       case SDVO_CLOCK_RATE_MULT_2X:
-               encoder_pixel_multiplier = 2;
-               break;
-       case SDVO_CLOCK_RATE_MULT_4X:
-               encoder_pixel_multiplier = 4;
-               break;
+       if (intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_CLOCK_RATE_MULT,
+                                &val, 1)) {
+               switch (val) {
+               case SDVO_CLOCK_RATE_MULT_1X:
+                       encoder_pixel_multiplier = 1;
+                       break;
+               case SDVO_CLOCK_RATE_MULT_2X:
+                       encoder_pixel_multiplier = 2;
+                       break;
+               case SDVO_CLOCK_RATE_MULT_4X:
+                       encoder_pixel_multiplier = 4;
+                       break;
+               }
        }
 
-       if(HAS_PCH_SPLIT(dev))
-               return; /* no pixel multiplier readout support yet */
-
        WARN(encoder_pixel_multiplier != pipe_config->pixel_multiplier,
             "SDVO pixel multiplier mismatch, port: %i, encoder: %i\n",
             pipe_config->pixel_multiplier, encoder_pixel_multiplier);
@@ -1381,7 +1379,7 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder,
 static void intel_disable_sdvo(struct intel_encoder *encoder)
 {
        struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
-       struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
+       struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
        u32 temp;
 
        intel_sdvo_set_active_outputs(intel_sdvo, 0);
@@ -1423,7 +1421,7 @@ static void intel_enable_sdvo(struct intel_encoder *encoder)
 {
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
+       struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
        struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
        u32 temp;
        bool input1, input2;
@@ -1584,7 +1582,7 @@ static uint16_t intel_sdvo_get_hotplug_support(struct intel_sdvo *intel_sdvo)
 
 static void intel_sdvo_enable_hotplug(struct intel_encoder *encoder)
 {
-       struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
+       struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
 
        intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG,
                        &intel_sdvo->hotplug_active, 2);
@@ -1697,6 +1695,9 @@ intel_sdvo_detect(struct drm_connector *connector, bool force)
        struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
        enum drm_connector_status ret;
 
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
+                     connector->base.id, drm_get_connector_name(connector));
+
        if (!intel_sdvo_get_value(intel_sdvo,
                                  SDVO_CMD_GET_ATTACHED_DISPLAYS,
                                  &response, 2))
@@ -2188,7 +2189,7 @@ static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs
 
 static void intel_sdvo_enc_destroy(struct drm_encoder *encoder)
 {
-       struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder);
+       struct intel_sdvo *intel_sdvo = to_sdvo(to_intel_encoder(encoder));
 
        if (intel_sdvo->sdvo_lvds_fixed_mode != NULL)
                drm_mode_destroy(encoder->dev,
index 1fa5612a4572cc0c3b92a3d6a253bc9f1da573ed..55bdf70b548be5c461146c0f8fe3c7155d9decec 100644 (file)
@@ -133,7 +133,7 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_framebuffer *fb,
 
        I915_WRITE(SPSIZE(pipe, plane), (crtc_h << 16) | crtc_w);
        I915_WRITE(SPCNTR(pipe, plane), sprctl);
-       I915_MODIFY_DISPBASE(SPSURF(pipe, plane), obj->gtt_offset +
+       I915_MODIFY_DISPBASE(SPSURF(pipe, plane), i915_gem_obj_ggtt_offset(obj) +
                             sprsurf_offset);
        POSTING_READ(SPSURF(pipe, plane));
 }
@@ -308,7 +308,8 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
        if (intel_plane->can_scale)
                I915_WRITE(SPRSCALE(pipe), sprscale);
        I915_WRITE(SPRCTL(pipe), sprctl);
-       I915_MODIFY_DISPBASE(SPRSURF(pipe), obj->gtt_offset + sprsurf_offset);
+       I915_MODIFY_DISPBASE(SPRSURF(pipe),
+                            i915_gem_obj_ggtt_offset(obj) + sprsurf_offset);
        POSTING_READ(SPRSURF(pipe));
 
        /* potentially re-enable LP watermarks */
@@ -478,7 +479,8 @@ ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
        I915_WRITE(DVSSIZE(pipe), (crtc_h << 16) | crtc_w);
        I915_WRITE(DVSSCALE(pipe), dvsscale);
        I915_WRITE(DVSCNTR(pipe), dvscntr);
-       I915_MODIFY_DISPBASE(DVSSURF(pipe), obj->gtt_offset + dvssurf_offset);
+       I915_MODIFY_DISPBASE(DVSSURF(pipe),
+                            i915_gem_obj_ggtt_offset(obj) + dvssurf_offset);
        POSTING_READ(DVSSURF(pipe));
 }
 
index 39debd80d190241836e89b8c6794bdb713e80653..f2c6d7909ae2d66ffa73ebe77d7c3b06d46403f7 100644 (file)
@@ -823,16 +823,14 @@ static const struct tv_mode tv_modes[] = {
        },
 };
 
-static struct intel_tv *enc_to_intel_tv(struct drm_encoder *encoder)
+static struct intel_tv *enc_to_tv(struct intel_encoder *encoder)
 {
-       return container_of(encoder, struct intel_tv, base.base);
+       return container_of(encoder, struct intel_tv, base);
 }
 
 static struct intel_tv *intel_attached_tv(struct drm_connector *connector)
 {
-       return container_of(intel_attached_encoder(connector),
-                           struct intel_tv,
-                           base);
+       return enc_to_tv(intel_attached_encoder(connector));
 }
 
 static bool
@@ -908,7 +906,7 @@ static bool
 intel_tv_compute_config(struct intel_encoder *encoder,
                        struct intel_crtc_config *pipe_config)
 {
-       struct intel_tv *intel_tv = enc_to_intel_tv(&encoder->base);
+       struct intel_tv *intel_tv = enc_to_tv(encoder);
        const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
 
        if (!tv_mode)
@@ -921,15 +919,12 @@ intel_tv_compute_config(struct intel_encoder *encoder,
        return true;
 }
 
-static void
-intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
-                 struct drm_display_mode *adjusted_mode)
+static void intel_tv_mode_set(struct intel_encoder *encoder)
 {
-       struct drm_device *dev = encoder->dev;
+       struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_crtc *crtc = encoder->crtc;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
+       struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
+       struct intel_tv *intel_tv = enc_to_tv(encoder);
        const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
        u32 tv_ctl;
        u32 hctl1, hctl2, hctl3;
@@ -1305,6 +1300,10 @@ intel_tv_detect(struct drm_connector *connector, bool force)
        struct intel_tv *intel_tv = intel_attached_tv(connector);
        int type;
 
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force=%d\n",
+                     connector->base.id, drm_get_connector_name(connector),
+                     force);
+
        mode = reported_modes[0];
 
        if (force) {
@@ -1483,10 +1482,6 @@ out:
        return ret;
 }
 
-static const struct drm_encoder_helper_funcs intel_tv_helper_funcs = {
-       .mode_set = intel_tv_mode_set,
-};
-
 static const struct drm_connector_funcs intel_tv_connector_funcs = {
        .dpms = intel_connector_dpms,
        .detect = intel_tv_detect,
@@ -1619,6 +1614,7 @@ intel_tv_init(struct drm_device *dev)
                         DRM_MODE_ENCODER_TVDAC);
 
        intel_encoder->compute_config = intel_tv_compute_config;
+       intel_encoder->mode_set = intel_tv_mode_set;
        intel_encoder->enable = intel_enable_tv;
        intel_encoder->disable = intel_disable_tv;
        intel_encoder->get_hw_state = intel_tv_get_hw_state;
@@ -1640,7 +1636,6 @@ intel_tv_init(struct drm_device *dev)
 
        intel_tv->tv_format = tv_modes[initial_mode].name;
 
-       drm_encoder_helper_add(&intel_encoder->base, &intel_tv_helper_funcs);
        drm_connector_helper_add(connector, &intel_tv_connector_helper_funcs);
        connector->interlace_allowed = false;
        connector->doublescan_allowed = false;
diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c
new file mode 100644 (file)
index 0000000..8f5bc86
--- /dev/null
@@ -0,0 +1,595 @@
+/*
+ * Copyright Â© 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "i915_drv.h"
+#include "intel_drv.h"
+
+#define FORCEWAKE_ACK_TIMEOUT_MS 2
+
+#define __raw_i915_read8(dev_priv__, reg__) readb((dev_priv__)->regs + (reg__))
+#define __raw_i915_write8(dev_priv__, reg__, val__) writeb(val__, (dev_priv__)->regs + (reg__))
+
+#define __raw_i915_read16(dev_priv__, reg__) readw((dev_priv__)->regs + (reg__))
+#define __raw_i915_write16(dev_priv__, reg__, val__) writew(val__, (dev_priv__)->regs + (reg__))
+
+#define __raw_i915_read32(dev_priv__, reg__) readl((dev_priv__)->regs + (reg__))
+#define __raw_i915_write32(dev_priv__, reg__, val__) writel(val__, (dev_priv__)->regs + (reg__))
+
+#define __raw_i915_read64(dev_priv__, reg__) readq((dev_priv__)->regs + (reg__))
+#define __raw_i915_write64(dev_priv__, reg__, val__) writeq(val__, (dev_priv__)->regs + (reg__))
+
+#define __raw_posting_read(dev_priv__, reg__) (void)__raw_i915_read32(dev_priv__, reg__)
+
+
+static void __gen6_gt_wait_for_thread_c0(struct drm_i915_private *dev_priv)
+{
+       u32 gt_thread_status_mask;
+
+       if (IS_HASWELL(dev_priv->dev))
+               gt_thread_status_mask = GEN6_GT_THREAD_STATUS_CORE_MASK_HSW;
+       else
+               gt_thread_status_mask = GEN6_GT_THREAD_STATUS_CORE_MASK;
+
+       /* w/a for a sporadic read returning 0 by waiting for the GT
+        * thread to wake up.
+        */
+       if (wait_for_atomic_us((__raw_i915_read32(dev_priv, GEN6_GT_THREAD_STATUS_REG) & gt_thread_status_mask) == 0, 500))
+               DRM_ERROR("GT thread status wait timed out\n");
+}
+
+static void __gen6_gt_force_wake_reset(struct drm_i915_private *dev_priv)
+{
+       __raw_i915_write32(dev_priv, FORCEWAKE, 0);
+       /* something from same cacheline, but !FORCEWAKE */
+       __raw_posting_read(dev_priv, ECOBUS);
+}
+
+static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
+{
+       if (wait_for_atomic((__raw_i915_read32(dev_priv, FORCEWAKE_ACK) & 1) == 0,
+                           FORCEWAKE_ACK_TIMEOUT_MS))
+               DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n");
+
+       __raw_i915_write32(dev_priv, FORCEWAKE, 1);
+       /* something from same cacheline, but !FORCEWAKE */
+       __raw_posting_read(dev_priv, ECOBUS);
+
+       if (wait_for_atomic((__raw_i915_read32(dev_priv, FORCEWAKE_ACK) & 1),
+                           FORCEWAKE_ACK_TIMEOUT_MS))
+               DRM_ERROR("Timed out waiting for forcewake to ack request.\n");
+
+       /* WaRsForcewakeWaitTC0:snb */
+       __gen6_gt_wait_for_thread_c0(dev_priv);
+}
+
+static void __gen6_gt_force_wake_mt_reset(struct drm_i915_private *dev_priv)
+{
+       __raw_i915_write32(dev_priv, FORCEWAKE_MT, _MASKED_BIT_DISABLE(0xffff));
+       /* something from same cacheline, but !FORCEWAKE_MT */
+       __raw_posting_read(dev_priv, ECOBUS);
+}
+
+static void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv)
+{
+       u32 forcewake_ack;
+
+       if (IS_HASWELL(dev_priv->dev))
+               forcewake_ack = FORCEWAKE_ACK_HSW;
+       else
+               forcewake_ack = FORCEWAKE_MT_ACK;
+
+       if (wait_for_atomic((__raw_i915_read32(dev_priv, forcewake_ack) & FORCEWAKE_KERNEL) == 0,
+                           FORCEWAKE_ACK_TIMEOUT_MS))
+               DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n");
+
+       __raw_i915_write32(dev_priv, FORCEWAKE_MT,
+                          _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL));
+       /* something from same cacheline, but !FORCEWAKE_MT */
+       __raw_posting_read(dev_priv, ECOBUS);
+
+       if (wait_for_atomic((__raw_i915_read32(dev_priv, forcewake_ack) & FORCEWAKE_KERNEL),
+                           FORCEWAKE_ACK_TIMEOUT_MS))
+               DRM_ERROR("Timed out waiting for forcewake to ack request.\n");
+
+       /* WaRsForcewakeWaitTC0:ivb,hsw */
+       __gen6_gt_wait_for_thread_c0(dev_priv);
+}
+
+static void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv)
+{
+       u32 gtfifodbg;
+
+       gtfifodbg = __raw_i915_read32(dev_priv, GTFIFODBG);
+       if (WARN(gtfifodbg & GT_FIFO_CPU_ERROR_MASK,
+            "MMIO read or write has been dropped %x\n", gtfifodbg))
+               __raw_i915_write32(dev_priv, GTFIFODBG, GT_FIFO_CPU_ERROR_MASK);
+}
+
+static void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
+{
+       __raw_i915_write32(dev_priv, FORCEWAKE, 0);
+       /* something from same cacheline, but !FORCEWAKE */
+       __raw_posting_read(dev_priv, ECOBUS);
+       gen6_gt_check_fifodbg(dev_priv);
+}
+
+static void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv)
+{
+       __raw_i915_write32(dev_priv, FORCEWAKE_MT,
+                          _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL));
+       /* something from same cacheline, but !FORCEWAKE_MT */
+       __raw_posting_read(dev_priv, ECOBUS);
+       gen6_gt_check_fifodbg(dev_priv);
+}
+
+static int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv)
+{
+       int ret = 0;
+
+       if (dev_priv->uncore.fifo_count < GT_FIFO_NUM_RESERVED_ENTRIES) {
+               int loop = 500;
+               u32 fifo = __raw_i915_read32(dev_priv, GT_FIFO_FREE_ENTRIES);
+               while (fifo <= GT_FIFO_NUM_RESERVED_ENTRIES && loop--) {
+                       udelay(10);
+                       fifo = __raw_i915_read32(dev_priv, GT_FIFO_FREE_ENTRIES);
+               }
+               if (WARN_ON(loop < 0 && fifo <= GT_FIFO_NUM_RESERVED_ENTRIES))
+                       ++ret;
+               dev_priv->uncore.fifo_count = fifo;
+       }
+       dev_priv->uncore.fifo_count--;
+
+       return ret;
+}
+
+static void vlv_force_wake_reset(struct drm_i915_private *dev_priv)
+{
+       __raw_i915_write32(dev_priv, FORCEWAKE_VLV,
+                          _MASKED_BIT_DISABLE(0xffff));
+       /* something from same cacheline, but !FORCEWAKE_VLV */
+       __raw_posting_read(dev_priv, FORCEWAKE_ACK_VLV);
+}
+
+static void vlv_force_wake_get(struct drm_i915_private *dev_priv)
+{
+       if (wait_for_atomic((__raw_i915_read32(dev_priv, FORCEWAKE_ACK_VLV) & FORCEWAKE_KERNEL) == 0,
+                           FORCEWAKE_ACK_TIMEOUT_MS))
+               DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n");
+
+       __raw_i915_write32(dev_priv, FORCEWAKE_VLV,
+                          _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL));
+       __raw_i915_write32(dev_priv, FORCEWAKE_MEDIA_VLV,
+                          _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL));
+
+       if (wait_for_atomic((__raw_i915_read32(dev_priv, FORCEWAKE_ACK_VLV) & FORCEWAKE_KERNEL),
+                           FORCEWAKE_ACK_TIMEOUT_MS))
+               DRM_ERROR("Timed out waiting for GT to ack forcewake request.\n");
+
+       if (wait_for_atomic((__raw_i915_read32(dev_priv, FORCEWAKE_ACK_MEDIA_VLV) &
+                            FORCEWAKE_KERNEL),
+                           FORCEWAKE_ACK_TIMEOUT_MS))
+               DRM_ERROR("Timed out waiting for media to ack forcewake request.\n");
+
+       /* WaRsForcewakeWaitTC0:vlv */
+       __gen6_gt_wait_for_thread_c0(dev_priv);
+}
+
+static void vlv_force_wake_put(struct drm_i915_private *dev_priv)
+{
+       __raw_i915_write32(dev_priv, FORCEWAKE_VLV,
+                          _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL));
+       __raw_i915_write32(dev_priv, FORCEWAKE_MEDIA_VLV,
+                          _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL));
+       /* The below doubles as a POSTING_READ */
+       gen6_gt_check_fifodbg(dev_priv);
+}
+
+void intel_uncore_early_sanitize(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (HAS_FPGA_DBG_UNCLAIMED(dev))
+               __raw_i915_write32(dev_priv, FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
+}
+
+void intel_uncore_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (IS_VALLEYVIEW(dev)) {
+               dev_priv->uncore.funcs.force_wake_get = vlv_force_wake_get;
+               dev_priv->uncore.funcs.force_wake_put = vlv_force_wake_put;
+       } else if (IS_HASWELL(dev)) {
+               dev_priv->uncore.funcs.force_wake_get = __gen6_gt_force_wake_mt_get;
+               dev_priv->uncore.funcs.force_wake_put = __gen6_gt_force_wake_mt_put;
+       } else if (IS_IVYBRIDGE(dev)) {
+               u32 ecobus;
+
+               /* IVB configs may use multi-threaded forcewake */
+
+               /* A small trick here - if the bios hasn't configured
+                * MT forcewake, and if the device is in RC6, then
+                * force_wake_mt_get will not wake the device and the
+                * ECOBUS read will return zero. Which will be
+                * (correctly) interpreted by the test below as MT
+                * forcewake being disabled.
+                */
+               mutex_lock(&dev->struct_mutex);
+               __gen6_gt_force_wake_mt_get(dev_priv);
+               ecobus = __raw_i915_read32(dev_priv, ECOBUS);
+               __gen6_gt_force_wake_mt_put(dev_priv);
+               mutex_unlock(&dev->struct_mutex);
+
+               if (ecobus & FORCEWAKE_MT_ENABLE) {
+                       dev_priv->uncore.funcs.force_wake_get =
+                               __gen6_gt_force_wake_mt_get;
+                       dev_priv->uncore.funcs.force_wake_put =
+                               __gen6_gt_force_wake_mt_put;
+               } else {
+                       DRM_INFO("No MT forcewake available on Ivybridge, this can result in issues\n");
+                       DRM_INFO("when using vblank-synced partial screen updates.\n");
+                       dev_priv->uncore.funcs.force_wake_get =
+                               __gen6_gt_force_wake_get;
+                       dev_priv->uncore.funcs.force_wake_put =
+                               __gen6_gt_force_wake_put;
+               }
+       } else if (IS_GEN6(dev)) {
+               dev_priv->uncore.funcs.force_wake_get =
+                       __gen6_gt_force_wake_get;
+               dev_priv->uncore.funcs.force_wake_put =
+                       __gen6_gt_force_wake_put;
+       }
+}
+
+void intel_uncore_sanitize(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (IS_VALLEYVIEW(dev)) {
+               vlv_force_wake_reset(dev_priv);
+       } else if (INTEL_INFO(dev)->gen >= 6) {
+               __gen6_gt_force_wake_reset(dev_priv);
+               if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev))
+                       __gen6_gt_force_wake_mt_reset(dev_priv);
+       }
+
+       /* BIOS often leaves RC6 enabled, but disable it for hw init */
+       intel_disable_gt_powersave(dev);
+}
+
+/*
+ * Generally this is called implicitly by the register read function. However,
+ * if some sequence requires the GT to not power down then this function should
+ * be called at the beginning of the sequence followed by a call to
+ * gen6_gt_force_wake_put() at the end of the sequence.
+ */
+void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
+{
+       unsigned long irqflags;
+
+       spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+       if (dev_priv->uncore.forcewake_count++ == 0)
+               dev_priv->uncore.funcs.force_wake_get(dev_priv);
+       spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
+}
+
+/*
+ * see gen6_gt_force_wake_get()
+ */
+void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
+{
+       unsigned long irqflags;
+
+       spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+       if (--dev_priv->uncore.forcewake_count == 0)
+               dev_priv->uncore.funcs.force_wake_put(dev_priv);
+       spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
+}
+
+/* We give fast paths for the really cool registers */
+#define NEEDS_FORCE_WAKE(dev_priv, reg) \
+       ((HAS_FORCE_WAKE((dev_priv)->dev)) && \
+        ((reg) < 0x40000) &&            \
+        ((reg) != FORCEWAKE))
+
+static void
+ilk_dummy_write(struct drm_i915_private *dev_priv)
+{
+       /* WaIssueDummyWriteToWakeupFromRC6:ilk Issue a dummy write to wake up
+        * the chip from rc6 before touching it for real. MI_MODE is masked,
+        * hence harmless to write 0 into. */
+       __raw_i915_write32(dev_priv, MI_MODE, 0);
+}
+
+static void
+hsw_unclaimed_reg_clear(struct drm_i915_private *dev_priv, u32 reg)
+{
+       if (HAS_FPGA_DBG_UNCLAIMED(dev_priv->dev) &&
+           (__raw_i915_read32(dev_priv, FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) {
+               DRM_ERROR("Unknown unclaimed register before writing to %x\n",
+                         reg);
+               __raw_i915_write32(dev_priv, FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
+       }
+}
+
+static void
+hsw_unclaimed_reg_check(struct drm_i915_private *dev_priv, u32 reg)
+{
+       if (HAS_FPGA_DBG_UNCLAIMED(dev_priv->dev) &&
+           (__raw_i915_read32(dev_priv, FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) {
+               DRM_ERROR("Unclaimed write to %x\n", reg);
+               __raw_i915_write32(dev_priv, FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
+       }
+}
+
+#define __i915_read(x) \
+u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg, bool trace) { \
+       unsigned long irqflags; \
+       u##x val = 0; \
+       spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); \
+       if (dev_priv->info->gen == 5) \
+               ilk_dummy_write(dev_priv); \
+       if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
+               if (dev_priv->uncore.forcewake_count == 0) \
+                       dev_priv->uncore.funcs.force_wake_get(dev_priv); \
+               val = __raw_i915_read##x(dev_priv, reg); \
+               if (dev_priv->uncore.forcewake_count == 0) \
+                       dev_priv->uncore.funcs.force_wake_put(dev_priv); \
+       } else { \
+               val = __raw_i915_read##x(dev_priv, reg); \
+       } \
+       spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \
+       trace_i915_reg_rw(false, reg, val, sizeof(val), trace); \
+       return val; \
+}
+
+__i915_read(8)
+__i915_read(16)
+__i915_read(32)
+__i915_read(64)
+#undef __i915_read
+
+#define __i915_write(x) \
+void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val, bool trace) { \
+       unsigned long irqflags; \
+       u32 __fifo_ret = 0; \
+       trace_i915_reg_rw(true, reg, val, sizeof(val), trace); \
+       spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); \
+       if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
+               __fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \
+       } \
+       if (dev_priv->info->gen == 5) \
+               ilk_dummy_write(dev_priv); \
+       hsw_unclaimed_reg_clear(dev_priv, reg); \
+       __raw_i915_write##x(dev_priv, reg, val); \
+       if (unlikely(__fifo_ret)) { \
+               gen6_gt_check_fifodbg(dev_priv); \
+       } \
+       hsw_unclaimed_reg_check(dev_priv, reg); \
+       spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \
+}
+__i915_write(8)
+__i915_write(16)
+__i915_write(32)
+__i915_write(64)
+#undef __i915_write
+
+static const struct register_whitelist {
+       uint64_t offset;
+       uint32_t size;
+       uint32_t gen_bitmask; /* support gens, 0x10 for 4, 0x30 for 4 and 5, etc. */
+} whitelist[] = {
+       { RING_TIMESTAMP(RENDER_RING_BASE), 8, 0xF0 },
+};
+
+int i915_reg_read_ioctl(struct drm_device *dev,
+                       void *data, struct drm_file *file)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_reg_read *reg = data;
+       struct register_whitelist const *entry = whitelist;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(whitelist); i++, entry++) {
+               if (entry->offset == reg->offset &&
+                   (1 << INTEL_INFO(dev)->gen & entry->gen_bitmask))
+                       break;
+       }
+
+       if (i == ARRAY_SIZE(whitelist))
+               return -EINVAL;
+
+       switch (entry->size) {
+       case 8:
+               reg->val = I915_READ64(reg->offset);
+               break;
+       case 4:
+               reg->val = I915_READ(reg->offset);
+               break;
+       case 2:
+               reg->val = I915_READ16(reg->offset);
+               break;
+       case 1:
+               reg->val = I915_READ8(reg->offset);
+               break;
+       default:
+               WARN_ON(1);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int i8xx_do_reset(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (IS_I85X(dev))
+               return -ENODEV;
+
+       I915_WRITE(D_STATE, I915_READ(D_STATE) | DSTATE_GFX_RESET_I830);
+       POSTING_READ(D_STATE);
+
+       if (IS_I830(dev) || IS_845G(dev)) {
+               I915_WRITE(DEBUG_RESET_I830,
+                          DEBUG_RESET_DISPLAY |
+                          DEBUG_RESET_RENDER |
+                          DEBUG_RESET_FULL);
+               POSTING_READ(DEBUG_RESET_I830);
+               msleep(1);
+
+               I915_WRITE(DEBUG_RESET_I830, 0);
+               POSTING_READ(DEBUG_RESET_I830);
+       }
+
+       msleep(1);
+
+       I915_WRITE(D_STATE, I915_READ(D_STATE) & ~DSTATE_GFX_RESET_I830);
+       POSTING_READ(D_STATE);
+
+       return 0;
+}
+
+static int i965_reset_complete(struct drm_device *dev)
+{
+       u8 gdrst;
+       pci_read_config_byte(dev->pdev, I965_GDRST, &gdrst);
+       return (gdrst & GRDOM_RESET_ENABLE) == 0;
+}
+
+static int i965_do_reset(struct drm_device *dev)
+{
+       int ret;
+
+       /*
+        * Set the domains we want to reset (GRDOM/bits 2 and 3) as
+        * well as the reset bit (GR/bit 0).  Setting the GR bit
+        * triggers the reset; when done, the hardware will clear it.
+        */
+       pci_write_config_byte(dev->pdev, I965_GDRST,
+                             GRDOM_RENDER | GRDOM_RESET_ENABLE);
+       ret =  wait_for(i965_reset_complete(dev), 500);
+       if (ret)
+               return ret;
+
+       /* We can't reset render&media without also resetting display ... */
+       pci_write_config_byte(dev->pdev, I965_GDRST,
+                             GRDOM_MEDIA | GRDOM_RESET_ENABLE);
+
+       ret =  wait_for(i965_reset_complete(dev), 500);
+       if (ret)
+               return ret;
+
+       pci_write_config_byte(dev->pdev, I965_GDRST, 0);
+
+       return 0;
+}
+
+static int ironlake_do_reset(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 gdrst;
+       int ret;
+
+       gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR);
+       gdrst &= ~GRDOM_MASK;
+       I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR,
+                  gdrst | GRDOM_RENDER | GRDOM_RESET_ENABLE);
+       ret = wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500);
+       if (ret)
+               return ret;
+
+       /* We can't reset render&media without also resetting display ... */
+       gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR);
+       gdrst &= ~GRDOM_MASK;
+       I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR,
+                  gdrst | GRDOM_MEDIA | GRDOM_RESET_ENABLE);
+       return wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500);
+}
+
+static int gen6_do_reset(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int     ret;
+       unsigned long irqflags;
+
+       /* Hold uncore.lock across reset to prevent any register access
+        * with forcewake not set correctly
+        */
+       spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+
+       /* Reset the chip */
+
+       /* GEN6_GDRST is not in the gt power well, no need to check
+        * for fifo space for the write or forcewake the chip for
+        * the read
+        */
+       __raw_i915_write32(dev_priv, GEN6_GDRST, GEN6_GRDOM_FULL);
+
+       /* Spin waiting for the device to ack the reset request */
+       ret = wait_for((__raw_i915_read32(dev_priv, GEN6_GDRST) & GEN6_GRDOM_FULL) == 0, 500);
+
+       /* If reset with a user forcewake, try to restore, otherwise turn it off */
+       if (dev_priv->uncore.forcewake_count)
+               dev_priv->uncore.funcs.force_wake_get(dev_priv);
+       else
+               dev_priv->uncore.funcs.force_wake_put(dev_priv);
+
+       /* Restore fifo count */
+       dev_priv->uncore.fifo_count = __raw_i915_read32(dev_priv, GT_FIFO_FREE_ENTRIES);
+
+       spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
+       return ret;
+}
+
+int intel_gpu_reset(struct drm_device *dev)
+{
+       switch (INTEL_INFO(dev)->gen) {
+       case 7:
+       case 6: return gen6_do_reset(dev);
+       case 5: return ironlake_do_reset(dev);
+       case 4: return i965_do_reset(dev);
+       case 2: return i8xx_do_reset(dev);
+       default: return -ENODEV;
+       }
+}
+
+void intel_uncore_clear_errors(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       /* XXX needs spinlock around caller's grouping */
+       if (HAS_FPGA_DBG_UNCLAIMED(dev))
+               __raw_i915_write32(dev_priv, FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
+}
+
+void intel_uncore_check_errors(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (HAS_FPGA_DBG_UNCLAIMED(dev) &&
+           (__raw_i915_read32(dev_priv, FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) {
+               DRM_ERROR("Unclaimed register before interrupt\n");
+               __raw_i915_write32(dev_priv, FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
+       }
+}
index 9fa5685baee0cff1a57d13b4132f19fdf4359a3d..1a75ea395b336579e4a8c2c76c56aec8d3f299ec 100644 (file)
@@ -349,7 +349,7 @@ void mgag200_gem_free_object(struct drm_gem_object *obj)
 
 static inline u64 mgag200_bo_mmap_offset(struct mgag200_bo *bo)
 {
-       return bo->bo.addr_space_offset;
+       return drm_vma_node_offset_addr(&bo->bo.vma_node);
 }
 
 int
index 251784aa22259a44baec12749d21c9b1e2163f35..503a414cbdad2ef83db8f10c9eaadd80522c515d 100644 (file)
@@ -29,6 +29,7 @@ static void mga_crtc_load_lut(struct drm_crtc *crtc)
        struct mga_crtc *mga_crtc = to_mga_crtc(crtc);
        struct drm_device *dev = crtc->dev;
        struct mga_device *mdev = dev->dev_private;
+       struct drm_framebuffer *fb = crtc->fb;
        int i;
 
        if (!crtc->enabled)
@@ -36,6 +37,28 @@ static void mga_crtc_load_lut(struct drm_crtc *crtc)
 
        WREG8(DAC_INDEX + MGA1064_INDEX, 0);
 
+       if (fb && fb->bits_per_pixel == 16) {
+               int inc = (fb->depth == 15) ? 8 : 4;
+               u8 r, b;
+               for (i = 0; i < MGAG200_LUT_SIZE; i += inc) {
+                       if (fb->depth == 16) {
+                               if (i > (MGAG200_LUT_SIZE >> 1)) {
+                                       r = b = 0;
+                               } else {
+                                       r = mga_crtc->lut_r[i << 1];
+                                       b = mga_crtc->lut_b[i << 1];
+                               }
+                       } else {
+                               r = mga_crtc->lut_r[i];
+                               b = mga_crtc->lut_b[i];
+                       }
+                       /* VGA registers */
+                       WREG8(DAC_INDEX + MGA1064_COL_PAL, r);
+                       WREG8(DAC_INDEX + MGA1064_COL_PAL, mga_crtc->lut_g[i]);
+                       WREG8(DAC_INDEX + MGA1064_COL_PAL, b);
+               }
+               return;
+       }
        for (i = 0; i < MGAG200_LUT_SIZE; i++) {
                /* VGA registers */
                WREG8(DAC_INDEX + MGA1064_COL_PAL, mga_crtc->lut_r[i]);
@@ -877,7 +900,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
 
        pitch = crtc->fb->pitches[0] / (crtc->fb->bits_per_pixel / 8);
        if (crtc->fb->bits_per_pixel == 24)
-               pitch = pitch >> (4 - bppshift);
+               pitch = (pitch * 3) >> (4 - bppshift);
        else
                pitch = pitch >> (4 - bppshift);
 
@@ -1251,6 +1274,24 @@ static void mga_crtc_destroy(struct drm_crtc *crtc)
        kfree(mga_crtc);
 }
 
+static void mga_crtc_disable(struct drm_crtc *crtc)
+{
+       int ret;
+       DRM_DEBUG_KMS("\n");
+       mga_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+       if (crtc->fb) {
+               struct mga_framebuffer *mga_fb = to_mga_framebuffer(crtc->fb);
+               struct drm_gem_object *obj = mga_fb->obj;
+               struct mgag200_bo *bo = gem_to_mga_bo(obj);
+               ret = mgag200_bo_reserve(bo, false);
+               if (ret)
+                       return;
+               mgag200_bo_push_sysram(bo);
+               mgag200_bo_unreserve(bo);
+       }
+       crtc->fb = NULL;
+}
+
 /* These provide the minimum set of functions required to handle a CRTC */
 static const struct drm_crtc_funcs mga_crtc_funcs = {
        .cursor_set = mga_crtc_cursor_set,
@@ -1261,6 +1302,7 @@ static const struct drm_crtc_funcs mga_crtc_funcs = {
 };
 
 static const struct drm_crtc_helper_funcs mga_helper_funcs = {
+       .disable = mga_crtc_disable,
        .dpms = mga_crtc_dpms,
        .mode_fixup = mga_crtc_mode_fixup,
        .mode_set = mga_crtc_mode_set,
@@ -1581,6 +1623,8 @@ static struct drm_connector *mga_vga_init(struct drm_device *dev)
 
        drm_connector_helper_add(connector, &mga_vga_connector_helper_funcs);
 
+       drm_sysfs_connector_add(connector);
+
        mga_connector->i2c = mgag200_i2c_create(dev);
        if (!mga_connector->i2c)
                DRM_ERROR("failed to add ddc bus\n");
index 3acb2b044c7b2d626c4efb9741c39a89f92a5ebc..13878d5de063f4b08b97ee2f5735dc2e3e7cb37b 100644 (file)
@@ -353,6 +353,7 @@ int mgag200_bo_pin(struct mgag200_bo *bo, u32 pl_flag, u64 *gpu_addr)
                bo->pin_count++;
                if (gpu_addr)
                        *gpu_addr = mgag200_bo_gpu_offset(bo);
+               return 0;
        }
 
        mgag200_ttm_placement(bo, pl_flag);
index 373dbcc523b23a1cc5c16e3aa5d1c8ca271e8e98..a19e7d79b847b2447d7254c1c77aeac623fb44cc 100644 (file)
@@ -36,6 +36,8 @@ nva3_hda_eld(struct nv50_disp_priv *priv, int or, u8 *data, u32 size)
        if (data && data[0]) {
                for (i = 0; i < size; i++)
                        nv_wr32(priv, 0x61c440 + soff, (i << 8) | data[i]);
+               for (; i < 0x60; i++)
+                       nv_wr32(priv, 0x61c440 + soff, (i << 8));
                nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000003);
        } else
        if (data) {
index dc57e24fc1df955253d1f447d8404c4d43d29fc6..717639386ced2c3e881dbf102ba39e24a5737293 100644 (file)
@@ -41,6 +41,8 @@ nvd0_hda_eld(struct nv50_disp_priv *priv, int or, u8 *data, u32 size)
        if (data && data[0]) {
                for (i = 0; i < size; i++)
                        nv_wr32(priv, 0x10ec00 + soff, (i << 8) | data[i]);
+               for (; i < 0x60; i++)
+                       nv_wr32(priv, 0x10ec00 + soff, (i << 8));
                nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000003);
        } else
        if (data) {
index ab1e918469a822f76bc09f4c09eb215f97a56990..526b75242899fb6e97e0abc3bd48cd228affe151 100644 (file)
@@ -47,14 +47,8 @@ int
 nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size)
 {
        struct nv50_disp_priv *priv = (void *)object->engine;
-       struct nouveau_bios *bios = nouveau_bios(priv);
-       const u16 type = (mthd & NV50_DISP_SOR_MTHD_TYPE) >> 12;
        const u8  head = (mthd & NV50_DISP_SOR_MTHD_HEAD) >> 3;
-       const u8  link = (mthd & NV50_DISP_SOR_MTHD_LINK) >> 2;
        const u8    or = (mthd & NV50_DISP_SOR_MTHD_OR);
-       const u16 mask = (0x0100 << head) | (0x0040 << link) | (0x0001 << or);
-       struct dcb_output outp;
-       u8  ver, hdr;
        u32 data;
        int ret = -EINVAL;
 
@@ -62,8 +56,6 @@ nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size)
                return -EINVAL;
        data = *(u32 *)args;
 
-       if (type && !dcb_outp_match(bios, type, mask, &ver, &hdr, &outp))
-               return -ENODEV;
 
        switch (mthd & ~0x3f) {
        case NV50_DISP_SOR_PWR:
index 49ecbb859b251974eefd6c5767d1b31ae2b624dc..c19004301309ea0c039fe8336d7fffdb906b24e7 100644 (file)
@@ -265,8 +265,8 @@ nv31_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 int
 nv31_mpeg_init(struct nouveau_object *object)
 {
-       struct nouveau_engine *engine = nv_engine(object->engine);
-       struct nv31_mpeg_priv *priv = (void *)engine;
+       struct nouveau_engine *engine = nv_engine(object);
+       struct nv31_mpeg_priv *priv = (void *)object;
        struct nouveau_fb *pfb = nouveau_fb(object);
        int ret, i;
 
@@ -284,7 +284,10 @@ nv31_mpeg_init(struct nouveau_object *object)
        /* PMPEG init */
        nv_wr32(priv, 0x00b32c, 0x00000000);
        nv_wr32(priv, 0x00b314, 0x00000100);
-       nv_wr32(priv, 0x00b220, nv44_graph_class(priv) ? 0x00000044 : 0x00000031);
+       if (nv_device(priv)->chipset >= 0x40 && nv44_graph_class(priv))
+               nv_wr32(priv, 0x00b220, 0x00000044);
+       else
+               nv_wr32(priv, 0x00b220, 0x00000031);
        nv_wr32(priv, 0x00b300, 0x02001ec1);
        nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001);
 
index f7c581ad1991b880b3abe6590f0250b68261a9d2..dd6196072e9c7f58062c7e500ea8c57ba19cb580 100644 (file)
@@ -61,6 +61,7 @@ nv40_mpeg_context_ctor(struct nouveau_object *parent,
        if (ret)
                return ret;
 
+       nv_wo32(&chan->base.base, 0x78, 0x02001ec1);
        return 0;
 }
 
index 0639bc59d0a513725195ea64be7af30ed2dadbf0..5f6ede7c48928a799e3a2084371e5bb86a2388d4 100644 (file)
@@ -118,7 +118,13 @@ _nouveau_xtensa_init(struct nouveau_object *object)
                        return ret;
                }
 
-               ret = nouveau_gpuobj_new(object, NULL, fw->size, 0x1000, 0,
+               if (fw->size > 0x40000) {
+                       nv_warn(xtensa, "firmware %s too large\n", name);
+                       release_firmware(fw);
+                       return -EINVAL;
+               }
+
+               ret = nouveau_gpuobj_new(object, NULL, 0x40000, 0x1000, 0,
                                         &xtensa->gpu_fw);
                if (ret) {
                        release_firmware(fw);
index f2e87b105666f344c46e0c96c9870a062dd76340..fcf57fa309bfd54bbcbba86bdfc53ef5fcc481f6 100644 (file)
@@ -55,7 +55,7 @@ struct nouveau_vma {
 struct nouveau_vm {
        struct nouveau_vmmgr *vmm;
        struct nouveau_mm mm;
-       int refcount;
+       struct kref refcount;
 
        struct list_head pgd_list;
        atomic_t engref[NVDEV_SUBDEV_NR];
index 6c974dd83e8bcbe43daf5ac6e44f6b9690180e91..db9d6ddde52c31cc7395de7cca70ceaf0671d015 100644 (file)
@@ -81,7 +81,7 @@ void nv44_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
 void nv46_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
                       u32 pitch, u32 flags, struct nouveau_fb_tile *);
 
-void nv50_ram_put(struct nouveau_fb *, struct nouveau_mem **);
+void __nv50_ram_put(struct nouveau_fb *, struct nouveau_mem *);
 extern int nv50_fb_memtype[0x80];
 
 #endif
index af5aa7ee8ad954a465f4b6ec3183e7091731afdb..903baff77fddcc20e8e2f18a6df808d66c0d316d 100644 (file)
 #include "priv.h"
 
 void
-nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
+__nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem *mem)
 {
        struct nouveau_mm_node *this;
-       struct nouveau_mem *mem;
 
-       mem = *pmem;
-       *pmem = NULL;
-       if (unlikely(mem == NULL))
-               return;
-
-       mutex_lock(&pfb->base.mutex);
        while (!list_empty(&mem->regions)) {
                this = list_first_entry(&mem->regions, typeof(*this), rl_entry);
 
@@ -46,6 +39,19 @@ nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
        }
 
        nouveau_mm_free(&pfb->tags, &mem->tag);
+}
+
+void
+nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
+{
+       struct nouveau_mem *mem = *pmem;
+
+       *pmem = NULL;
+       if (unlikely(mem == NULL))
+               return;
+
+       mutex_lock(&pfb->base.mutex);
+       __nv50_ram_put(pfb, mem);
        mutex_unlock(&pfb->base.mutex);
 
        kfree(mem);
index 9c3634acbb9d8e3c404a8e251470636552d4fc6d..cf97c4de4a6b2911722da3b1799487f217cfb560 100644 (file)
@@ -33,11 +33,19 @@ void
 nvc0_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
 {
        struct nouveau_ltcg *ltcg = nouveau_ltcg(pfb);
+       struct nouveau_mem *mem = *pmem;
 
-       if ((*pmem)->tag)
-               ltcg->tags_free(ltcg, &(*pmem)->tag);
+       *pmem = NULL;
+       if (unlikely(mem == NULL))
+               return;
 
-       nv50_ram_put(pfb, pmem);
+       mutex_lock(&pfb->base.mutex);
+       if (mem->tag)
+               ltcg->tags_free(ltcg, &mem->tag);
+       __nv50_ram_put(pfb, mem);
+       mutex_unlock(&pfb->base.mutex);
+
+       kfree(mem);
 }
 
 int
index bf489dcf46e2796fed5e0e1b1f109ae2dcfe015b..c4c1d415e7feb871329c275e894558f44c60aff8 100644 (file)
@@ -103,7 +103,7 @@ nv50_gpio_intr(struct nouveau_subdev *subdev)
        int i;
 
        intr0 = nv_rd32(priv, 0xe054) & nv_rd32(priv, 0xe050);
-       if (nv_device(priv)->chipset >= 0x90)
+       if (nv_device(priv)->chipset > 0x92)
                intr1 = nv_rd32(priv, 0xe074) & nv_rd32(priv, 0xe070);
 
        hi = (intr0 & 0x0000ffff) | (intr1 << 16);
@@ -115,7 +115,7 @@ nv50_gpio_intr(struct nouveau_subdev *subdev)
        }
 
        nv_wr32(priv, 0xe054, intr0);
-       if (nv_device(priv)->chipset >= 0x90)
+       if (nv_device(priv)->chipset > 0x92)
                nv_wr32(priv, 0xe074, intr1);
 }
 
@@ -146,7 +146,7 @@ nv50_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        int ret;
 
        ret = nouveau_gpio_create(parent, engine, oclass,
-                                 nv_device(parent)->chipset >= 0x90 ? 32 : 16,
+                                 nv_device(parent)->chipset > 0x92 ? 32 : 16,
                                  &priv);
        *pobject = nv_object(priv);
        if (ret)
@@ -182,7 +182,7 @@ nv50_gpio_init(struct nouveau_object *object)
        /* disable, and ack any pending gpio interrupts */
        nv_wr32(priv, 0xe050, 0x00000000);
        nv_wr32(priv, 0xe054, 0xffffffff);
-       if (nv_device(priv)->chipset >= 0x90) {
+       if (nv_device(priv)->chipset > 0x92) {
                nv_wr32(priv, 0xe070, 0x00000000);
                nv_wr32(priv, 0xe074, 0xffffffff);
        }
@@ -195,7 +195,7 @@ nv50_gpio_fini(struct nouveau_object *object, bool suspend)
 {
        struct nv50_gpio_priv *priv = (void *)object;
        nv_wr32(priv, 0xe050, 0x00000000);
-       if (nv_device(priv)->chipset >= 0x90)
+       if (nv_device(priv)->chipset > 0x92)
                nv_wr32(priv, 0xe070, 0x00000000);
        return nouveau_gpio_fini(&priv->base, suspend);
 }
index 0cb322a5e72cdaab4f29dc7f2e6306963c110ba0..f25fc5fc7dd11a773e6743a3df5d3ae5e1235532 100644 (file)
@@ -41,7 +41,7 @@ nv50_mc_intr[] = {
        { 0x04000000, NVDEV_ENGINE_DISP },
        { 0x10000000, NVDEV_SUBDEV_BUS },
        { 0x80000000, NVDEV_ENGINE_SW },
-       { 0x0000d101, NVDEV_SUBDEV_FB },
+       { 0x0002d101, NVDEV_SUBDEV_FB },
        {},
 };
 
index 67fcb6c852ac008539548f8271889998b64043d5..ef3133e7575c8eaf937520cf750bd51effcd7505 100644 (file)
@@ -361,7 +361,7 @@ nouveau_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length,
 
        INIT_LIST_HEAD(&vm->pgd_list);
        vm->vmm = vmm;
-       vm->refcount = 1;
+       kref_init(&vm->refcount);
        vm->fpde = offset >> (vmm->pgt_bits + 12);
        vm->lpde = (offset + length - 1) >> (vmm->pgt_bits + 12);
 
@@ -441,8 +441,9 @@ nouveau_vm_unlink(struct nouveau_vm *vm, struct nouveau_gpuobj *mpgd)
 }
 
 static void
-nouveau_vm_del(struct nouveau_vm *vm)
+nouveau_vm_del(struct kref *kref)
 {
+       struct nouveau_vm *vm = container_of(kref, typeof(*vm), refcount);
        struct nouveau_vm_pgd *vpgd, *tmp;
 
        list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) {
@@ -458,27 +459,19 @@ int
 nouveau_vm_ref(struct nouveau_vm *ref, struct nouveau_vm **ptr,
               struct nouveau_gpuobj *pgd)
 {
-       struct nouveau_vm *vm;
-       int ret;
-
-       vm = ref;
-       if (vm) {
-               ret = nouveau_vm_link(vm, pgd);
+       if (ref) {
+               int ret = nouveau_vm_link(ref, pgd);
                if (ret)
                        return ret;
 
-               vm->refcount++;
+               kref_get(&ref->refcount);
        }
 
-       vm = *ptr;
-       *ptr = ref;
-
-       if (vm) {
-               nouveau_vm_unlink(vm, pgd);
-
-               if (--vm->refcount == 0)
-                       nouveau_vm_del(vm);
+       if (*ptr) {
+               nouveau_vm_unlink(*ptr, pgd);
+               kref_put(&(*ptr)->refcount, nouveau_vm_del);
        }
 
+       *ptr = ref;
        return 0;
 }
index 4e7ee5f4155c96bce6b1091fdf432a6d46140eab..af20fba3a1a47ae441f8c587d79670d445ed6374 100644 (file)
@@ -198,7 +198,12 @@ nouveau_bo_new(struct drm_device *dev, int size, int align,
        size_t acc_size;
        int ret;
        int type = ttm_bo_type_device;
-       int max_size = INT_MAX & ~((1 << drm->client.base.vm->vmm->lpg_shift) - 1);
+       int lpg_shift = 12;
+       int max_size;
+
+       if (drm->client.base.vm)
+               lpg_shift = drm->client.base.vm->vmm->lpg_shift;
+       max_size = INT_MAX & ~((1 << lpg_shift) - 1);
 
        if (size <= 0 || size > max_size) {
                nv_warn(drm, "skipped size %x\n", (u32)size);
index 907d20ef6d4d119f81c06fe1801edf3867f01673..ac1ee0da2aa2192b20c99236c2aecae9293dba42 100644 (file)
@@ -690,7 +690,7 @@ 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 = gem->driver_private;
-               *poffset = bo->bo.addr_space_offset;
+               *poffset = drm_vma_node_offset_addr(&bo->bo.vma_node);
                drm_gem_object_unreference_unlocked(gem);
                return 0;
        }
index 61972668fd0532f9f29e6ea540ab925713d5cf7d..3c1a150a34fb0b2dc522d1e97e532e3cc4bc1838 100644 (file)
@@ -684,7 +684,7 @@ nouveau_driver_fops = {
 static struct drm_driver
 driver = {
        .driver_features =
-               DRIVER_USE_AGP | DRIVER_PCI_DMA | DRIVER_SG |
+               DRIVER_USE_AGP |
                DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME,
 
        .load = nouveau_drm_load,
index 4c1bc061fae2cab668f5d5f2bd24f1ab5febbc62..8f6d63d7edd314c4f6a6ff7e492c3b37be88930e 100644 (file)
@@ -398,7 +398,8 @@ void
 nouveau_fbcon_output_poll_changed(struct drm_device *dev)
 {
        struct nouveau_drm *drm = nouveau_drm(dev);
-       drm_fb_helper_hotplug_event(&drm->fbcon->helper);
+       if (drm->fbcon)
+               drm_fb_helper_hotplug_event(&drm->fbcon->helper);
 }
 
 static int
index 830cb7bad922bba909a6c5129c16a786cb9ee969..487242fb3fdc53f28cac33fc3db7ccfeefab1604 100644 (file)
@@ -220,7 +220,7 @@ nouveau_gem_info(struct drm_file *file_priv, struct drm_gem_object *gem,
        }
 
        rep->size = nvbo->bo.mem.num_pages << PAGE_SHIFT;
-       rep->map_handle = nvbo->bo.addr_space_offset;
+       rep->map_handle = drm_vma_node_offset_addr(&nvbo->bo.vma_node);
        rep->tile_mode = nvbo->tile_mode;
        rep->tile_flags = nvbo->tile_flags;
        return 0;
index 8e47a9bae8c301e1ac205a0140ef650ed9d7aa5f..22aa9963ea6fd46b36f28b457fa7cfeecac0372b 100644 (file)
@@ -76,7 +76,7 @@ nv17_fence_context_new(struct nouveau_channel *chan)
        struct ttm_mem_reg *mem = &priv->bo->bo.mem;
        struct nouveau_object *object;
        u32 start = mem->start * PAGE_SIZE;
-       u32 limit = mem->start + mem->size - 1;
+       u32 limit = start + mem->size - 1;
        int ret = 0;
 
        fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL);
index f9701e567db89793136c52e02bf11d59baba4ce4..0ee363840035b1e67bd3e6c6b8bb63afbf4d8ea3 100644 (file)
@@ -39,6 +39,8 @@ nv50_fence_context_new(struct nouveau_channel *chan)
        struct nv10_fence_chan *fctx;
        struct ttm_mem_reg *mem = &priv->bo->bo.mem;
        struct nouveau_object *object;
+       u32 start = mem->start * PAGE_SIZE;
+       u32 limit = start + mem->size - 1;
        int ret, i;
 
        fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL);
@@ -51,26 +53,28 @@ nv50_fence_context_new(struct nouveau_channel *chan)
        fctx->base.sync = nv17_fence_sync;
 
        ret = nouveau_object_new(nv_object(chan->cli), chan->handle,
-                                NvSema, 0x0002,
+                                NvSema, 0x003d,
                                 &(struct nv_dma_class) {
                                        .flags = NV_DMA_TARGET_VRAM |
                                                 NV_DMA_ACCESS_RDWR,
-                                       .start = mem->start * PAGE_SIZE,
-                                       .limit = mem->size - 1,
+                                       .start = start,
+                                       .limit = limit,
                                 }, sizeof(struct nv_dma_class),
                                 &object);
 
        /* dma objects for display sync channel semaphore blocks */
        for (i = 0; !ret && i < dev->mode_config.num_crtc; i++) {
                struct nouveau_bo *bo = nv50_display_crtc_sema(dev, i);
+               u32 start = bo->bo.mem.start * PAGE_SIZE;
+               u32 limit = start + bo->bo.mem.size - 1;
 
                ret = nouveau_object_new(nv_object(chan->cli), chan->handle,
                                         NvEvoSema0 + i, 0x003d,
                                         &(struct nv_dma_class) {
                                                .flags = NV_DMA_TARGET_VRAM |
                                                         NV_DMA_ACCESS_RDWR,
-                                               .start = bo->bo.offset,
-                                               .limit = bo->bo.offset + 0xfff,
+                                               .start = start,
+                                               .limit = limit,
                                         }, sizeof(struct nv_dma_class),
                                         &object);
        }
index ebbdf4132e9cb2175fabd6422ac17365eaa10d4a..f90531fc00c911a01f795fbd692c33e74a939bb9 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <linux/spinlock.h>
 #include <linux/shmem_fs.h>
+#include <drm/drm_vma_manager.h>
 
 #include "omap_drv.h"
 #include "omap_dmm_tiler.h"
@@ -308,21 +309,20 @@ uint32_t omap_gem_flags(struct drm_gem_object *obj)
 static uint64_t mmap_offset(struct drm_gem_object *obj)
 {
        struct drm_device *dev = obj->dev;
+       int ret;
+       size_t size;
 
        WARN_ON(!mutex_is_locked(&dev->struct_mutex));
 
-       if (!obj->map_list.map) {
-               /* Make it mmapable */
-               size_t size = omap_gem_mmap_size(obj);
-               int ret = _drm_gem_create_mmap_offset_size(obj, size);
-
-               if (ret) {
-                       dev_err(dev->dev, "could not allocate mmap offset\n");
-                       return 0;
-               }
+       /* Make it mmapable */
+       size = omap_gem_mmap_size(obj);
+       ret = _drm_gem_create_mmap_offset_size(obj, size);
+       if (ret) {
+               dev_err(dev->dev, "could not allocate mmap offset\n");
+               return 0;
        }
 
-       return (uint64_t)obj->map_list.hash.key << PAGE_SHIFT;
+       return drm_vma_node_offset_addr(&obj->vma_node);
 }
 
 uint64_t omap_gem_mmap_offset(struct drm_gem_object *obj)
@@ -997,12 +997,11 @@ void omap_gem_describe(struct drm_gem_object *obj, struct seq_file *m)
 {
        struct drm_device *dev = obj->dev;
        struct omap_gem_object *omap_obj = to_omap_bo(obj);
-       uint64_t off = 0;
+       uint64_t off;
 
        WARN_ON(!mutex_is_locked(&dev->struct_mutex));
 
-       if (obj->map_list.map)
-               off = (uint64_t)obj->map_list.hash.key;
+       off = drm_vma_node_start(&obj->vma_node);
 
        seq_printf(m, "%08x: %2d (%2d) %08llx %08Zx (%2d) %p %4d",
                        omap_obj->flags, obj->name, obj->refcount.refcount.counter,
@@ -1309,8 +1308,7 @@ void omap_gem_free_object(struct drm_gem_object *obj)
 
        list_del(&omap_obj->mm_list);
 
-       if (obj->map_list.map)
-               drm_gem_free_mmap_offset(obj);
+       drm_gem_free_mmap_offset(obj);
 
        /* this means the object is still pinned.. which really should
         * not happen.  I think..
@@ -1427,8 +1425,9 @@ struct drm_gem_object *omap_gem_new(struct drm_device *dev,
                omap_obj->height = gsize.tiled.height;
        }
 
+       ret = 0;
        if (flags & (OMAP_BO_DMA|OMAP_BO_EXT_MEM))
-               ret = drm_gem_private_object_init(dev, obj, size);
+               drm_gem_private_object_init(dev, obj, size);
        else
                ret = drm_gem_object_init(dev, obj, size);
 
index f9eb679eb79b28764319f469726abf7b4147da01..dbb157542f8f049eb6ecf26e118adeb35ce9de89 100644 (file)
@@ -118,52 +118,7 @@ _drm_gem_create_mmap_offset_size(struct drm_gem_object *obj, size_t size)
 {
        struct drm_device *dev = obj->dev;
        struct drm_gem_mm *mm = dev->mm_private;
-       struct drm_map_list *list;
-       struct drm_local_map *map;
-       int ret = 0;
-
-       /* Set the object up for mmap'ing */
-       list = &obj->map_list;
-       list->map = kzalloc(sizeof(struct drm_map_list), GFP_KERNEL);
-       if (!list->map)
-               return -ENOMEM;
-
-       map = list->map;
-       map->type = _DRM_GEM;
-       map->size = size;
-       map->handle = obj;
-
-       /* Get a DRM GEM mmap offset allocated... */
-       list->file_offset_node = drm_mm_search_free(&mm->offset_manager,
-                       size / PAGE_SIZE, 0, 0);
-
-       if (!list->file_offset_node) {
-               DRM_ERROR("failed to allocate offset for bo %d\n", obj->name);
-               ret = -ENOSPC;
-               goto out_free_list;
-       }
-
-       list->file_offset_node = drm_mm_get_block(list->file_offset_node,
-                       size / PAGE_SIZE, 0);
-       if (!list->file_offset_node) {
-               ret = -ENOMEM;
-               goto out_free_list;
-       }
-
-       list->hash.key = list->file_offset_node->start;
-       ret = drm_ht_insert_item(&mm->offset_hash, &list->hash);
-       if (ret) {
-               DRM_ERROR("failed to add to map hash\n");
-               goto out_free_mm;
-       }
-
-       return 0;
-
-out_free_mm:
-       drm_mm_put_block(list->file_offset_node);
-out_free_list:
-       kfree(list->map);
-       list->map = NULL;
 
-       return ret;
+       return drm_vma_offset_add(&mm->vma_manager, &obj->vma_node,
+                                 size / PAGE_SIZE);
 }
index 8cb6167038e544625ec666a6fef7b4308d8e832d..d458a140c02407c01858f2d7b8a212e80417db3a 100644 (file)
@@ -59,7 +59,7 @@ static inline unsigned long qxl_bo_size(struct qxl_bo *bo)
 
 static inline u64 qxl_bo_mmap_offset(struct qxl_bo *bo)
 {
-       return bo->tbo.addr_space_offset;
+       return drm_vma_node_offset_addr(&bo->tbo.vma_node);
 }
 
 static inline int qxl_bo_wait(struct qxl_bo *bo, u32 *mem_type,
index b61449e52cd5695c7c024548ecedfc3340b11156..0109a9644cb29ef7a6e13ac76a90544effcefd20 100644 (file)
@@ -88,7 +88,7 @@ qxl_release_free(struct qxl_device *qdev,
        list_for_each_entry_safe(entry, tmp, &release->bos, tv.head) {
                struct qxl_bo *bo = to_qxl_bo(entry->tv.bo);
                QXL_INFO(qdev, "release %llx\n",
-                       entry->tv.bo->addr_space_offset
+                       drm_vma_node_offset_addr(&entry->tv.bo->vma_node)
                                                - DRM_FILE_OFFSET);
                qxl_fence_remove_release(&bo->fence, release->id);
                qxl_bo_unref(&bo);
index d4660cf942a52b98c2c0a204b423bbe90ee56ed5..c451257f08fb51ea4b2c5346339237032705f955 100644 (file)
@@ -540,7 +540,7 @@ static int r128_do_init_cce(struct drm_device *dev, drm_r128_init_t *init)
        dev_priv->ring.end = ((u32 *) dev_priv->cce_ring->handle
                              + init->ring_size / sizeof(u32));
        dev_priv->ring.size = init->ring_size;
-       dev_priv->ring.size_l2qw = drm_order(init->ring_size / 8);
+       dev_priv->ring.size_l2qw = order_base_2(init->ring_size / 8);
 
        dev_priv->ring.tail_mask = (dev_priv->ring.size / sizeof(u32)) - 1;
 
index fb441a790f3dc5a56fa6c65bf4384f2d098906fb..15da7ef344a4e55fa11d604c21269e97ab361386 100644 (file)
@@ -1222,12 +1222,17 @@ int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
        int r;
 
        mutex_lock(&ctx->mutex);
+       /* reset data block */
+       ctx->data_block = 0;
        /* reset reg block */
        ctx->reg_block = 0;
        /* reset fb window */
        ctx->fb_base = 0;
        /* reset io mode */
        ctx->io_mode = ATOM_IO_MM;
+       /* reset divmul */
+       ctx->divmul[0] = 0;
+       ctx->divmul[1] = 0;
        r = atom_execute_table_locked(ctx, index, params);
        mutex_unlock(&ctx->mutex);
        return r;
index 6dacec4e20901bd1f12e428a387434a8db8a91a8..6adbc998349e152770d3b29e478448d12c2a24f5 100644 (file)
@@ -2535,8 +2535,8 @@ static int cik_cp_gfx_resume(struct radeon_device *rdev)
        /* ring 0 - compute and gfx */
        /* Set ring buffer size */
        ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
-       rb_bufsz = drm_order(ring->ring_size / 8);
-       tmp = (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
+       rb_bufsz = order_base_2(ring->ring_size / 8);
+       tmp = (order_base_2(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
 #ifdef __BIG_ENDIAN
        tmp |= BUF_SWAP_32BIT;
 #endif
@@ -2915,7 +2915,7 @@ static int cik_cp_compute_resume(struct radeon_device *rdev)
                /* set the EOP size, register value is 2^(EOP_SIZE+1) dwords */
                tmp = RREG32(CP_HPD_EOP_CONTROL);
                tmp &= ~EOP_SIZE_MASK;
-               tmp |= drm_order(MEC_HPD_SIZE / 8);
+               tmp |= order_base_2(MEC_HPD_SIZE / 8);
                WREG32(CP_HPD_EOP_CONTROL, tmp);
        }
        cik_srbm_select(rdev, 0, 0, 0, 0);
@@ -3030,9 +3030,9 @@ static int cik_cp_compute_resume(struct radeon_device *rdev)
                        ~(QUEUE_SIZE_MASK | RPTR_BLOCK_SIZE_MASK);
 
                mqd->queue_state.cp_hqd_pq_control |=
-                       drm_order(rdev->ring[idx].ring_size / 8);
+                       order_base_2(rdev->ring[idx].ring_size / 8);
                mqd->queue_state.cp_hqd_pq_control |=
-                       (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8);
+                       (order_base_2(RADEON_GPU_PAGE_SIZE/8) << 8);
 #ifdef __BIG_ENDIAN
                mqd->queue_state.cp_hqd_pq_control |= BUF_SWAP_32BIT;
 #endif
@@ -3375,7 +3375,7 @@ static int cik_sdma_gfx_resume(struct radeon_device *rdev)
                WREG32(SDMA0_SEM_WAIT_FAIL_TIMER_CNTL + reg_offset, 0);
 
                /* Set ring buffer size in dwords */
-               rb_bufsz = drm_order(ring->ring_size / 4);
+               rb_bufsz = order_base_2(ring->ring_size / 4);
                rb_cntl = rb_bufsz << 1;
 #ifdef __BIG_ENDIAN
                rb_cntl |= SDMA_RB_SWAP_ENABLE | SDMA_RPTR_WRITEBACK_SWAP_ENABLE;
@@ -5030,7 +5030,7 @@ static int cik_irq_init(struct radeon_device *rdev)
        WREG32(INTERRUPT_CNTL, interrupt_cntl);
 
        WREG32(IH_RB_BASE, rdev->ih.gpu_addr >> 8);
-       rb_bufsz = drm_order(rdev->ih.ring_size / 4);
+       rb_bufsz = order_base_2(rdev->ih.ring_size / 4);
 
        ih_rb_cntl = (IH_WPTR_OVERFLOW_ENABLE |
                      IH_WPTR_OVERFLOW_CLEAR |
index 038dcac7670cf540950d4ce64a26830da6325e0d..b67c9ec7f690258a5df72d1807da2a21a4966e32 100644 (file)
@@ -2881,8 +2881,8 @@ static int evergreen_cp_resume(struct radeon_device *rdev)
        RREG32(GRBM_SOFT_RESET);
 
        /* Set ring buffer size */
-       rb_bufsz = drm_order(ring->ring_size / 8);
-       tmp = (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
+       rb_bufsz = order_base_2(ring->ring_size / 8);
+       tmp = (order_base_2(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
 #ifdef __BIG_ENDIAN
        tmp |= BUF_SWAP_32BIT;
 #endif
index b0d3fb341417342cd06b3454fe17527cbb581e48..bb9ea3641312af1a8da0aff84486a124c629704a 100644 (file)
@@ -157,9 +157,9 @@ static void evergreen_audio_set_dto(struct drm_encoder *encoder, u32 clock)
         * number (coefficient of two integer numbers.  DCCG_AUDIO_DTOx_PHASE
         * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
         */
+       WREG32(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO0_SOURCE_SEL(radeon_crtc->crtc_id));
        WREG32(DCCG_AUDIO_DTO0_PHASE, base_rate * 100);
        WREG32(DCCG_AUDIO_DTO0_MODULE, clock * 100);
-       WREG32(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO0_SOURCE_SEL(radeon_crtc->crtc_id));
 }
 
 
index 56bd4f3be4febfe75522deb222a0218c7792b248..5b6e477656569e371c09e318d6e93f11caad6487 100644 (file)
@@ -1560,8 +1560,8 @@ static int cayman_cp_resume(struct radeon_device *rdev)
 
                /* Set ring buffer size */
                ring = &rdev->ring[ridx[i]];
-               rb_cntl = drm_order(ring->ring_size / 8);
-               rb_cntl |= drm_order(RADEON_GPU_PAGE_SIZE/8) << 8;
+               rb_cntl = order_base_2(ring->ring_size / 8);
+               rb_cntl |= order_base_2(RADEON_GPU_PAGE_SIZE/8) << 8;
 #ifdef __BIG_ENDIAN
                rb_cntl |= BUF_SWAP_32BIT;
 #endif
@@ -1720,7 +1720,7 @@ int cayman_dma_resume(struct radeon_device *rdev)
                WREG32(DMA_SEM_WAIT_FAIL_TIMER_CNTL + reg_offset, 0);
 
                /* Set ring buffer size in dwords */
-               rb_bufsz = drm_order(ring->ring_size / 4);
+               rb_bufsz = order_base_2(ring->ring_size / 4);
                rb_cntl = rb_bufsz << 1;
 #ifdef __BIG_ENDIAN
                rb_cntl |= DMA_RB_SWAP_ENABLE | DMA_RPTR_WRITEBACK_SWAP_ENABLE;
index 559cf24d51af8dbe7304caa443e7e15118c750ca..4f9b9bc20daaccde2911de65882c5a9c32d23f15 100644 (file)
@@ -1054,10 +1054,6 @@ static int ni_restrict_performance_levels_before_switch(struct radeon_device *rd
 int ni_dpm_force_performance_level(struct radeon_device *rdev,
                                   enum radeon_dpm_forced_level level)
 {
-       struct radeon_ps *rps = rdev->pm.dpm.current_ps;
-       struct ni_ps *ps = ni_get_ps(rps);
-       u32 levels;
-
        if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
                if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 0) != PPSMC_Result_OK)
                        return -EINVAL;
@@ -1068,8 +1064,7 @@ int ni_dpm_force_performance_level(struct radeon_device *rdev,
                if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK)
                        return -EINVAL;
 
-               levels = ps->performance_level_count - 1;
-               if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, levels) != PPSMC_Result_OK)
+               if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 1) != PPSMC_Result_OK)
                        return -EINVAL;
        } else if (level == RADEON_DPM_FORCED_LEVEL_AUTO) {
                if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK)
index 75349cdaa84b181186d6dee878d582437521a96a..5625cf706f0c3326b3e70d6d337fa23bbe7650f7 100644 (file)
@@ -1097,7 +1097,7 @@ int r100_cp_init(struct radeon_device *rdev, unsigned ring_size)
        }
 
        /* Align ring size */
-       rb_bufsz = drm_order(ring_size / 8);
+       rb_bufsz = order_base_2(ring_size / 8);
        ring_size = (1 << (rb_bufsz + 1)) * 4;
        r100_cp_load_microcode(rdev);
        r = radeon_ring_init(rdev, ring, ring_size, RADEON_WB_CP_RPTR_OFFSET,
index 10f712e37003030e81a7770e94ca696c4c8f2c08..cfc1d28ade39e4d39329feee29dd8a63de410c66 100644 (file)
@@ -2413,8 +2413,8 @@ int r600_cp_resume(struct radeon_device *rdev)
        WREG32(GRBM_SOFT_RESET, 0);
 
        /* Set ring buffer size */
-       rb_bufsz = drm_order(ring->ring_size / 8);
-       tmp = (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
+       rb_bufsz = order_base_2(ring->ring_size / 8);
+       tmp = (order_base_2(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
 #ifdef __BIG_ENDIAN
        tmp |= BUF_SWAP_32BIT;
 #endif
@@ -2467,7 +2467,7 @@ void r600_ring_init(struct radeon_device *rdev, struct radeon_ring *ring, unsign
        int r;
 
        /* Align ring size */
-       rb_bufsz = drm_order(ring_size / 8);
+       rb_bufsz = order_base_2(ring_size / 8);
        ring_size = (1 << (rb_bufsz + 1)) * 4;
        ring->ring_size = ring_size;
        ring->align_mask = 16 - 1;
@@ -2547,7 +2547,7 @@ int r600_dma_resume(struct radeon_device *rdev)
        WREG32(DMA_SEM_WAIT_FAIL_TIMER_CNTL, 0);
 
        /* Set ring buffer size in dwords */
-       rb_bufsz = drm_order(ring->ring_size / 4);
+       rb_bufsz = order_base_2(ring->ring_size / 4);
        rb_cntl = rb_bufsz << 1;
 #ifdef __BIG_ENDIAN
        rb_cntl |= DMA_RB_SWAP_ENABLE | DMA_RPTR_WRITEBACK_SWAP_ENABLE;
@@ -2656,7 +2656,7 @@ int r600_uvd_rbc_start(struct radeon_device *rdev)
        WREG32(UVD_RBC_RB_BASE, ring->gpu_addr);
 
        /* Set ring buffer size */
-       rb_bufsz = drm_order(ring->ring_size);
+       rb_bufsz = order_base_2(ring->ring_size);
        rb_bufsz = (0x1 << 8) | rb_bufsz;
        WREG32(UVD_RBC_RB_CNTL, rb_bufsz);
 
@@ -3815,7 +3815,7 @@ void r600_ih_ring_init(struct radeon_device *rdev, unsigned ring_size)
        u32 rb_bufsz;
 
        /* Align ring size */
-       rb_bufsz = drm_order(ring_size / 4);
+       rb_bufsz = order_base_2(ring_size / 4);
        ring_size = (1 << rb_bufsz) * 4;
        rdev->ih.ring_size = ring_size;
        rdev->ih.ptr_mask = rdev->ih.ring_size - 1;
@@ -4052,7 +4052,7 @@ int r600_irq_init(struct radeon_device *rdev)
        WREG32(INTERRUPT_CNTL, interrupt_cntl);
 
        WREG32(IH_RB_BASE, rdev->ih.gpu_addr >> 8);
-       rb_bufsz = drm_order(rdev->ih.ring_size / 4);
+       rb_bufsz = order_base_2(rdev->ih.ring_size / 4);
 
        ih_rb_cntl = (IH_WPTR_OVERFLOW_ENABLE |
                      IH_WPTR_OVERFLOW_CLEAR |
index 1c51c08b1fdeddf5524ddf4029aa02ce98a92dcc..d8eb48bff0ed204e9c52538342a11dcd1bd5b8ff 100644 (file)
@@ -2200,13 +2200,13 @@ int r600_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
        dev_priv->ring.end = ((u32 *) dev_priv->cp_ring->handle
                              + init->ring_size / sizeof(u32));
        dev_priv->ring.size = init->ring_size;
-       dev_priv->ring.size_l2qw = drm_order(init->ring_size / 8);
+       dev_priv->ring.size_l2qw = order_base_2(init->ring_size / 8);
 
        dev_priv->ring.rptr_update = /* init->rptr_update */ 4096;
-       dev_priv->ring.rptr_update_l2qw = drm_order(/* init->rptr_update */ 4096 / 8);
+       dev_priv->ring.rptr_update_l2qw = order_base_2(/* init->rptr_update */ 4096 / 8);
 
        dev_priv->ring.fetch_size = /* init->fetch_size */ 32;
-       dev_priv->ring.fetch_size_l2ow = drm_order(/* init->fetch_size */ 32 / 16);
+       dev_priv->ring.fetch_size_l2ow = order_base_2(/* init->fetch_size */ 32 / 16);
 
        dev_priv->ring.tail_mask = (dev_priv->ring.size / sizeof(u32)) - 1;
 
index e3f3e8841789a5c7a0234f73fb089dc0cf204687..4ccd61f60eb6cd23849940c3c25ed0e9eec675fd 100644 (file)
@@ -2782,7 +2782,7 @@ int radeon_atom_get_clock_dividers(struct radeon_device *rdev,
                                                             ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN) ? true : false;
                                dividers->enable_dithen = (args.v3.ucCntlFlag &
                                                           ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE) ? false : true;
-                               dividers->fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDiv);
+                               dividers->whole_fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDiv);
                                dividers->frac_fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDivFrac);
                                dividers->ref_div = args.v3.ucRefDiv;
                                dividers->vco_mode = (args.v3.ucCntlFlag &
index efc4f6441ef42c8a9bb85a9d93e6db44f92bc97b..3cae2bbc1854d73dda35f13f0b8cfc3201dc2c25 100644 (file)
@@ -1444,13 +1444,13 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
        dev_priv->ring.end = ((u32 *) dev_priv->cp_ring->handle
                              + init->ring_size / sizeof(u32));
        dev_priv->ring.size = init->ring_size;
-       dev_priv->ring.size_l2qw = drm_order(init->ring_size / 8);
+       dev_priv->ring.size_l2qw = order_base_2(init->ring_size / 8);
 
        dev_priv->ring.rptr_update = /* init->rptr_update */ 4096;
-       dev_priv->ring.rptr_update_l2qw = drm_order( /* init->rptr_update */ 4096 / 8);
+       dev_priv->ring.rptr_update_l2qw = order_base_2( /* init->rptr_update */ 4096 / 8);
 
        dev_priv->ring.fetch_size = /* init->fetch_size */ 32;
-       dev_priv->ring.fetch_size_l2ow = drm_order( /* init->fetch_size */ 32 / 16);
+       dev_priv->ring.fetch_size_l2ow = order_base_2( /* init->fetch_size */ 32 / 16);
        dev_priv->ring.tail_mask = (dev_priv->ring.size / sizeof(u32)) - 1;
 
        dev_priv->ring.high_mark = RADEON_RING_HIGH_MARK;
index 29876b1be8ecae78b15bc8690804307c15885f12..cb7f1a8c5a4a61adbb41cedfac601628de9a5aa2 100644 (file)
@@ -101,8 +101,6 @@ void radeon_driver_irq_preinstall_kms(struct drm_device *dev);
 int radeon_driver_irq_postinstall_kms(struct drm_device *dev);
 void radeon_driver_irq_uninstall_kms(struct drm_device *dev);
 irqreturn_t radeon_driver_irq_handler_kms(DRM_IRQ_ARGS);
-int radeon_dma_ioctl_kms(struct drm_device *dev, void *data,
-                        struct drm_file *file_priv);
 int radeon_gem_object_init(struct drm_gem_object *obj);
 void radeon_gem_object_free(struct drm_gem_object *obj);
 int radeon_gem_object_open(struct drm_gem_object *obj,
@@ -390,8 +388,8 @@ static const struct file_operations radeon_driver_kms_fops = {
 
 static struct drm_driver kms_driver = {
        .driver_features =
-           DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG |
-           DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED | DRIVER_GEM |
+           DRIVER_USE_AGP | DRIVER_USE_MTRR | 
+           DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM |
            DRIVER_PRIME,
        .dev_priv_size = 0,
        .load = radeon_driver_load_kms,
@@ -421,7 +419,6 @@ static struct drm_driver kms_driver = {
        .gem_free_object = radeon_gem_object_free,
        .gem_open_object = radeon_gem_object_open,
        .gem_close_object = radeon_gem_object_close,
-       .dma_ioctl = radeon_dma_ioctl_kms,
        .dumb_create = radeon_mode_dumb_create,
        .dumb_map_offset = radeon_mode_dumb_mmap,
        .dumb_destroy = radeon_mode_dumb_destroy,
index 49ff3d1a610238009f242af5fdf4606d9a1951b9..07b023655bb4b6bb271eca8afda367b032d0319a 100644 (file)
@@ -683,16 +683,6 @@ int radeon_get_vblank_timestamp_kms(struct drm_device *dev, int crtc,
                                                     drmcrtc);
 }
 
-/*
- * IOCTL.
- */
-int radeon_dma_ioctl_kms(struct drm_device *dev, void *data,
-                        struct drm_file *file_priv)
-{
-       /* Not valid in KMS. */
-       return -EINVAL;
-}
-
 #define KMS_INVALID_IOCTL(name)                                                \
 int name(struct drm_device *dev, void *data, struct drm_file *file_priv)\
 {                                                                      \
index 49c82c4800134aa5500c8999c1e2e7c196330d2c..209b1115026379dccef518bf60ab9fa68217d9ab 100644 (file)
@@ -113,13 +113,10 @@ static inline unsigned radeon_bo_gpu_page_alignment(struct radeon_bo *bo)
  * @bo:        radeon object for which we query the offset
  *
  * Returns mmap offset of the object.
- *
- * Note: addr_space_offset is constant after ttm bo init thus isn't protected
- * by any lock.
  */
 static inline u64 radeon_bo_mmap_offset(struct radeon_bo *bo)
 {
-       return bo->tbo.addr_space_offset;
+       return drm_vma_node_offset_addr(&bo->tbo.vma_node);
 }
 
 extern int radeon_bo_wait(struct radeon_bo *bo, u32 *mem_type,
index d325280e2f9ffcc94b2260e802f6533c242f6546..8e23b6d1ba688c22f8461b019827f5eec20df86d 100644 (file)
@@ -3383,8 +3383,8 @@ static int si_cp_resume(struct radeon_device *rdev)
        /* ring 0 - compute and gfx */
        /* Set ring buffer size */
        ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
-       rb_bufsz = drm_order(ring->ring_size / 8);
-       tmp = (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
+       rb_bufsz = order_base_2(ring->ring_size / 8);
+       tmp = (order_base_2(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
 #ifdef __BIG_ENDIAN
        tmp |= BUF_SWAP_32BIT;
 #endif
@@ -3416,8 +3416,8 @@ static int si_cp_resume(struct radeon_device *rdev)
        /* ring1  - compute only */
        /* Set ring buffer size */
        ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX];
-       rb_bufsz = drm_order(ring->ring_size / 8);
-       tmp = (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
+       rb_bufsz = order_base_2(ring->ring_size / 8);
+       tmp = (order_base_2(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
 #ifdef __BIG_ENDIAN
        tmp |= BUF_SWAP_32BIT;
 #endif
@@ -3442,8 +3442,8 @@ static int si_cp_resume(struct radeon_device *rdev)
        /* ring2 - compute only */
        /* Set ring buffer size */
        ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX];
-       rb_bufsz = drm_order(ring->ring_size / 8);
-       tmp = (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
+       rb_bufsz = order_base_2(ring->ring_size / 8);
+       tmp = (order_base_2(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
 #ifdef __BIG_ENDIAN
        tmp |= BUF_SWAP_32BIT;
 #endif
@@ -5215,14 +5215,12 @@ static void si_enable_mc_ls(struct radeon_device *rdev,
 
 static void si_init_cg(struct radeon_device *rdev)
 {
-       bool has_uvd = true;
-
        si_enable_mgcg(rdev, true);
-       si_enable_cgcg(rdev, true);
+       si_enable_cgcg(rdev, false);
        /* disable MC LS on Tahiti */
        if (rdev->family == CHIP_TAHITI)
                si_enable_mc_ls(rdev, false);
-       if (has_uvd) {
+       if (rdev->has_uvd) {
                si_enable_uvd_mgcg(rdev, true);
                si_init_uvd_internal_cg(rdev);
        }
@@ -5230,9 +5228,7 @@ static void si_init_cg(struct radeon_device *rdev)
 
 static void si_fini_cg(struct radeon_device *rdev)
 {
-       bool has_uvd = true;
-
-       if (has_uvd)
+       if (rdev->has_uvd)
                si_enable_uvd_mgcg(rdev, false);
        si_enable_cgcg(rdev, false);
        si_enable_mgcg(rdev, false);
@@ -5241,11 +5237,11 @@ static void si_fini_cg(struct radeon_device *rdev)
 static void si_init_pg(struct radeon_device *rdev)
 {
        bool has_pg = false;
-
+#if 0
        /* only cape verde supports PG */
        if (rdev->family == CHIP_VERDE)
                has_pg = true;
-
+#endif
        if (has_pg) {
                si_init_ao_cu_mask(rdev);
                si_init_dma_pg(rdev);
@@ -5651,7 +5647,7 @@ static int si_irq_init(struct radeon_device *rdev)
        WREG32(INTERRUPT_CNTL, interrupt_cntl);
 
        WREG32(IH_RB_BASE, rdev->ih.gpu_addr >> 8);
-       rb_bufsz = drm_order(rdev->ih.ring_size / 4);
+       rb_bufsz = order_base_2(rdev->ih.ring_size / 4);
 
        ih_rb_cntl = (IH_WPTR_OVERFLOW_ENABLE |
                      IH_WPTR_OVERFLOW_CLEAR |
index 73aaa2e4c31272b6f4a28341f05e700e0c7bf42c..7ad22e87cd62aab0e4d990de3a72641c29310e55 100644 (file)
@@ -37,8 +37,6 @@
 
 #define SMC_RAM_END                 0x20000
 
-#define DDR3_DRAM_ROWS              0x2000
-
 #define SCLK_MIN_DEEPSLEEP_FREQ     1350
 
 static const struct si_cac_config_reg cac_weights_tahiti[] =
@@ -1767,8 +1765,9 @@ static void si_calculate_leakage_for_v_and_t_formula(const struct ni_leakage_coe
 {
        s64 kt, kv, leakage_w, i_leakage, vddc;
        s64 temperature, t_slope, t_intercept, av, bv, t_ref;
+       s64 tmp;
 
-       i_leakage = drm_int2fixp(ileakage / 100);
+       i_leakage = drm_int2fixp(ileakage) / 100;
        vddc = div64_s64(drm_int2fixp(v), 1000);
        temperature = div64_s64(drm_int2fixp(t), 1000);
 
@@ -1778,8 +1777,9 @@ static void si_calculate_leakage_for_v_and_t_formula(const struct ni_leakage_coe
        bv = div64_s64(drm_int2fixp(coeff->bv), 100000000);
        t_ref = drm_int2fixp(coeff->t_ref);
 
-       kt = drm_fixp_div(drm_fixp_exp(drm_fixp_mul(drm_fixp_mul(t_slope, vddc) + t_intercept, temperature)),
-                         drm_fixp_exp(drm_fixp_mul(drm_fixp_mul(t_slope, vddc) + t_intercept, t_ref)));
+       tmp = drm_fixp_mul(t_slope, vddc) + t_intercept;
+       kt = drm_fixp_exp(drm_fixp_mul(tmp, temperature));
+       kt = drm_fixp_div(kt, drm_fixp_exp(drm_fixp_mul(tmp, t_ref)));
        kv = drm_fixp_mul(av, drm_fixp_exp(drm_fixp_mul(bv, vddc)));
 
        leakage_w = drm_fixp_mul(drm_fixp_mul(drm_fixp_mul(i_leakage, kt), kv), vddc);
@@ -1931,6 +1931,7 @@ static void si_initialize_powertune_defaults(struct radeon_device *rdev)
                        si_pi->cac_override = cac_override_pitcairn;
                        si_pi->powertune_data = &powertune_data_pitcairn;
                        si_pi->dte_data = dte_data_pitcairn;
+                       break;
                }
        } else if (rdev->family == CHIP_VERDE) {
                si_pi->lcac_config = lcac_cape_verde;
@@ -1941,6 +1942,7 @@ static void si_initialize_powertune_defaults(struct radeon_device *rdev)
                case 0x683B:
                case 0x683F:
                case 0x6829:
+               case 0x6835:
                        si_pi->cac_weights = cac_weights_cape_verde_pro;
                        si_pi->dte_data = dte_data_cape_verde;
                        break;
@@ -3237,10 +3239,10 @@ int si_dpm_force_performance_level(struct radeon_device *rdev,
 {
        struct radeon_ps *rps = rdev->pm.dpm.current_ps;
        struct ni_ps *ps = ni_get_ps(rps);
-       u32 levels;
+       u32 levels = ps->performance_level_count;
 
        if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
-               if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 0) != PPSMC_Result_OK)
+               if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, levels) != PPSMC_Result_OK)
                        return -EINVAL;
 
                if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 1) != PPSMC_Result_OK)
@@ -3249,14 +3251,13 @@ int si_dpm_force_performance_level(struct radeon_device *rdev,
                if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK)
                        return -EINVAL;
 
-               levels = ps->performance_level_count - 1;
-               if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, levels) != PPSMC_Result_OK)
+               if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 1) != PPSMC_Result_OK)
                        return -EINVAL;
        } else if (level == RADEON_DPM_FORCED_LEVEL_AUTO) {
                if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK)
                        return -EINVAL;
 
-               if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 0) != PPSMC_Result_OK)
+               if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, levels) != PPSMC_Result_OK)
                        return -EINVAL;
        }
 
@@ -3620,8 +3621,12 @@ static void si_enable_display_gap(struct radeon_device *rdev)
 {
        u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL);
 
+       tmp &= ~(DISP1_GAP_MASK | DISP2_GAP_MASK);
+       tmp |= (DISP1_GAP(R600_PM_DISPLAY_GAP_IGNORE) |
+               DISP2_GAP(R600_PM_DISPLAY_GAP_IGNORE));
+
        tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK);
-       tmp |= (DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE) |
+       tmp |= (DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK) |
                DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE));
        WREG32(CG_DISPLAY_GAP_CNTL, tmp);
 }
@@ -4036,16 +4041,15 @@ static int si_force_switch_to_arb_f0(struct radeon_device *rdev)
 static u32 si_calculate_memory_refresh_rate(struct radeon_device *rdev,
                                            u32 engine_clock)
 {
-       struct rv7xx_power_info *pi = rv770_get_pi(rdev);
        u32 dram_rows;
        u32 dram_refresh_rate;
        u32 mc_arb_rfsh_rate;
        u32 tmp = (RREG32(MC_ARB_RAMCFG) & NOOFROWS_MASK) >> NOOFROWS_SHIFT;
 
-       if (pi->mem_gddr5)
-               dram_rows = 1 << (tmp + 10);
+       if (tmp >= 4)
+               dram_rows = 16384;
        else
-               dram_rows = DDR3_DRAM_ROWS;
+               dram_rows = 1 << (tmp + 10);
 
        dram_refresh_rate = 1 << ((RREG32(MC_SEQ_MISC0) & 0x3) + 3);
        mc_arb_rfsh_rate = ((engine_clock * 10) * dram_refresh_rate / dram_rows - 32) / 64;
@@ -6013,16 +6017,11 @@ int si_dpm_set_power_state(struct radeon_device *rdev)
                return ret;
        }
 
-#if 0
-       /* XXX */
        ret = si_dpm_force_performance_level(rdev, RADEON_DPM_FORCED_LEVEL_AUTO);
        if (ret) {
                DRM_ERROR("si_dpm_force_performance_level failed\n");
                return ret;
        }
-#else
-       rdev->pm.dpm.forced_level = RADEON_DPM_FORCED_LEVEL_AUTO;
-#endif
 
        return 0;
 }
index cb9dd674670c97f188bd0fa1eb765c97d4f62f8e..050edfaf5b889050c1414fccdad380b1a020dea3 100644 (file)
@@ -615,13 +615,7 @@ static void ttm_bo_release(struct kref *kref)
        struct ttm_bo_device *bdev = bo->bdev;
        struct ttm_mem_type_manager *man = &bdev->man[bo->mem.mem_type];
 
-       write_lock(&bdev->vm_lock);
-       if (likely(bo->vm_node != NULL)) {
-               rb_erase(&bo->vm_rb, &bdev->addr_space_rb);
-               drm_mm_put_block(bo->vm_node);
-               bo->vm_node = NULL;
-       }
-       write_unlock(&bdev->vm_lock);
+       drm_vma_offset_remove(&bdev->vma_manager, &bo->vma_node);
        ttm_mem_io_lock(man, false);
        ttm_mem_io_free_vm(bo);
        ttm_mem_io_unlock(man);
@@ -1129,6 +1123,7 @@ int ttm_bo_init(struct ttm_bo_device *bdev,
        bo->resv = &bo->ttm_resv;
        reservation_object_init(bo->resv);
        atomic_inc(&bo->glob->bo_count);
+       drm_vma_node_reset(&bo->vma_node);
 
        ret = ttm_bo_check_placement(bo, placement);
 
@@ -1424,10 +1419,7 @@ int ttm_bo_device_release(struct ttm_bo_device *bdev)
                TTM_DEBUG("Swap list was clean\n");
        spin_unlock(&glob->lru_lock);
 
-       BUG_ON(!drm_mm_clean(&bdev->addr_space_mm));
-       write_lock(&bdev->vm_lock);
-       drm_mm_takedown(&bdev->addr_space_mm);
-       write_unlock(&bdev->vm_lock);
+       drm_vma_offset_manager_destroy(&bdev->vma_manager);
 
        return ret;
 }
@@ -1441,7 +1433,6 @@ int ttm_bo_device_init(struct ttm_bo_device *bdev,
 {
        int ret = -EINVAL;
 
-       rwlock_init(&bdev->vm_lock);
        bdev->driver = driver;
 
        memset(bdev->man, 0, sizeof(bdev->man));
@@ -1454,9 +1445,8 @@ int ttm_bo_device_init(struct ttm_bo_device *bdev,
        if (unlikely(ret != 0))
                goto out_no_sys;
 
-       bdev->addr_space_rb = RB_ROOT;
-       drm_mm_init(&bdev->addr_space_mm, file_page_offset, 0x10000000);
-
+       drm_vma_offset_manager_init(&bdev->vma_manager, file_page_offset,
+                                   0x10000000);
        INIT_DELAYED_WORK(&bdev->wq, ttm_bo_delayed_workqueue);
        INIT_LIST_HEAD(&bdev->ddestroy);
        bdev->dev_mapping = NULL;
@@ -1498,12 +1488,8 @@ bool ttm_mem_reg_is_pci(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
 void ttm_bo_unmap_virtual_locked(struct ttm_buffer_object *bo)
 {
        struct ttm_bo_device *bdev = bo->bdev;
-       loff_t offset = (loff_t) bo->addr_space_offset;
-       loff_t holelen = ((loff_t) bo->mem.num_pages) << PAGE_SHIFT;
 
-       if (!bdev->dev_mapping)
-               return;
-       unmap_mapping_range(bdev->dev_mapping, offset, holelen, 1);
+       drm_vma_node_unmap(&bo->vma_node, bdev->dev_mapping);
        ttm_mem_io_free_vm(bo);
 }
 
@@ -1520,31 +1506,6 @@ void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo)
 
 EXPORT_SYMBOL(ttm_bo_unmap_virtual);
 
-static void ttm_bo_vm_insert_rb(struct ttm_buffer_object *bo)
-{
-       struct ttm_bo_device *bdev = bo->bdev;
-       struct rb_node **cur = &bdev->addr_space_rb.rb_node;
-       struct rb_node *parent = NULL;
-       struct ttm_buffer_object *cur_bo;
-       unsigned long offset = bo->vm_node->start;
-       unsigned long cur_offset;
-
-       while (*cur) {
-               parent = *cur;
-               cur_bo = rb_entry(parent, struct ttm_buffer_object, vm_rb);
-               cur_offset = cur_bo->vm_node->start;
-               if (offset < cur_offset)
-                       cur = &parent->rb_left;
-               else if (offset > cur_offset)
-                       cur = &parent->rb_right;
-               else
-                       BUG();
-       }
-
-       rb_link_node(&bo->vm_rb, parent, cur);
-       rb_insert_color(&bo->vm_rb, &bdev->addr_space_rb);
-}
-
 /**
  * ttm_bo_setup_vm:
  *
@@ -1559,38 +1520,9 @@ static void ttm_bo_vm_insert_rb(struct ttm_buffer_object *bo)
 static int ttm_bo_setup_vm(struct ttm_buffer_object *bo)
 {
        struct ttm_bo_device *bdev = bo->bdev;
-       int ret;
-
-retry_pre_get:
-       ret = drm_mm_pre_get(&bdev->addr_space_mm);
-       if (unlikely(ret != 0))
-               return ret;
-
-       write_lock(&bdev->vm_lock);
-       bo->vm_node = drm_mm_search_free(&bdev->addr_space_mm,
-                                        bo->mem.num_pages, 0, 0);
-
-       if (unlikely(bo->vm_node == NULL)) {
-               ret = -ENOMEM;
-               goto out_unlock;
-       }
-
-       bo->vm_node = drm_mm_get_block_atomic(bo->vm_node,
-                                             bo->mem.num_pages, 0);
 
-       if (unlikely(bo->vm_node == NULL)) {
-               write_unlock(&bdev->vm_lock);
-               goto retry_pre_get;
-       }
-
-       ttm_bo_vm_insert_rb(bo);
-       write_unlock(&bdev->vm_lock);
-       bo->addr_space_offset = ((uint64_t) bo->vm_node->start) << PAGE_SHIFT;
-
-       return 0;
-out_unlock:
-       write_unlock(&bdev->vm_lock);
-       return ret;
+       return drm_vma_offset_add(&bdev->vma_manager, &bo->vma_node,
+                                 bo->mem.num_pages);
 }
 
 int ttm_bo_wait(struct ttm_buffer_object *bo,
index 319cf4127c5b2b308523fe154f32b6fd0076b000..7cc904d3a4d12b4efd6935f75ed302335552a4aa 100644 (file)
@@ -30,6 +30,7 @@
 
 #include <drm/ttm/ttm_bo_driver.h>
 #include <drm/ttm/ttm_placement.h>
+#include <drm/drm_vma_manager.h>
 #include <linux/io.h>
 #include <linux/highmem.h>
 #include <linux/wait.h>
@@ -450,7 +451,7 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo,
        INIT_LIST_HEAD(&fbo->lru);
        INIT_LIST_HEAD(&fbo->swap);
        INIT_LIST_HEAD(&fbo->io_reserve_lru);
-       fbo->vm_node = NULL;
+       drm_vma_node_reset(&fbo->vma_node);
        atomic_set(&fbo->cpu_writers, 0);
 
        spin_lock(&bdev->fence_lock);
index 3df9f16b041cb214cc5570f890af2e892c25ac7e..8c0e2c0202157768e8cd113efebe5861ec2b569d 100644 (file)
@@ -33,6 +33,7 @@
 #include <ttm/ttm_module.h>
 #include <ttm/ttm_bo_driver.h>
 #include <ttm/ttm_placement.h>
+#include <drm/drm_vma_manager.h>
 #include <linux/mm.h>
 #include <linux/rbtree.h>
 #include <linux/module.h>
 
 #define TTM_BO_VM_NUM_PREFAULT 16
 
-static struct ttm_buffer_object *ttm_bo_vm_lookup_rb(struct ttm_bo_device *bdev,
-                                                    unsigned long page_start,
-                                                    unsigned long num_pages)
-{
-       struct rb_node *cur = bdev->addr_space_rb.rb_node;
-       unsigned long cur_offset;
-       struct ttm_buffer_object *bo;
-       struct ttm_buffer_object *best_bo = NULL;
-
-       while (likely(cur != NULL)) {
-               bo = rb_entry(cur, struct ttm_buffer_object, vm_rb);
-               cur_offset = bo->vm_node->start;
-               if (page_start >= cur_offset) {
-                       cur = cur->rb_right;
-                       best_bo = bo;
-                       if (page_start == cur_offset)
-                               break;
-               } else
-                       cur = cur->rb_left;
-       }
-
-       if (unlikely(best_bo == NULL))
-               return NULL;
-
-       if (unlikely((best_bo->vm_node->start + best_bo->num_pages) <
-                    (page_start + num_pages)))
-               return NULL;
-
-       return best_bo;
-}
-
 static int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
        struct ttm_buffer_object *bo = (struct ttm_buffer_object *)
@@ -146,9 +116,9 @@ static int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
        }
 
        page_offset = ((address - vma->vm_start) >> PAGE_SHIFT) +
-           bo->vm_node->start - vma->vm_pgoff;
+           drm_vma_node_start(&bo->vma_node) - vma->vm_pgoff;
        page_last = vma_pages(vma) +
-           bo->vm_node->start - vma->vm_pgoff;
+           drm_vma_node_start(&bo->vma_node) - vma->vm_pgoff;
 
        if (unlikely(page_offset >= bo->num_pages)) {
                retval = VM_FAULT_SIGBUS;
@@ -249,6 +219,30 @@ static const struct vm_operations_struct ttm_bo_vm_ops = {
        .close = ttm_bo_vm_close
 };
 
+static struct ttm_buffer_object *ttm_bo_vm_lookup(struct ttm_bo_device *bdev,
+                                                 unsigned long offset,
+                                                 unsigned long pages)
+{
+       struct drm_vma_offset_node *node;
+       struct ttm_buffer_object *bo = NULL;
+
+       drm_vma_offset_lock_lookup(&bdev->vma_manager);
+
+       node = drm_vma_offset_lookup_locked(&bdev->vma_manager, offset, pages);
+       if (likely(node)) {
+               bo = container_of(node, struct ttm_buffer_object, vma_node);
+               if (!kref_get_unless_zero(&bo->kref))
+                       bo = NULL;
+       }
+
+       drm_vma_offset_unlock_lookup(&bdev->vma_manager);
+
+       if (!bo)
+               pr_err("Could not find buffer object to map\n");
+
+       return bo;
+}
+
 int ttm_bo_mmap(struct file *filp, struct vm_area_struct *vma,
                struct ttm_bo_device *bdev)
 {
@@ -256,17 +250,9 @@ int ttm_bo_mmap(struct file *filp, struct vm_area_struct *vma,
        struct ttm_buffer_object *bo;
        int ret;
 
-       read_lock(&bdev->vm_lock);
-       bo = ttm_bo_vm_lookup_rb(bdev, vma->vm_pgoff,
-                                vma_pages(vma));
-       if (likely(bo != NULL) && !kref_get_unless_zero(&bo->kref))
-               bo = NULL;
-       read_unlock(&bdev->vm_lock);
-
-       if (unlikely(bo == NULL)) {
-               pr_err("Could not find buffer object to map\n");
+       bo = ttm_bo_vm_lookup(bdev, vma->vm_pgoff, vma_pages(vma));
+       if (unlikely(!bo))
                return -EINVAL;
-       }
 
        driver = bo->bdev->driver;
        if (unlikely(!driver->verify_access)) {
@@ -324,12 +310,7 @@ ssize_t ttm_bo_io(struct ttm_bo_device *bdev, struct file *filp,
        bool no_wait = false;
        bool dummy;
 
-       read_lock(&bdev->vm_lock);
-       bo = ttm_bo_vm_lookup_rb(bdev, dev_offset, 1);
-       if (likely(bo != NULL))
-               ttm_bo_reference(bo);
-       read_unlock(&bdev->vm_lock);
-
+       bo = ttm_bo_vm_lookup(bdev, dev_offset, 1);
        if (unlikely(bo == NULL))
                return -EFAULT;
 
@@ -343,7 +324,7 @@ ssize_t ttm_bo_io(struct ttm_bo_device *bdev, struct file *filp,
        if (unlikely(ret != 0))
                goto out_unref;
 
-       kmap_offset = dev_offset - bo->vm_node->start;
+       kmap_offset = dev_offset - drm_vma_node_start(&bo->vma_node);
        if (unlikely(kmap_offset >= bo->num_pages)) {
                ret = -EFBIG;
                goto out_unref;
index ef034fa3e6f5982a88fe2341a1fa03d38138d8fb..2a4cb2f83b36329adf994469335ab74f40282e2f 100644 (file)
@@ -223,8 +223,7 @@ void udl_gem_free_object(struct drm_gem_object *gem_obj)
        if (obj->pages)
                udl_gem_put_pages(obj);
 
-       if (gem_obj->map_list.map)
-               drm_gem_free_mmap_offset(gem_obj);
+       drm_gem_free_mmap_offset(gem_obj);
 }
 
 /* the dumb interface doesn't work with the GEM straight MMAP
@@ -247,13 +246,11 @@ int udl_gem_mmap(struct drm_file *file, struct drm_device *dev,
        ret = udl_gem_get_pages(gobj, GFP_KERNEL);
        if (ret)
                goto out;
-       if (!gobj->base.map_list.map) {
-               ret = drm_gem_create_mmap_offset(obj);
-               if (ret)
-                       goto out;
-       }
+       ret = drm_gem_create_mmap_offset(obj);
+       if (ret)
+               goto out;
 
-       *offset = (u64)gobj->base.map_list.hash.key << PAGE_SHIFT;
+       *offset = drm_vma_node_offset_addr(&gobj->base.vma_node);
 
 out:
        drm_gem_object_unreference(&gobj->base);
index 7953d1f90b63d4eeefb0a44c8a43d2eee3345991..0e67cf41065d801e6526d23dc5cdf375bdabe1c7 100644 (file)
@@ -500,7 +500,7 @@ int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data,
                goto out_no_dmabuf;
 
        rep->handle = handle;
-       rep->map_handle = dma_buf->base.addr_space_offset;
+       rep->map_handle = drm_vma_node_offset_addr(&dma_buf->base.vma_node);
        rep->cur_gmr_id = handle;
        rep->cur_gmr_offset = 0;
 
@@ -834,7 +834,7 @@ int vmw_dumb_map_offset(struct drm_file *file_priv,
        if (ret != 0)
                return -EINVAL;
 
-       *offset = out_buf->base.addr_space_offset;
+       *offset = drm_vma_node_offset_addr(&out_buf->base.vma_node);
        vmw_dmabuf_unreference(&out_buf);
        return 0;
 }
index c5e9a9b494c2c3b1973194bd49295d4585072556..bc323b3dbe4df01666e85f28c3bd36aa9bb4dbf2 100644 (file)
@@ -108,7 +108,7 @@ static void tegra_bo_destroy(struct drm_device *drm, struct tegra_bo *bo)
 
 unsigned int tegra_bo_get_mmap_offset(struct tegra_bo *bo)
 {
-       return (unsigned int)bo->gem.map_list.hash.key << PAGE_SHIFT;
+       return (unsigned int)drm_vma_node_offset_addr(&bo->gem.vma_node);
 }
 
 struct tegra_bo *tegra_bo_create(struct drm_device *drm, unsigned int size)
@@ -182,8 +182,7 @@ void tegra_bo_free_object(struct drm_gem_object *gem)
 {
        struct tegra_bo *bo = to_tegra_bo(gem);
 
-       if (gem->map_list.map)
-               drm_gem_free_mmap_offset(gem);
+       drm_gem_free_mmap_offset(gem);
 
        drm_gem_object_release(gem);
        tegra_bo_destroy(gem->dev, bo);
index 14ef6ab6979093605784dfe824c03ff931dd108c..3d7c9f67b6d7631504b9fbaed82fff152e295bb0 100644 (file)
@@ -743,6 +743,14 @@ config HID_WIIMOTE
        To compile this driver as a module, choose M here: the
        module will be called hid-wiimote.
 
+config HID_XINMO
+       tristate "Xin-Mo non-fully compliant devices"
+       depends on HID
+       ---help---
+       Support for Xin-Mo devices that are not fully compliant with the HID
+       standard. Currently only supports the Xin-Mo Dual Arcade. Say Y here
+       if you have a Xin-Mo Dual Arcade controller.
+
 config HID_ZEROPLUS
        tristate "Zeroplus based game controller support"
        depends on HID
index 6f687287e2125168fbfa46ab0f8d9384a08dc797..a959f4aecaf5754d1fd9499b1bad386e57615df5 100644 (file)
@@ -110,6 +110,7 @@ obj-$(CONFIG_HID_TIVO)              += hid-tivo.o
 obj-$(CONFIG_HID_TOPSEED)      += hid-topseed.o
 obj-$(CONFIG_HID_TWINHAN)      += hid-twinhan.o
 obj-$(CONFIG_HID_UCLOGIC)      += hid-uclogic.o
+obj-$(CONFIG_HID_XINMO)                += hid-xinmo.o
 obj-$(CONFIG_HID_ZEROPLUS)     += hid-zpff.o
 obj-$(CONFIG_HID_ZYDACRON)     += hid-zydacron.o
 obj-$(CONFIG_HID_WACOM)                += hid-wacom.o
index 7c5507e94820cc93b8867884dad993244431668a..9428ea7cdf8a00dc686e00c6da77be5cb60215b7 100644 (file)
@@ -90,11 +90,10 @@ static int a4_probe(struct hid_device *hdev, const struct hid_device_id *id)
        struct a4tech_sc *a4;
        int ret;
 
-       a4 = kzalloc(sizeof(*a4), GFP_KERNEL);
+       a4 = devm_kzalloc(&hdev->dev, sizeof(*a4), GFP_KERNEL);
        if (a4 == NULL) {
                hid_err(hdev, "can't alloc device descriptor\n");
-               ret = -ENOMEM;
-               goto err_free;
+               return -ENOMEM;
        }
 
        a4->quirks = id->driver_data;
@@ -104,27 +103,16 @@ static int a4_probe(struct hid_device *hdev, const struct hid_device_id *id)
        ret = hid_parse(hdev);
        if (ret) {
                hid_err(hdev, "parse failed\n");
-               goto err_free;
+               return ret;
        }
 
        ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
        if (ret) {
                hid_err(hdev, "hw start failed\n");
-               goto err_free;
+               return ret;
        }
 
        return 0;
-err_free:
-       kfree(a4);
-       return ret;
-}
-
-static void a4_remove(struct hid_device *hdev)
-{
-       struct a4tech_sc *a4 = hid_get_drvdata(hdev);
-
-       hid_hw_stop(hdev);
-       kfree(a4);
 }
 
 static const struct hid_device_id a4_devices[] = {
@@ -144,7 +132,6 @@ static struct hid_driver a4_driver = {
        .input_mapped = a4_input_mapped,
        .event = a4_event,
        .probe = a4_probe,
-       .remove = a4_remove,
 };
 module_hid_driver(a4_driver);
 
index c7710b5c69afbf009d0e9f2d727668e6cdae5045..881cf7b4f9a433f8ae3e0f6721b3789aa66731f7 100644 (file)
@@ -349,7 +349,7 @@ static int apple_probe(struct hid_device *hdev,
        unsigned int connect_mask = HID_CONNECT_DEFAULT;
        int ret;
 
-       asc = kzalloc(sizeof(*asc), GFP_KERNEL);
+       asc = devm_kzalloc(&hdev->dev, sizeof(*asc), GFP_KERNEL);
        if (asc == NULL) {
                hid_err(hdev, "can't alloc apple descriptor\n");
                return -ENOMEM;
@@ -362,7 +362,7 @@ static int apple_probe(struct hid_device *hdev,
        ret = hid_parse(hdev);
        if (ret) {
                hid_err(hdev, "parse failed\n");
-               goto err_free;
+               return ret;
        }
 
        if (quirks & APPLE_HIDDEV)
@@ -373,19 +373,10 @@ static int apple_probe(struct hid_device *hdev,
        ret = hid_hw_start(hdev, connect_mask);
        if (ret) {
                hid_err(hdev, "hw start failed\n");
-               goto err_free;
+               return ret;
        }
 
        return 0;
-err_free:
-       kfree(asc);
-       return ret;
-}
-
-static void apple_remove(struct hid_device *hdev)
-{
-       hid_hw_stop(hdev);
-       kfree(hid_get_drvdata(hdev));
 }
 
 static const struct hid_device_id apple_devices[] = {
@@ -551,7 +542,6 @@ static struct hid_driver apple_driver = {
        .id_table = apple_devices,
        .report_fixup = apple_report_fixup,
        .probe = apple_probe,
-       .remove = apple_remove,
        .event = apple_event,
        .input_mapping = apple_input_mapping,
        .input_mapped = apple_input_mapped,
index 36668d1aca8fc2133299e93cf994857d78cbea2e..3efe19f4deaed585548615e1fa1cb4fbc5ffeed7 100644 (file)
@@ -450,7 +450,7 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
                        }
                        parser->local.delimiter_depth--;
                }
-               return 1;
+               return 0;
 
        case HID_LOCAL_ITEM_TAG_USAGE:
 
@@ -1128,7 +1128,8 @@ static void hid_output_field(const struct hid_device *hid,
 }
 
 /*
- * Create a report.
+ * Create a report. 'data' has to be allocated using
+ * hid_alloc_report_buf() so that it has proper size.
  */
 
 void hid_output_report(struct hid_report *report, __u8 *data)
@@ -1144,6 +1145,22 @@ void hid_output_report(struct hid_report *report, __u8 *data)
 }
 EXPORT_SYMBOL_GPL(hid_output_report);
 
+/*
+ * Allocator for buffer that is going to be passed to hid_output_report()
+ */
+u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags)
+{
+       /*
+        * 7 extra bytes are necessary to achieve proper functionality
+        * of implement() working on 8 byte chunks
+        */
+
+       int len = ((report->size - 1) >> 3) + 1 + (report->id > 0) + 7;
+
+       return kmalloc(len, flags);
+}
+EXPORT_SYMBOL_GPL(hid_alloc_report_buf);
+
 /*
  * Set a field value. The report this field belongs to has to be
  * created and transferred to the device, to set this value in the
@@ -1597,6 +1614,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_GX_IMPERATOR) },
        { 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) },
@@ -1736,6 +1754,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET) },
        { HID_USB_DEVICE(USB_VENDOR_ID_X_TENSIONS, USB_DEVICE_ID_SPEEDLINK_VAD_CEZANNE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_XIN_MO_DUAL_ARCADE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ZYDACRON, USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL) },
index ffe4c7ae3340150cdcfb8c9f3db9c241422cf8eb..4f01a52c98abda7f60252debf6dacaa53c80ab35 100644 (file)
 #define USB_VENDOR_ID_KYE              0x0458
 #define USB_DEVICE_ID_KYE_ERGO_525V    0x0087
 #define USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE 0x0138
+#define USB_DEVICE_ID_GENIUS_GX_IMPERATOR      0x4018
 #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_VENDOR_ID_XAT      0x2505
 #define USB_DEVICE_ID_XAT_CSR  0x0220
 
+#define USB_VENDOR_ID_XIN_MO                   0x16c0
+#define USB_DEVICE_ID_XIN_MO_DUAL_ARCADE       0x05e1
+
 #define USB_VENDOR_ID_XIROKU           0x1477
 #define USB_DEVICE_ID_XIROKU_SPX       0x1006
 #define USB_DEVICE_ID_XIROKU_MPX       0x1007
index 7480799e535cb229a8bae89cf3795d1a5e91b738..308eee8fc7c3b1145b62b5508404d24655c355f9 100644 (file)
@@ -1137,6 +1137,74 @@ unsigned int hidinput_count_leds(struct hid_device *hid)
 }
 EXPORT_SYMBOL_GPL(hidinput_count_leds);
 
+static void hidinput_led_worker(struct work_struct *work)
+{
+       struct hid_device *hid = container_of(work, struct hid_device,
+                                             led_work);
+       struct hid_field *field;
+       struct hid_report *report;
+       int len;
+       __u8 *buf;
+
+       field = hidinput_get_led_field(hid);
+       if (!field)
+               return;
+
+       /*
+        * field->report is accessed unlocked regarding HID core. So there might
+        * be another incoming SET-LED request from user-space, which changes
+        * the LED state while we assemble our outgoing buffer. However, this
+        * doesn't matter as hid_output_report() correctly converts it into a
+        * boolean value no matter what information is currently set on the LED
+        * field (even garbage). So the remote device will always get a valid
+        * request.
+        * And in case we send a wrong value, a next led worker is spawned
+        * for every SET-LED request so the following worker will send the
+        * correct value, guaranteed!
+        */
+
+       report = field->report;
+
+       /* use custom SET_REPORT request if possible (asynchronous) */
+       if (hid->ll_driver->request)
+               return hid->ll_driver->request(hid, report, HID_REQ_SET_REPORT);
+
+       /* fall back to generic raw-output-report */
+       len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
+       buf = kmalloc(len, GFP_KERNEL);
+       if (!buf)
+               return;
+
+       hid_output_report(report, buf);
+       /* synchronous output report */
+       hid->hid_output_raw_report(hid, buf, len, HID_OUTPUT_REPORT);
+       kfree(buf);
+}
+
+static int hidinput_input_event(struct input_dev *dev, unsigned int type,
+                               unsigned int code, int value)
+{
+       struct hid_device *hid = input_get_drvdata(dev);
+       struct hid_field *field;
+       int offset;
+
+       if (type == EV_FF)
+               return input_ff_event(dev, type, code, value);
+
+       if (type != EV_LED)
+               return -1;
+
+       if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {
+               hid_warn(dev, "event field not found\n");
+               return -1;
+       }
+
+       hid_set_field(field, offset, value);
+
+       schedule_work(&hid->led_work);
+       return 0;
+}
+
 static int hidinput_open(struct input_dev *dev)
 {
        struct hid_device *hid = input_get_drvdata(dev);
@@ -1183,7 +1251,10 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid)
        }
 
        input_set_drvdata(input_dev, hid);
-       input_dev->event = hid->ll_driver->hidinput_input_event;
+       if (hid->ll_driver->hidinput_input_event)
+               input_dev->event = hid->ll_driver->hidinput_input_event;
+       else if (hid->ll_driver->request || hid->hid_output_raw_report)
+               input_dev->event = hidinput_input_event;
        input_dev->open = hidinput_open;
        input_dev->close = hidinput_close;
        input_dev->setkeycode = hidinput_setkeycode;
@@ -1278,6 +1349,7 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
        int i, j, k;
 
        INIT_LIST_HEAD(&hid->inputs);
+       INIT_WORK(&hid->led_work, hidinput_led_worker);
 
        if (!force) {
                for (i = 0; i < hid->maxcollection; i++) {
@@ -1379,6 +1451,12 @@ void hidinput_disconnect(struct hid_device *hid)
                input_unregister_device(hidinput->input);
                kfree(hidinput);
        }
+
+       /* led_work is spawned by input_dev callbacks, but doesn't access the
+        * parent input_dev at all. Once all input devices are removed, we
+        * know that led_work will never get restarted, so we can cancel it
+        * synchronously and are safe. */
+       cancel_work_sync(&hid->led_work);
 }
 EXPORT_SYMBOL_GPL(hidinput_disconnect);
 
index 1e2ee2aa84a023fc5e4412c7fe8c04666a3e6a8e..73845120295eba6f678679715c9ca3f97917a643 100644 (file)
@@ -268,6 +268,26 @@ static __u8 easypen_m610x_rdesc_fixed[] = {
        0xC0                          /*  End Collection                  */
 };
 
+static __u8 *kye_consumer_control_fixup(struct hid_device *hdev, __u8 *rdesc,
+               unsigned int *rsize, int offset, const char *device_name) {
+       /*
+        * the fixup that need to be done:
+        *   - change Usage Maximum in the Comsumer Control
+        *     (report ID 3) to a reasonable value
+        */
+       if (*rsize >= offset + 31 &&
+           /* Usage Page (Consumer Devices) */
+           rdesc[offset] == 0x05 && rdesc[offset + 1] == 0x0c &&
+           /* Usage (Consumer Control) */
+           rdesc[offset + 2] == 0x09 && rdesc[offset + 3] == 0x01 &&
+           /*   Usage Maximum > 12287 */
+           rdesc[offset + 10] == 0x2a && rdesc[offset + 12] > 0x2f) {
+               hid_info(hdev, "fixing up %s report descriptor\n", device_name);
+               rdesc[offset + 12] = 0x2f;
+       }
+       return rdesc;
+}
+
 static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                unsigned int *rsize)
 {
@@ -315,23 +335,12 @@ static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                }
                break;
        case USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE:
-               /*
-                * the fixup that need to be done:
-                *   - change Usage Maximum in the Comsumer Control
-                *     (report ID 3) to a reasonable value
-                */
-               if (*rsize >= 135 &&
-                       /* Usage Page (Consumer Devices) */
-                       rdesc[104] == 0x05 && rdesc[105] == 0x0c &&
-                       /* Usage (Consumer Control) */
-                       rdesc[106] == 0x09 && rdesc[107] == 0x01 &&
-                       /*   Usage Maximum > 12287 */
-                       rdesc[114] == 0x2a && rdesc[116] > 0x2f) {
-                       hid_info(hdev,
-                                "fixing up Genius Gila Gaming Mouse "
-                                "report descriptor\n");
-                       rdesc[116] = 0x2f;
-               }
+               rdesc = kye_consumer_control_fixup(hdev, rdesc, rsize, 104,
+                                       "Genius Gila Gaming Mouse");
+               break;
+       case USB_DEVICE_ID_GENIUS_GX_IMPERATOR:
+               rdesc = kye_consumer_control_fixup(hdev, rdesc, rsize, 83,
+                                       "Genius Gx Imperator Keyboard");
                break;
        }
        return rdesc;
@@ -428,6 +437,8 @@ static const struct hid_device_id kye_devices[] = {
                                USB_DEVICE_ID_KYE_EASYPEN_M610X) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KYE,
                                USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_KYE,
+                               USB_DEVICE_ID_GENIUS_GX_IMPERATOR) },
        { }
 };
 MODULE_DEVICE_TABLE(hid, kye_devices);
index 5207591a598c05944a348be2252c4a346e0e5cfa..e7ad88effd4018f4dbbd02358e37d7e9a41e3ca7 100644 (file)
@@ -574,7 +574,7 @@ static int logi_dj_ll_input_event(struct input_dev *dev, unsigned int type,
 
        struct hid_field *field;
        struct hid_report *report;
-       unsigned char data[8];
+       unsigned char *data;
        int offset;
 
        dbg_hid("%s: %s, type:%d | code:%d | value:%d\n",
@@ -590,6 +590,13 @@ static int logi_dj_ll_input_event(struct input_dev *dev, unsigned int type,
                return -1;
        }
        hid_set_field(field, offset, value);
+
+       data = hid_alloc_report_buf(field->report, GFP_ATOMIC);
+       if (!data) {
+               dev_warn(&dev->dev, "failed to allocate report buf memory\n");
+               return -1;
+       }
+
        hid_output_report(field->report, &data[0]);
 
        output_report_enum = &dj_rcv_hiddev->report_enum[HID_OUTPUT_REPORT];
@@ -600,8 +607,9 @@ static int logi_dj_ll_input_event(struct input_dev *dev, unsigned int type,
 
        hid_hw_request(dj_rcv_hiddev, report, HID_REQ_SET_REPORT);
 
-       return 0;
+       kfree(data);
 
+       return 0;
 }
 
 static int logi_dj_ll_start(struct hid_device *hid)
@@ -756,10 +764,10 @@ static int logi_dj_probe(struct hid_device *hdev,
        }
 
        /* This is enabling the polling urb on the IN endpoint */
-       retval = hdev->ll_driver->open(hdev);
+       retval = hid_hw_open(hdev);
        if (retval < 0) {
-               dev_err(&hdev->dev, "%s:hdev->ll_driver->open returned "
-                       "error:%d\n", __func__, retval);
+               dev_err(&hdev->dev, "%s:hid_hw_open returned error:%d\n",
+                       __func__, retval);
                goto llopen_failed;
        }
 
@@ -776,7 +784,7 @@ static int logi_dj_probe(struct hid_device *hdev,
        return retval;
 
 logi_dj_recv_query_paired_devices_failed:
-       hdev->ll_driver->close(hdev);
+       hid_hw_close(hdev);
 
 llopen_failed:
 switch_to_dj_mode_fail:
@@ -818,7 +826,7 @@ static void logi_dj_remove(struct hid_device *hdev)
 
        cancel_work_sync(&djrcv_dev->work);
 
-       hdev->ll_driver->close(hdev);
+       hid_hw_close(hdev);
        hid_hw_stop(hdev);
 
        /* I suppose that at this point the only context that can access
index 5bc37343eb22b3de7f3cca6163c6f1fd9a10dd4b..3b43d1cfa9368609302de46a73658779199d446f 100644 (file)
@@ -36,7 +36,7 @@ MODULE_PARM_DESC(emulate_scroll_wheel, "Emulate a scroll wheel");
 static unsigned int scroll_speed = 32;
 static int param_set_scroll_speed(const char *val, struct kernel_param *kp) {
        unsigned long speed;
-       if (!val || strict_strtoul(val, 0, &speed) || speed > 63)
+       if (!val || kstrtoul(val, 0, &speed) || speed > 63)
                return -EINVAL;
        scroll_speed = speed;
        return 0;
@@ -484,7 +484,7 @@ static int magicmouse_probe(struct hid_device *hdev,
        struct hid_report *report;
        int ret;
 
-       msc = kzalloc(sizeof(*msc), GFP_KERNEL);
+       msc = devm_kzalloc(&hdev->dev, sizeof(*msc), GFP_KERNEL);
        if (msc == NULL) {
                hid_err(hdev, "can't alloc magicmouse descriptor\n");
                return -ENOMEM;
@@ -498,13 +498,13 @@ static int magicmouse_probe(struct hid_device *hdev,
        ret = hid_parse(hdev);
        if (ret) {
                hid_err(hdev, "magicmouse hid parse failed\n");
-               goto err_free;
+               return ret;
        }
 
        ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
        if (ret) {
                hid_err(hdev, "magicmouse hw start failed\n");
-               goto err_free;
+               return ret;
        }
 
        if (!msc->input) {
@@ -548,19 +548,9 @@ static int magicmouse_probe(struct hid_device *hdev,
        return 0;
 err_stop_hw:
        hid_hw_stop(hdev);
-err_free:
-       kfree(msc);
        return ret;
 }
 
-static void magicmouse_remove(struct hid_device *hdev)
-{
-       struct magicmouse_sc *msc = hid_get_drvdata(hdev);
-
-       hid_hw_stop(hdev);
-       kfree(msc);
-}
-
 static const struct hid_device_id magic_mice[] = {
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
                USB_DEVICE_ID_APPLE_MAGICMOUSE), .driver_data = 0 },
@@ -574,7 +564,6 @@ static struct hid_driver magicmouse_driver = {
        .name = "magicmouse",
        .id_table = magic_mice,
        .probe = magicmouse_probe,
-       .remove = magicmouse_remove,
        .raw_event = magicmouse_raw_event,
        .input_mapping = magicmouse_input_mapping,
        .input_configured = magicmouse_input_configured,
index cb0e361d7a4be8e5e790f9ab250ffbfd17c52fe7..0fe00e2552f23aebbdbeb408ef18a7be46d115c9 100644 (file)
@@ -261,17 +261,6 @@ static struct mt_class mt_classes[] = {
        { }
 };
 
-static void mt_free_input_name(struct hid_input *hi)
-{
-       struct hid_device *hdev = hi->report->device;
-       const char *name = hi->input->name;
-
-       if (name != hdev->name) {
-               hi->input->name = hdev->name;
-               kfree(name);
-       }
-}
-
 static ssize_t mt_show_quirks(struct device *dev,
                           struct device_attribute *attr,
                           char *buf)
@@ -415,13 +404,6 @@ static void mt_pen_report(struct hid_device *hid, struct hid_report *report)
 static void mt_pen_input_configured(struct hid_device *hdev,
                                        struct hid_input *hi)
 {
-       char *name = kzalloc(strlen(hi->input->name) + 5, GFP_KERNEL);
-       if (name) {
-               sprintf(name, "%s Pen", hi->input->name);
-               mt_free_input_name(hi);
-               hi->input->name = name;
-       }
-
        /* force BTN_STYLUS to allow tablet matching in udev */
        __set_bit(BTN_STYLUS, hi->input->keybit);
 }
@@ -928,16 +910,26 @@ static void mt_post_parse(struct mt_device *td)
 static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
 {
        struct mt_device *td = hid_get_drvdata(hdev);
-       char *name = kstrdup(hdev->name, GFP_KERNEL);
-
-       if (name)
-               hi->input->name = name;
+       char *name;
+       const char *suffix = NULL;
 
        if (hi->report->id == td->mt_report_id)
                mt_touch_input_configured(hdev, hi);
 
-       if (hi->report->id == td->pen_report_id)
+       if (hi->report->field[0]->physical == HID_DG_STYLUS) {
+               suffix = "Pen";
                mt_pen_input_configured(hdev, hi);
+       }
+
+       if (suffix) {
+               name = devm_kzalloc(&hi->input->dev,
+                                   strlen(hdev->name) + strlen(suffix) + 2,
+                                   GFP_KERNEL);
+               if (name) {
+                       sprintf(name, "%s %s", hdev->name, suffix);
+                       hi->input->name = name;
+               }
+       }
 }
 
 static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
@@ -945,7 +937,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
        int ret, i;
        struct mt_device *td;
        struct mt_class *mtclass = mt_classes; /* MT_CLS_DEFAULT */
-       struct hid_input *hi;
 
        for (i = 0; mt_classes[i].name ; i++) {
                if (id->driver_data == mt_classes[i].name) {
@@ -967,7 +958,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
        hdev->quirks |= HID_QUIRK_MULTI_INPUT;
        hdev->quirks |= HID_QUIRK_NO_EMPTY_INPUT;
 
-       td = kzalloc(sizeof(struct mt_device), GFP_KERNEL);
+       td = devm_kzalloc(&hdev->dev, sizeof(struct mt_device), GFP_KERNEL);
        if (!td) {
                dev_err(&hdev->dev, "cannot allocate multitouch data\n");
                return -ENOMEM;
@@ -980,11 +971,11 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
        td->pen_report_id = -1;
        hid_set_drvdata(hdev, td);
 
-       td->fields = kzalloc(sizeof(struct mt_fields), GFP_KERNEL);
+       td->fields = devm_kzalloc(&hdev->dev, sizeof(struct mt_fields),
+                                 GFP_KERNEL);
        if (!td->fields) {
                dev_err(&hdev->dev, "cannot allocate multitouch fields data\n");
-               ret = -ENOMEM;
-               goto fail;
+               return -ENOMEM;
        }
 
        if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID)
@@ -992,29 +983,22 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        ret = hid_parse(hdev);
        if (ret != 0)
-               goto fail;
+               return ret;
 
        ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
        if (ret)
-               goto hid_fail;
+               return ret;
 
        ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group);
 
        mt_set_maxcontacts(hdev);
        mt_set_input_mode(hdev);
 
-       kfree(td->fields);
+       /* release .fields memory as it is not used anymore */
+       devm_kfree(&hdev->dev, td->fields);
        td->fields = NULL;
 
        return 0;
-
-hid_fail:
-       list_for_each_entry(hi, &hdev->inputs, list)
-               mt_free_input_name(hi);
-fail:
-       kfree(td->fields);
-       kfree(td);
-       return ret;
 }
 
 #ifdef CONFIG_PM
@@ -1039,17 +1023,8 @@ static int mt_resume(struct hid_device *hdev)
 
 static void mt_remove(struct hid_device *hdev)
 {
-       struct mt_device *td = hid_get_drvdata(hdev);
-       struct hid_input *hi;
-
        sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
-       list_for_each_entry(hi, &hdev->inputs, list)
-               mt_free_input_name(hi);
-
        hid_hw_stop(hdev);
-
-       kfree(td);
-       hid_set_drvdata(hdev, NULL);
 }
 
 static const struct hid_device_id mt_devices[] = {
index ef95102515e4d499143dd02a831481902d674b1e..98d1fdf7d8cd0d2e3d5c7ae6b240e15085a951d7 100644 (file)
@@ -237,7 +237,7 @@ static ssize_t set_min_width(struct device *dev,
 
        unsigned long val;
 
-       if (strict_strtoul(buf, 0, &val))
+       if (kstrtoul(buf, 0, &val))
                return -EINVAL;
 
        if (val > nd->sensor_physical_width)
@@ -272,7 +272,7 @@ static ssize_t set_min_height(struct device *dev,
 
        unsigned long val;
 
-       if (strict_strtoul(buf, 0, &val))
+       if (kstrtoul(buf, 0, &val))
                return -EINVAL;
 
        if (val > nd->sensor_physical_height)
@@ -306,7 +306,7 @@ static ssize_t set_activate_slack(struct device *dev,
 
        unsigned long val;
 
-       if (strict_strtoul(buf, 0, &val))
+       if (kstrtoul(buf, 0, &val))
                return -EINVAL;
 
        if (val > 0x7f)
@@ -341,7 +341,7 @@ static ssize_t set_activation_width(struct device *dev,
 
        unsigned long val;
 
-       if (strict_strtoul(buf, 0, &val))
+       if (kstrtoul(buf, 0, &val))
                return -EINVAL;
 
        if (val > nd->sensor_physical_width)
@@ -377,7 +377,7 @@ static ssize_t set_activation_height(struct device *dev,
 
        unsigned long val;
 
-       if (strict_strtoul(buf, 0, &val))
+       if (kstrtoul(buf, 0, &val))
                return -EINVAL;
 
        if (val > nd->sensor_physical_height)
@@ -411,7 +411,7 @@ static ssize_t set_deactivate_slack(struct device *dev,
 
        unsigned long val;
 
-       if (strict_strtoul(buf, 0, &val))
+       if (kstrtoul(buf, 0, &val))
                return -EINVAL;
 
        /*
index 59ab8e157e6b249d025ea26d4bd0ba4b2bb7f227..024cdf3c2297f91d6288cd13cf75e3a4c4881991 100644 (file)
@@ -394,7 +394,7 @@ static void dump_buff_as_hex(char *dst, size_t dst_sz, const u8 *data,
 void picolcd_debug_out_report(struct picolcd_data *data,
                struct hid_device *hdev, struct hid_report *report)
 {
-       u8 raw_data[70];
+       u8 *raw_data;
        int raw_size = (report->size >> 3) + 1;
        char *buff;
 #define BUFF_SZ 256
@@ -407,20 +407,20 @@ void picolcd_debug_out_report(struct picolcd_data *data,
        if (!buff)
                return;
 
-       snprintf(buff, BUFF_SZ, "\nout report %d (size %d) =  ",
-                       report->id, raw_size);
-       hid_debug_event(hdev, buff);
-       if (raw_size + 5 > sizeof(raw_data)) {
+       raw_data = hid_alloc_report_buf(report, GFP_ATOMIC);
+       if (!raw_data) {
                kfree(buff);
-               hid_debug_event(hdev, " TOO BIG\n");
                return;
-       } else {
-               raw_data[0] = report->id;
-               hid_output_report(report, raw_data);
-               dump_buff_as_hex(buff, BUFF_SZ, raw_data, raw_size);
-               hid_debug_event(hdev, buff);
        }
 
+       snprintf(buff, BUFF_SZ, "\nout report %d (size %d) =  ",
+                       report->id, raw_size);
+       hid_debug_event(hdev, buff);
+       raw_data[0] = report->id;
+       hid_output_report(report, raw_data);
+       dump_buff_as_hex(buff, BUFF_SZ, raw_data, raw_size);
+       hid_debug_event(hdev, buff);
+
        switch (report->id) {
        case REPORT_LED_STATE:
                /* 1 data byte with GPO state */
@@ -644,6 +644,7 @@ void picolcd_debug_out_report(struct picolcd_data *data,
                break;
        }
        wake_up_interruptible(&hdev->debug_wait);
+       kfree(raw_data);
        kfree(buff);
 }
 
index 327f9b8ed1f4ea3cea3e89166c29570a9539d306..071ee9e2fd9fea5c4d40165e60e6f1b71e5bd7a4 100644 (file)
@@ -59,7 +59,7 @@ static ssize_t arvo_sysfs_set_mode_key(struct device *dev,
        unsigned long state;
        int retval;
 
-       retval = strict_strtoul(buf, 10, &state);
+       retval = kstrtoul(buf, 10, &state);
        if (retval)
                return retval;
 
@@ -107,7 +107,7 @@ static ssize_t arvo_sysfs_set_key_mask(struct device *dev,
        unsigned long key_mask;
        int retval;
 
-       retval = strict_strtoul(buf, 10, &key_mask);
+       retval = kstrtoul(buf, 10, &key_mask);
        if (retval)
                return retval;
 
@@ -159,7 +159,7 @@ static ssize_t arvo_sysfs_set_actual_profile(struct device *dev,
        unsigned long profile;
        int retval;
 
-       retval = strict_strtoul(buf, 10, &profile);
+       retval = kstrtoul(buf, 10, &profile);
        if (retval)
                return retval;
 
index 8023751d525766ae16b32f8a8943f8c5f9b0796e..5dd0ea4eb4f71ec6cfc210b5a71a8b648a709461 100644 (file)
@@ -82,7 +82,7 @@ static ssize_t isku_sysfs_set_actual_profile(struct device *dev,
        isku = hid_get_drvdata(dev_get_drvdata(dev));
        usb_dev = interface_to_usbdev(to_usb_interface(dev));
 
-       retval = strict_strtoul(buf, 10, &profile);
+       retval = kstrtoul(buf, 10, &profile);
        if (retval)
                return retval;
 
index 7fae070788fa2e4b03fb9281e792aaf9e24065a4..00ab287f73849b94d85c3d4bf603733273396fc6 100644 (file)
@@ -456,7 +456,7 @@ static ssize_t kone_sysfs_set_tcu(struct device *dev,
        kone = hid_get_drvdata(dev_get_drvdata(dev));
        usb_dev = interface_to_usbdev(to_usb_interface(dev));
 
-       retval = strict_strtoul(buf, 10, &state);
+       retval = kstrtoul(buf, 10, &state);
        if (retval)
                return retval;
 
@@ -545,7 +545,7 @@ static ssize_t kone_sysfs_set_startup_profile(struct device *dev,
        kone = hid_get_drvdata(dev_get_drvdata(dev));
        usb_dev = interface_to_usbdev(to_usb_interface(dev));
 
-       retval = strict_strtoul(buf, 10, &new_startup_profile);
+       retval = kstrtoul(buf, 10, &new_startup_profile);
        if (retval)
                return retval;
 
index 6a48fa3c7da913e487e5aa0b1538ba5aff19bbb1..26b9663ddf4746ce1590733745d77f512c46d8c0 100644 (file)
@@ -246,7 +246,7 @@ static ssize_t koneplus_sysfs_set_actual_profile(struct device *dev,
        koneplus = hid_get_drvdata(dev_get_drvdata(dev));
        usb_dev = interface_to_usbdev(to_usb_interface(dev));
 
-       retval = strict_strtoul(buf, 10, &profile);
+       retval = kstrtoul(buf, 10, &profile);
        if (retval)
                return retval;
 
index b8b37789b864bbeb3c4de24047658172518b25ec..c2a17e45c99cb6fa49443e68c0b37fe9f7839f99 100644 (file)
@@ -282,7 +282,7 @@ static ssize_t kovaplus_sysfs_set_actual_profile(struct device *dev,
        kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
        usb_dev = interface_to_usbdev(to_usb_interface(dev));
 
-       retval = strict_strtoul(buf, 10, &profile);
+       retval = kstrtoul(buf, 10, &profile);
        if (retval)
                return retval;
 
index ecbc74923d063d6494aaa4648f08d91a6c44e686..f9898aad72fa324b5c00fcbecbceeb5cbfee6e9b 100644 (file)
@@ -623,7 +623,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
        struct sony_sc *sc;
        unsigned int connect_mask = HID_CONNECT_DEFAULT;
 
-       sc = kzalloc(sizeof(*sc), GFP_KERNEL);
+       sc = devm_kzalloc(&hdev->dev, sizeof(*sc), GFP_KERNEL);
        if (sc == NULL) {
                hid_err(hdev, "can't alloc sony descriptor\n");
                return -ENOMEM;
@@ -635,7 +635,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
        ret = hid_parse(hdev);
        if (ret) {
                hid_err(hdev, "parse failed\n");
-               goto err_free;
+               return ret;
        }
 
        if (sc->quirks & VAIO_RDESC_CONSTANT)
@@ -648,7 +648,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
        ret = hid_hw_start(hdev, connect_mask);
        if (ret) {
                hid_err(hdev, "hw start failed\n");
-               goto err_free;
+               return ret;
        }
 
        if (sc->quirks & SIXAXIS_CONTROLLER_USB) {
@@ -668,8 +668,6 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
        return 0;
 err_stop:
        hid_hw_stop(hdev);
-err_free:
-       kfree(sc);
        return ret;
 }
 
@@ -681,7 +679,6 @@ static void sony_remove(struct hid_device *hdev)
                buzz_remove(hdev);
 
        hid_hw_stop(hdev);
-       kfree(sc);
 }
 
 static const struct hid_device_id sony_devices[] = {
diff --git a/drivers/hid/hid-xinmo.c b/drivers/hid/hid-xinmo.c
new file mode 100644 (file)
index 0000000..6153e50
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ *  HID driver for Xin-Mo devices, currently only the Dual Arcade controller.
+ *  Fixes the negative axis event values (the devices sends -2) to match the
+ *  logical axis minimum of the HID report descriptor (the report announces
+ *  -1). It is needed because hid-input discards out of bounds values.
+ *  (This module is based on "hid-saitek" and "hid-lg".)
+ *
+ *  Copyright (c) 2013 Olivier Scherler
+ */
+
+/*
+ * 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include "hid-ids.h"
+
+/*
+ * Fix negative events that are out of bounds.
+ */
+static int xinmo_event(struct hid_device *hdev, struct hid_field *field,
+               struct hid_usage *usage, __s32 value)
+{
+       switch (usage->code) {
+       case ABS_X:
+       case ABS_Y:
+       case ABS_Z:
+       case ABS_RX:
+               if (value < -1) {
+                       input_event(field->hidinput->input, usage->type,
+                               usage->code, -1);
+                       return 1;
+               }
+               break;
+       }
+
+       return 0;
+}
+
+static const struct hid_device_id xinmo_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_XIN_MO_DUAL_ARCADE) },
+       { }
+};
+
+MODULE_DEVICE_TABLE(hid, xinmo_devices);
+
+static struct hid_driver xinmo_driver = {
+       .name = "xinmo",
+       .id_table = xinmo_devices,
+       .event = xinmo_event
+};
+
+static int __init xinmo_init(void)
+{
+       return hid_register_driver(&xinmo_driver);
+}
+
+static void __exit xinmo_exit(void)
+{
+       hid_unregister_driver(&xinmo_driver);
+}
+
+module_init(xinmo_init);
+module_exit(xinmo_exit);
+MODULE_LICENSE("GPL");
index e4cddeccd6b51691bffc955a62569ead5e6d480e..1a660bd97ab2118f092403c71e237f620f6671ff 100644 (file)
@@ -169,7 +169,7 @@ static int zc_probe(struct hid_device *hdev, const struct hid_device_id *id)
        int ret;
        struct zc_device *zc;
 
-       zc = kzalloc(sizeof(*zc), GFP_KERNEL);
+       zc = devm_kzalloc(&hdev->dev, sizeof(*zc), GFP_KERNEL);
        if (zc == NULL) {
                hid_err(hdev, "can't alloc descriptor\n");
                return -ENOMEM;
@@ -180,28 +180,16 @@ static int zc_probe(struct hid_device *hdev, const struct hid_device_id *id)
        ret = hid_parse(hdev);
        if (ret) {
                hid_err(hdev, "parse failed\n");
-               goto err_free;
+               return ret;
        }
 
        ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
        if (ret) {
                hid_err(hdev, "hw start failed\n");
-               goto err_free;
+               return ret;
        }
 
        return 0;
-err_free:
-       kfree(zc);
-
-       return ret;
-}
-
-static void zc_remove(struct hid_device *hdev)
-{
-       struct zc_device *zc = hid_get_drvdata(hdev);
-
-       hid_hw_stop(hdev);
-       kfree(zc);
 }
 
 static const struct hid_device_id zc_devices[] = {
@@ -217,7 +205,6 @@ static struct hid_driver zc_driver = {
        .input_mapping = zc_input_mapping,
        .raw_event = zc_raw_event,
        .probe = zc_probe,
-       .remove = zc_remove,
 };
 module_hid_driver(zc_driver);
 
index 879b0ed701a3fb4109243a2642857c16518185b8..c21e692a83a4b9658d3e9d254d066ce15449987f 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/hid.h>
 #include <linux/mutex.h>
 #include <linux/acpi.h>
+#include <linux/of.h>
 
 #include <linux/i2c/i2c-hid.h>
 
@@ -756,29 +757,6 @@ static int i2c_hid_power(struct hid_device *hid, int lvl)
        return ret;
 }
 
-static int i2c_hid_hidinput_input_event(struct input_dev *dev,
-               unsigned int type, unsigned int code, int value)
-{
-       struct hid_device *hid = input_get_drvdata(dev);
-       struct hid_field *field;
-       int offset;
-
-       if (type == EV_FF)
-               return input_ff_event(dev, type, code, value);
-
-       if (type != EV_LED)
-               return -1;
-
-       offset = hidinput_find_field(hid, type, code, &field);
-
-       if (offset == -1) {
-               hid_warn(dev, "event field not found\n");
-               return -1;
-       }
-
-       return hid_set_field(field, offset, value);
-}
-
 static struct hid_ll_driver i2c_hid_ll_driver = {
        .parse = i2c_hid_parse,
        .start = i2c_hid_start,
@@ -787,7 +765,6 @@ static struct hid_ll_driver i2c_hid_ll_driver = {
        .close = i2c_hid_close,
        .power = i2c_hid_power,
        .request = i2c_hid_request,
-       .hidinput_input_event = i2c_hid_hidinput_input_event,
 };
 
 static int i2c_hid_init_irq(struct i2c_client *client)
@@ -933,6 +910,42 @@ static inline int i2c_hid_acpi_pdata(struct i2c_client *client,
 }
 #endif
 
+#ifdef CONFIG_OF
+static int i2c_hid_of_probe(struct i2c_client *client,
+               struct i2c_hid_platform_data *pdata)
+{
+       struct device *dev = &client->dev;
+       u32 val;
+       int ret;
+
+       ret = of_property_read_u32(dev->of_node, "hid-descr-addr", &val);
+       if (ret) {
+               dev_err(&client->dev, "HID register address not provided\n");
+               return -ENODEV;
+       }
+       if (val >> 16) {
+               dev_err(&client->dev, "Bad HID register address: 0x%08x\n",
+                       val);
+               return -EINVAL;
+       }
+       pdata->hid_descriptor_address = val;
+
+       return 0;
+}
+
+static const struct of_device_id i2c_hid_of_match[] = {
+       { .compatible = "hid-over-i2c" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, i2c_hid_of_match);
+#else
+static inline int i2c_hid_of_probe(struct i2c_client *client,
+               struct i2c_hid_platform_data *pdata)
+{
+       return -ENODEV;
+}
+#endif
+
 static int i2c_hid_probe(struct i2c_client *client,
                         const struct i2c_device_id *dev_id)
 {
@@ -954,7 +967,11 @@ static int i2c_hid_probe(struct i2c_client *client,
        if (!ihid)
                return -ENOMEM;
 
-       if (!platform_data) {
+       if (client->dev.of_node) {
+               ret = i2c_hid_of_probe(client, &ihid->pdata);
+               if (ret)
+                       goto err;
+       } else if (!platform_data) {
                ret = i2c_hid_acpi_pdata(client, &ihid->pdata);
                if (ret) {
                        dev_err(&client->dev,
@@ -1095,6 +1112,7 @@ static struct i2c_driver i2c_hid_driver = {
                .owner  = THIS_MODULE,
                .pm     = &i2c_hid_pm,
                .acpi_match_table = ACPI_PTR(i2c_hid_acpi_match),
+               .of_match_table = of_match_ptr(i2c_hid_of_match),
        },
 
        .probe          = i2c_hid_probe,
index fc307e0422afc92c31bfac65d410244d5859e804..f53f2d52e677b4f80b1bd454e673f2ec0a7ce816 100644 (file)
@@ -116,30 +116,6 @@ static void uhid_hid_close(struct hid_device *hid)
        uhid_queue_event(uhid, UHID_CLOSE);
 }
 
-static int uhid_hid_input(struct input_dev *input, unsigned int type,
-                         unsigned int code, int value)
-{
-       struct hid_device *hid = input_get_drvdata(input);
-       struct uhid_device *uhid = hid->driver_data;
-       unsigned long flags;
-       struct uhid_event *ev;
-
-       ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
-       if (!ev)
-               return -ENOMEM;
-
-       ev->type = UHID_OUTPUT_EV;
-       ev->u.output_ev.type = type;
-       ev->u.output_ev.code = code;
-       ev->u.output_ev.value = value;
-
-       spin_lock_irqsave(&uhid->qlock, flags);
-       uhid_queue(uhid, ev);
-       spin_unlock_irqrestore(&uhid->qlock, flags);
-
-       return 0;
-}
-
 static int uhid_hid_parse(struct hid_device *hid)
 {
        struct uhid_device *uhid = hid->driver_data;
@@ -273,7 +249,6 @@ static struct hid_ll_driver uhid_hid_driver = {
        .stop = uhid_hid_stop,
        .open = uhid_hid_open,
        .close = uhid_hid_close,
-       .hidinput_input_event = uhid_hid_input,
        .parse = uhid_hid_parse,
 };
 
index 99418285222cf118cbc09e4d9029c80ba3493fcf..bd38cdfbbba64fbb9fe76b6307f436f3f63f02f9 100644 (file)
@@ -535,7 +535,6 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re
 {
        int head;
        struct usbhid_device *usbhid = hid->driver_data;
-       int len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
 
        if ((hid->quirks & HID_QUIRK_NOGET) && dir == USB_DIR_IN)
                return;
@@ -546,7 +545,7 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re
                        return;
                }
 
-               usbhid->out[usbhid->outhead].raw_report = kmalloc(len, GFP_ATOMIC);
+               usbhid->out[usbhid->outhead].raw_report = hid_alloc_report_buf(report, GFP_ATOMIC);
                if (!usbhid->out[usbhid->outhead].raw_report) {
                        hid_warn(hid, "output queueing failed\n");
                        return;
@@ -595,7 +594,7 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re
        }
 
        if (dir == USB_DIR_OUT) {
-               usbhid->ctrl[usbhid->ctrlhead].raw_report = kmalloc(len, GFP_ATOMIC);
+               usbhid->ctrl[usbhid->ctrlhead].raw_report = hid_alloc_report_buf(report, GFP_ATOMIC);
                if (!usbhid->ctrl[usbhid->ctrlhead].raw_report) {
                        hid_warn(hid, "control queueing failed\n");
                        return;
@@ -649,62 +648,6 @@ static void usbhid_submit_report(struct hid_device *hid, struct hid_report *repo
        spin_unlock_irqrestore(&usbhid->lock, flags);
 }
 
-/* Workqueue routine to send requests to change LEDs */
-static void hid_led(struct work_struct *work)
-{
-       struct usbhid_device *usbhid =
-               container_of(work, struct usbhid_device, led_work);
-       struct hid_device *hid = usbhid->hid;
-       struct hid_field *field;
-       unsigned long flags;
-
-       field = hidinput_get_led_field(hid);
-       if (!field) {
-               hid_warn(hid, "LED event field not found\n");
-               return;
-       }
-
-       spin_lock_irqsave(&usbhid->lock, flags);
-       if (!test_bit(HID_DISCONNECTED, &usbhid->iofl)) {
-               usbhid->ledcount = hidinput_count_leds(hid);
-               hid_dbg(usbhid->hid, "New ledcount = %u\n", usbhid->ledcount);
-               __usbhid_submit_report(hid, field->report, USB_DIR_OUT);
-       }
-       spin_unlock_irqrestore(&usbhid->lock, flags);
-}
-
-static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
-{
-       struct hid_device *hid = input_get_drvdata(dev);
-       struct usbhid_device *usbhid = hid->driver_data;
-       struct hid_field *field;
-       unsigned long flags;
-       int offset;
-
-       if (type == EV_FF)
-               return input_ff_event(dev, type, code, value);
-
-       if (type != EV_LED)
-               return -1;
-
-       if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {
-               hid_warn(dev, "event field not found\n");
-               return -1;
-       }
-
-       spin_lock_irqsave(&usbhid->lock, flags);
-       hid_set_field(field, offset, value);
-       spin_unlock_irqrestore(&usbhid->lock, flags);
-
-       /*
-        * Defer performing requested LED action.
-        * This is more likely gather all LED changes into a single URB.
-        */
-       schedule_work(&usbhid->led_work);
-
-       return 0;
-}
-
 static int usbhid_wait_io(struct hid_device *hid)
 {
        struct usbhid_device *usbhid = hid->driver_data;
@@ -857,7 +800,7 @@ static int hid_find_field_early(struct hid_device *hid, unsigned int page,
        return -1;
 }
 
-void usbhid_set_leds(struct hid_device *hid)
+static void usbhid_set_leds(struct hid_device *hid)
 {
        struct hid_field *field;
        int offset;
@@ -867,7 +810,6 @@ void usbhid_set_leds(struct hid_device *hid)
                usbhid_submit_report(hid, field->report, USB_DIR_OUT);
        }
 }
-EXPORT_SYMBOL_GPL(usbhid_set_leds);
 
 /*
  * Traverse the supplied list of reports and find the longest
@@ -1274,7 +1216,6 @@ static struct hid_ll_driver usb_hid_driver = {
        .open = usbhid_open,
        .close = usbhid_close,
        .power = usbhid_power,
-       .hidinput_input_event = usb_hidinput_input_event,
        .request = usbhid_request,
        .wait = usbhid_wait_io,
        .idle = usbhid_idle,
@@ -1368,8 +1309,6 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *
        setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid);
        spin_lock_init(&usbhid->lock);
 
-       INIT_WORK(&usbhid->led_work, hid_led);
-
        ret = hid_add_device(hid);
        if (ret) {
                if (ret != -ENODEV)
@@ -1402,7 +1341,6 @@ static void hid_cancel_delayed_stuff(struct usbhid_device *usbhid)
 {
        del_timer_sync(&usbhid->io_retry);
        cancel_work_sync(&usbhid->reset_work);
-       cancel_work_sync(&usbhid->led_work);
 }
 
 static void hid_cease_io(struct usbhid_device *usbhid)
@@ -1522,15 +1460,17 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message)
        struct usbhid_device *usbhid = hid->driver_data;
        int status = 0;
        bool driver_suspended = false;
+       unsigned int ledcount;
 
        if (PMSG_IS_AUTO(message)) {
+               ledcount = hidinput_count_leds(hid);
                spin_lock_irq(&usbhid->lock);   /* Sync with error handler */
                if (!test_bit(HID_RESET_PENDING, &usbhid->iofl)
                    && !test_bit(HID_CLEAR_HALT, &usbhid->iofl)
                    && !test_bit(HID_OUT_RUNNING, &usbhid->iofl)
                    && !test_bit(HID_CTRL_RUNNING, &usbhid->iofl)
                    && !test_bit(HID_KEYS_PRESSED, &usbhid->iofl)
-                   && (!usbhid->ledcount || ignoreled))
+                   && (!ledcount || ignoreled))
                {
                        set_bit(HID_SUSPENDED, &usbhid->iofl);
                        spin_unlock_irq(&usbhid->lock);
index dbb6af6991350d4e09b2c7ca484411065afdc75c..f633c24ce28b8d8f81d831c37059992914e7c32b 100644 (file)
@@ -92,9 +92,6 @@ struct usbhid_device {
        unsigned int retry_delay;                                       /* Delay length in ms */
        struct work_struct reset_work;                                  /* Task context for resets */
        wait_queue_head_t wait;                                         /* For sleeping */
-       int ledcount;                                                   /* counting the number of active leds */
-
-       struct work_struct led_work;                                    /* Task context for setting LEDs */
 };
 
 #define        hid_to_usb_dev(hid_dev) \
index ba962ac4b81f2e63519ee12138e1b2e298befe90..7092c78f814f03c82c0976d682b0ec1c2b4155dc 100644 (file)
@@ -145,7 +145,7 @@ static int ads7828_remove(struct i2c_client *client)
 static int ads7828_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
-       struct ads7828_platform_data *pdata = client->dev.platform_data;
+       struct ads7828_platform_data *pdata = dev_get_platdata(&client->dev);
        struct ads7828_data *data;
        int err;
 
index 2e5e2dc47eafdca62ae3513bee1e471cbdb1276d..78be66176840d1c6abdf29dd632d7a107f6ad2d3 100644 (file)
@@ -316,6 +316,18 @@ static int adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
        return tjmax;
 }
 
+static bool cpu_has_tjmax(struct cpuinfo_x86 *c)
+{
+       u8 model = c->x86_model;
+
+       return model > 0xe &&
+              model != 0x1c &&
+              model != 0x26 &&
+              model != 0x27 &&
+              model != 0x35 &&
+              model != 0x36;
+}
+
 static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
 {
        int err;
@@ -328,7 +340,7 @@ static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
         */
        err = rdmsr_safe_on_cpu(id, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
        if (err) {
-               if (c->x86_model > 0xe && c->x86_model != 0x1c)
+               if (cpu_has_tjmax(c))
                        dev_warn(dev, "Unable to read TjMax from CPU %u\n", id);
        } else {
                val = (eax >> 16) & 0xff;
index f1d6b422cf0682b43ed6b4354481d97de240fcef..0918b91365880f93be1d4a807cc0ab5fd58a6588 100644 (file)
@@ -77,7 +77,7 @@ struct ds620_data {
 
 static void ds620_init_client(struct i2c_client *client)
 {
-       struct ds620_platform_data *ds620_info = client->dev.platform_data;
+       struct ds620_platform_data *ds620_info = dev_get_platdata(&client->dev);
        u16 conf, new_conf;
 
        new_conf = conf =
index 0c9f3da242bf91be9a6688f71de6d96385ce8453..15b7f5281def34947ee72afb7c3e170573d5693e 100644 (file)
@@ -1375,7 +1375,7 @@ static void f71805f_init_device(struct f71805f_data *data)
 
 static int f71805f_probe(struct platform_device *pdev)
 {
-       struct f71805f_sio_data *sio_data = pdev->dev.platform_data;
+       struct f71805f_sio_data *sio_data = dev_get_platdata(&pdev->dev);
        struct f71805f_data *data;
        struct resource *res;
        int i, err;
index cfb02dd91aadda144e5986e19e3f57e0fd65743e..31b221eeee6ca7c4c789cc4aeaf88164136664fd 100644 (file)
@@ -2267,7 +2267,7 @@ static int f71882fg_create_fan_sysfs_files(
 static int f71882fg_probe(struct platform_device *pdev)
 {
        struct f71882fg_data *data;
-       struct f71882fg_sio_data *sio_data = pdev->dev.platform_data;
+       struct f71882fg_sio_data *sio_data = dev_get_platdata(&pdev->dev);
        int nr_fans = f71882fg_nr_fans[sio_data->type];
        int nr_temps = f71882fg_nr_temps[sio_data->type];
        int err, i;
index 9e300e567f15c6b0cc22d6245e9a1cccbc1d8e0e..a837b94977f4e8e59d9f3478a96747fe56de803e 100644 (file)
@@ -832,7 +832,8 @@ static int f75375_probe(struct i2c_client *client,
                const struct i2c_device_id *id)
 {
        struct f75375_data *data;
-       struct f75375s_platform_data *f75375s_pdata = client->dev.platform_data;
+       struct f75375s_platform_data *f75375s_pdata =
+                       dev_get_platdata(&client->dev);
        int err;
 
        if (!i2c_check_functionality(client->adapter,
index 73adf01b0ef2addbdb7052632a17c623be848a38..b4b8b5bef718a596a027d3e57703491eedba980c 100644 (file)
@@ -717,7 +717,7 @@ static void g762_of_clock_disable(struct i2c_client *client) { }
 
 static int g762_pdata_prop_import(struct i2c_client *client)
 {
-       struct g762_platform_data *pdata = client->dev.platform_data;
+       struct g762_platform_data *pdata = dev_get_platdata(&client->dev);
        int ret;
 
        if (!pdata)
index 3104149795c582e8ceac8780aca390059eafc721..b7d6a5704eb2ff15887f77341e8d8b2e57cdb291 100644 (file)
@@ -495,7 +495,7 @@ static int gpio_fan_probe(struct platform_device *pdev)
 {
        int err;
        struct gpio_fan_data *fan_data;
-       struct gpio_fan_platform_data *pdata = pdev->dev.platform_data;
+       struct gpio_fan_platform_data *pdata = dev_get_platdata(&pdev->dev);
 
 #ifdef CONFIG_OF_GPIO
        if (!pdata) {
index d917a2d8c30ffde4183382d8370bef781dd0e824..18c062360ca7950e77ef4573ddf3dbc9fc16be82 100644 (file)
@@ -232,9 +232,9 @@ static int ina2xx_probe(struct i2c_client *client,
        if (!data)
                return -ENOMEM;
 
-       if (client->dev.platform_data) {
+       if (dev_get_platdata(&client->dev)) {
                pdata =
-                 (struct ina2xx_platform_data *)client->dev.platform_data;
+                 (struct ina2xx_platform_data *)dev_get_platdata(&client->dev);
                shunt = pdata->shunt_uohms;
        } else if (!of_property_read_u32(client->dev.of_node,
                                "shunt-resistor", &val)) {
index 72b21d5b1c621ece4f8059ba48ae6afe26642c21..29ffa27c60b89b60bf84db948cf56a890772599e 100644 (file)
@@ -1962,7 +1962,7 @@ exit:
 static void it87_remove_files(struct device *dev)
 {
        struct it87_data *data = platform_get_drvdata(pdev);
-       struct it87_sio_data *sio_data = dev->platform_data;
+       struct it87_sio_data *sio_data = dev_get_platdata(dev);
        int i;
 
        sysfs_remove_group(&dev->kobj, &it87_group);
@@ -2014,7 +2014,7 @@ static int it87_probe(struct platform_device *pdev)
        struct it87_data *data;
        struct resource *res;
        struct device *dev = &pdev->dev;
-       struct it87_sio_data *sio_data = dev->platform_data;
+       struct it87_sio_data *sio_data = dev_get_platdata(dev);
        int err = 0, i;
        int enable_pwm_interface;
        int fan_beep_need_rw;
@@ -2316,7 +2316,7 @@ static int it87_check_pwm(struct device *dev)
 /* Called when we have found a new IT87. */
 static void it87_init_device(struct platform_device *pdev)
 {
-       struct it87_sio_data *sio_data = pdev->dev.platform_data;
+       struct it87_sio_data *sio_data = dev_get_platdata(&pdev->dev);
        struct it87_data *data = platform_get_drvdata(pdev);
        int tmp, i;
        u8 mask;
index 16e45d7021522d0eb60da181144810b3700711a9..333092ce2465e234c15d415d4a99bb381100f2a3 100644 (file)
@@ -855,8 +855,8 @@ static void lm87_init_client(struct i2c_client *client)
 {
        struct lm87_data *data = i2c_get_clientdata(client);
 
-       if (client->dev.platform_data) {
-               data->channel = *(u8 *)client->dev.platform_data;
+       if (dev_get_platdata(&client->dev)) {
+               data->channel = *(u8 *)dev_get_platdata(&client->dev);
                lm87_write_value(client,
                                 LM87_REG_CHANNEL_MODE, data->channel);
        } else {
index b5ebb9198c757e17eaf114d5cf15f7c91a28e14f..96dccaf919d1da4c02b26de8f937f5c401f84ff4 100644 (file)
@@ -261,7 +261,7 @@ static int max197_probe(struct platform_device *pdev)
 {
        int ch, ret;
        struct max197_data *data;
-       struct max197_platform_data *pdata = pdev->dev.platform_data;
+       struct max197_platform_data *pdata = dev_get_platdata(&pdev->dev);
        enum max197_chips chip = platform_get_device_id(pdev)->driver_data;
 
        if (pdata == NULL) {
index 3e7b4269f5b9df67658e5e3f855aaec6d95b3c29..066e587a18a5a280f29db1f19dd14e3d30ea4f48 100644 (file)
@@ -428,7 +428,7 @@ static int max6639_init_client(struct i2c_client *client)
 {
        struct max6639_data *data = i2c_get_clientdata(client);
        struct max6639_platform_data *max6639_info =
-               client->dev.platform_data;
+               dev_get_platdata(&client->dev);
        int i;
        int rpm_range = 1; /* default: 4000 RPM */
        int err;
index 328fb0353c171a1b879af1040185afa1be109ea4..a41b5f3fc5069596d7c9a0c0c164dcefefc7e621 100644 (file)
@@ -605,12 +605,12 @@ static int max6697_init_chip(struct i2c_client *client)
                if (ret < 0)
                        return ret;
                ret = i2c_smbus_write_byte_data(client, MAX6581_REG_IDEALITY,
-                                               pdata->ideality_mask >> 1);
+                                               pdata->ideality_value);
                if (ret < 0)
                        return ret;
                ret = i2c_smbus_write_byte_data(client,
                                                MAX6581_REG_IDEALITY_SELECT,
-                                               pdata->ideality_value);
+                                               pdata->ideality_mask >> 1);
                if (ret < 0)
                        return ret;
        }
index eedb32292d6d3c20035f56a90820861d38e02102..d219c06a857bb5795a176bb88d9e186fd6a4b286 100644 (file)
@@ -143,12 +143,13 @@ static int mcp3021_probe(struct i2c_client *client,
                break;
        }
 
-       if (client->dev.platform_data) {
-               data->vdd = *(u32 *)client->dev.platform_data;
+       if (dev_get_platdata(&client->dev)) {
+               data->vdd = *(u32 *)dev_get_platdata(&client->dev);
                if (data->vdd > MCP3021_VDD_MAX || data->vdd < MCP3021_VDD_MIN)
                        return -EINVAL;
-       } else
+       } else {
                data->vdd = MCP3021_VDD_REF;
+       }
 
        err = sysfs_create_file(&client->dev.kobj, &dev_attr_in0_input.attr);
        if (err)
index 99cec18254203c5ebfa59ba0b1cbfdecabf77aac..db519e5998317a2ee54a6be6ca1f4acdf3d277f1 100644 (file)
  * Supports the following chips:
  *
  * Chip        #vin    #fan    #pwm    #temp  chip IDs       man ID
+ * nct6106d     9      3       3       6+3    0xc450 0xc1    0x5ca3
  * nct6775f     9      4       3       6+3    0xb470 0xc1    0x5ca3
  * nct6776f     9      5       3       6+3    0xc330 0xc1    0x5ca3
  * nct6779d    15      5       5       2+6    0xc560 0xc1    0x5ca3
+ * nct6791d    15      6       6       2+6    0xc800 0xc1    0x5ca3
  *
  * #temp lists the number of monitored temperature sources (first value) plus
  * the number of directly connectable temperature sensors (second value).
 
 #define USE_ALTERNATE
 
-enum kinds { nct6775, nct6776, nct6779 };
+enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791 };
 
 /* used to set data->name = nct6775_device_names[data->sio_kind] */
 static const char * const nct6775_device_names[] = {
+       "nct6106",
        "nct6775",
        "nct6776",
        "nct6779",
+       "nct6791",
 };
 
 static unsigned short force_id;
@@ -91,9 +95,11 @@ MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
 #define SIO_REG_ENABLE         0x30    /* Logical device enable */
 #define SIO_REG_ADDR           0x60    /* Logical device address (2 bytes) */
 
+#define SIO_NCT6106_ID         0xc450
 #define SIO_NCT6775_ID         0xb470
 #define SIO_NCT6776_ID         0xc330
 #define SIO_NCT6779_ID         0xc560
+#define SIO_NCT6791_ID         0xc800
 #define SIO_ID_MASK            0xFFF0
 
 enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 };
@@ -167,7 +173,10 @@ superio_exit(int ioreg)
 #define NUM_TEMP       10      /* Max number of temp attribute sets w/ limits*/
 #define NUM_TEMP_FIXED 6       /* Max number of fixed temp attribute sets */
 
-#define NUM_REG_ALARM  4       /* Max number of alarm registers */
+#define NUM_REG_ALARM  7       /* Max number of alarm registers */
+#define NUM_REG_BEEP   5       /* Max number of beep registers */
+
+#define NUM_FAN                6
 
 /* Common and NCT6775 specific data */
 
@@ -185,6 +194,7 @@ static const u16 NCT6775_REG_IN[] = {
 
 #define NCT6775_REG_VBAT               0x5D
 #define NCT6775_REG_DIODE              0x5E
+#define NCT6775_DIODE_MASK             0x02
 
 #define NCT6775_REG_FANDIV1            0x506
 #define NCT6775_REG_FANDIV2            0x507
@@ -193,7 +203,7 @@ static const u16 NCT6775_REG_IN[] = {
 
 static const u16 NCT6775_REG_ALARM[NUM_REG_ALARM] = { 0x459, 0x45A, 0x45B };
 
-/* 0..15 voltages, 16..23 fans, 24..31 temperatures */
+/* 0..15 voltages, 16..23 fans, 24..29 temperatures, 30..31 intrusion */
 
 static const s8 NCT6775_ALARM_BITS[] = {
        0, 1, 2, 3, 8, 21, 20, 16,      /* in0.. in7 */
@@ -208,6 +218,23 @@ static const s8 NCT6775_ALARM_BITS[] = {
 #define TEMP_ALARM_BASE                24
 #define INTRUSION_ALARM_BASE   30
 
+static const u16 NCT6775_REG_BEEP[NUM_REG_BEEP] = { 0x56, 0x57, 0x453, 0x4e };
+
+/*
+ * 0..14 voltages, 15 global beep enable, 16..23 fans, 24..29 temperatures,
+ * 30..31 intrusion
+ */
+static const s8 NCT6775_BEEP_BITS[] = {
+       0, 1, 2, 3, 8, 9, 10, 16,       /* in0.. in7 */
+       17, -1, -1, -1, -1, -1, -1,     /* in8..in14 */
+       21,                             /* global beep enable */
+       6, 7, 11, 28, -1,               /* fan1..fan5 */
+       -1, -1, -1,                     /* unused */
+       4, 5, 13, -1, -1, -1,           /* temp1..temp6 */
+       12, -1 };                       /* intrusion0, intrusion1 */
+
+#define BEEP_ENABLE_BASE               15
+
 static const u8 NCT6775_REG_CR_CASEOPEN_CLR[] = { 0xe6, 0xee };
 static const u8 NCT6775_CR_CASEOPEN_CLR_MASK[] = { 0x20, 0x01 };
 
@@ -217,27 +244,32 @@ static const u8 NCT6775_PWM_MODE_MASK[] = { 0x01, 0x02, 0x01 };
 
 /* Advanced Fan control, some values are common for all fans */
 
-static const u16 NCT6775_REG_TARGET[] = { 0x101, 0x201, 0x301, 0x801, 0x901 };
-static const u16 NCT6775_REG_FAN_MODE[] = { 0x102, 0x202, 0x302, 0x802, 0x902 };
+static const u16 NCT6775_REG_TARGET[] = {
+       0x101, 0x201, 0x301, 0x801, 0x901, 0xa01 };
+static const u16 NCT6775_REG_FAN_MODE[] = {
+       0x102, 0x202, 0x302, 0x802, 0x902, 0xa02 };
 static const u16 NCT6775_REG_FAN_STEP_DOWN_TIME[] = {
-       0x103, 0x203, 0x303, 0x803, 0x903 };
+       0x103, 0x203, 0x303, 0x803, 0x903, 0xa03 };
 static const u16 NCT6775_REG_FAN_STEP_UP_TIME[] = {
-       0x104, 0x204, 0x304, 0x804, 0x904 };
+       0x104, 0x204, 0x304, 0x804, 0x904, 0xa04 };
 static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = {
-       0x105, 0x205, 0x305, 0x805, 0x905 };
-static const u16 NCT6775_REG_FAN_START_OUTPUT[]
-       = { 0x106, 0x206, 0x306, 0x806, 0x906 };
+       0x105, 0x205, 0x305, 0x805, 0x905, 0xa05 };
+static const u16 NCT6775_REG_FAN_START_OUTPUT[] = {
+       0x106, 0x206, 0x306, 0x806, 0x906, 0xa06 };
 static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a };
 static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b };
 
 static const u16 NCT6775_REG_FAN_STOP_TIME[] = {
-       0x107, 0x207, 0x307, 0x807, 0x907 };
-static const u16 NCT6775_REG_PWM[] = { 0x109, 0x209, 0x309, 0x809, 0x909 };
-static const u16 NCT6775_REG_PWM_READ[] = { 0x01, 0x03, 0x11, 0x13, 0x15 };
+       0x107, 0x207, 0x307, 0x807, 0x907, 0xa07 };
+static const u16 NCT6775_REG_PWM[] = {
+       0x109, 0x209, 0x309, 0x809, 0x909, 0xa09 };
+static const u16 NCT6775_REG_PWM_READ[] = {
+       0x01, 0x03, 0x11, 0x13, 0x15, 0xa09 };
 
 static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
 static const u16 NCT6775_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d };
 static const u16 NCT6775_REG_FAN_PULSES[] = { 0x641, 0x642, 0x643, 0x644, 0 };
+static const u16 NCT6775_FAN_PULSE_SHIFT[] = { 0, 0, 0, 0, 0, 0 };
 
 static const u16 NCT6775_REG_TEMP[] = {
        0x27, 0x150, 0x250, 0x62b, 0x62c, 0x62d };
@@ -253,25 +285,25 @@ static const u16 NCT6775_REG_TEMP_SOURCE[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
        0x621, 0x622, 0x623, 0x624, 0x625, 0x626 };
 
 static const u16 NCT6775_REG_TEMP_SEL[] = {
-       0x100, 0x200, 0x300, 0x800, 0x900 };
+       0x100, 0x200, 0x300, 0x800, 0x900, 0xa00 };
 
 static const u16 NCT6775_REG_WEIGHT_TEMP_SEL[] = {
-       0x139, 0x239, 0x339, 0x839, 0x939 };
+       0x139, 0x239, 0x339, 0x839, 0x939, 0xa39 };
 static const u16 NCT6775_REG_WEIGHT_TEMP_STEP[] = {
-       0x13a, 0x23a, 0x33a, 0x83a, 0x93a };
+       0x13a, 0x23a, 0x33a, 0x83a, 0x93a, 0xa3a };
 static const u16 NCT6775_REG_WEIGHT_TEMP_STEP_TOL[] = {
-       0x13b, 0x23b, 0x33b, 0x83b, 0x93b };
+       0x13b, 0x23b, 0x33b, 0x83b, 0x93b, 0xa3b };
 static const u16 NCT6775_REG_WEIGHT_DUTY_STEP[] = {
-       0x13c, 0x23c, 0x33c, 0x83c, 0x93c };
+       0x13c, 0x23c, 0x33c, 0x83c, 0x93c, 0xa3c };
 static const u16 NCT6775_REG_WEIGHT_TEMP_BASE[] = {
-       0x13d, 0x23d, 0x33d, 0x83d, 0x93d };
+       0x13d, 0x23d, 0x33d, 0x83d, 0x93d, 0xa3d };
 
 static const u16 NCT6775_REG_TEMP_OFFSET[] = { 0x454, 0x455, 0x456 };
 
 static const u16 NCT6775_REG_AUTO_TEMP[] = {
-       0x121, 0x221, 0x321, 0x821, 0x921 };
+       0x121, 0x221, 0x321, 0x821, 0x921, 0xa21 };
 static const u16 NCT6775_REG_AUTO_PWM[] = {
-       0x127, 0x227, 0x327, 0x827, 0x927 };
+       0x127, 0x227, 0x327, 0x827, 0x927, 0xa27 };
 
 #define NCT6775_AUTO_TEMP(data, nr, p) ((data)->REG_AUTO_TEMP[nr] + (p))
 #define NCT6775_AUTO_PWM(data, nr, p)  ((data)->REG_AUTO_PWM[nr] + (p))
@@ -279,9 +311,9 @@ static const u16 NCT6775_REG_AUTO_PWM[] = {
 static const u16 NCT6775_REG_CRITICAL_ENAB[] = { 0x134, 0x234, 0x334 };
 
 static const u16 NCT6775_REG_CRITICAL_TEMP[] = {
-       0x135, 0x235, 0x335, 0x835, 0x935 };
+       0x135, 0x235, 0x335, 0x835, 0x935, 0xa35 };
 static const u16 NCT6775_REG_CRITICAL_TEMP_TOLERANCE[] = {
-       0x138, 0x238, 0x338, 0x838, 0x938 };
+       0x138, 0x238, 0x338, 0x838, 0x938, 0xa38 };
 
 static const char *const nct6775_temp_label[] = {
        "",
@@ -325,17 +357,28 @@ static const s8 NCT6776_ALARM_BITS[] = {
        4, 5, 13, -1, -1, -1,           /* temp1..temp6 */
        12, 9 };                        /* intrusion0, intrusion1 */
 
+static const u16 NCT6776_REG_BEEP[NUM_REG_BEEP] = { 0xb2, 0xb3, 0xb4, 0xb5 };
+
+static const s8 NCT6776_BEEP_BITS[] = {
+       0, 1, 2, 3, 4, 5, 6, 7,         /* in0.. in7 */
+       8, -1, -1, -1, -1, -1, -1,      /* in8..in14 */
+       24,                             /* global beep enable */
+       25, 26, 27, 28, 29,             /* fan1..fan5 */
+       -1, -1, -1,                     /* unused */
+       16, 17, 18, 19, 20, 21,         /* temp1..temp6 */
+       30, 31 };                       /* intrusion0, intrusion1 */
+
 static const u16 NCT6776_REG_TOLERANCE_H[] = {
-       0x10c, 0x20c, 0x30c, 0x80c, 0x90c };
+       0x10c, 0x20c, 0x30c, 0x80c, 0x90c, 0xa0c };
 
-static const u8 NCT6776_REG_PWM_MODE[] = { 0x04, 0, 0 };
-static const u8 NCT6776_PWM_MODE_MASK[] = { 0x01, 0, 0 };
+static const u8 NCT6776_REG_PWM_MODE[] = { 0x04, 0, 0, 0, 0, 0 };
+static const u8 NCT6776_PWM_MODE_MASK[] = { 0x01, 0, 0, 0, 0, 0 };
 
 static const u16 NCT6776_REG_FAN_MIN[] = { 0x63a, 0x63c, 0x63e, 0x640, 0x642 };
 static const u16 NCT6776_REG_FAN_PULSES[] = { 0x644, 0x645, 0x646, 0, 0 };
 
 static const u16 NCT6776_REG_WEIGHT_DUTY_BASE[] = {
-       0x13e, 0x23e, 0x33e, 0x83e, 0x93e };
+       0x13e, 0x23e, 0x33e, 0x83e, 0x93e, 0xa3e };
 
 static const u16 NCT6776_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
        0x18, 0x152, 0x252, 0x628, 0x629, 0x62A };
@@ -390,14 +433,25 @@ static const s8 NCT6779_ALARM_BITS[] = {
        4, 5, 13, -1, -1, -1,           /* temp1..temp6 */
        12, 9 };                        /* intrusion0, intrusion1 */
 
-static const u16 NCT6779_REG_FAN[] = { 0x4b0, 0x4b2, 0x4b4, 0x4b6, 0x4b8 };
+static const s8 NCT6779_BEEP_BITS[] = {
+       0, 1, 2, 3, 4, 5, 6, 7,         /* in0.. in7 */
+       8, 9, 10, 11, 12, 13, 14,       /* in8..in14 */
+       24,                             /* global beep enable */
+       25, 26, 27, 28, 29,             /* fan1..fan5 */
+       -1, -1, -1,                     /* unused */
+       16, 17, -1, -1, -1, -1,         /* temp1..temp6 */
+       30, 31 };                       /* intrusion0, intrusion1 */
+
+static const u16 NCT6779_REG_FAN[] = {
+       0x4b0, 0x4b2, 0x4b4, 0x4b6, 0x4b8, 0x4ba };
 static const u16 NCT6779_REG_FAN_PULSES[] = {
-       0x644, 0x645, 0x646, 0x647, 0x648 };
+       0x644, 0x645, 0x646, 0x647, 0x648, 0x649 };
 
 static const u16 NCT6779_REG_CRITICAL_PWM_ENABLE[] = {
-       0x136, 0x236, 0x336, 0x836, 0x936 };
+       0x136, 0x236, 0x336, 0x836, 0x936, 0xa36 };
+#define NCT6779_CRITICAL_PWM_ENABLE_MASK       0x01
 static const u16 NCT6779_REG_CRITICAL_PWM[] = {
-       0x137, 0x237, 0x337, 0x837, 0x937 };
+       0x137, 0x237, 0x337, 0x837, 0x937, 0xa37 };
 
 static const u16 NCT6779_REG_TEMP[] = { 0x27, 0x150 };
 static const u16 NCT6779_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
@@ -449,6 +503,122 @@ static const u16 NCT6779_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6779_temp_label) - 1]
 static const u16 NCT6779_REG_TEMP_CRIT[ARRAY_SIZE(nct6779_temp_label) - 1]
        = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a };
 
+/* NCT6791 specific data */
+
+#define NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE    0x28
+
+static const u16 NCT6791_REG_ALARM[NUM_REG_ALARM] = {
+       0x459, 0x45A, 0x45B, 0x568, 0x45D };
+
+static const s8 NCT6791_ALARM_BITS[] = {
+       0, 1, 2, 3, 8, 21, 20, 16,      /* in0.. in7 */
+       17, 24, 25, 26, 27, 28, 29,     /* in8..in14 */
+       -1,                             /* unused */
+       6, 7, 11, 10, 23, 33,           /* fan1..fan6 */
+       -1, -1,                         /* unused */
+       4, 5, 13, -1, -1, -1,           /* temp1..temp6 */
+       12, 9 };                        /* intrusion0, intrusion1 */
+
+
+/* NCT6102D/NCT6106D specific data */
+
+#define NCT6106_REG_VBAT       0x318
+#define NCT6106_REG_DIODE      0x319
+#define NCT6106_DIODE_MASK     0x01
+
+static const u16 NCT6106_REG_IN_MAX[] = {
+       0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9e, 0xa0, 0xa2 };
+static const u16 NCT6106_REG_IN_MIN[] = {
+       0x91, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9f, 0xa1, 0xa3 };
+static const u16 NCT6106_REG_IN[] = {
+       0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x09 };
+
+static const u16 NCT6106_REG_TEMP[] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 };
+static const u16 NCT6106_REG_TEMP_HYST[] = {
+       0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd7 };
+static const u16 NCT6106_REG_TEMP_OVER[] = {
+       0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd6 };
+static const u16 NCT6106_REG_TEMP_CRIT_L[] = {
+       0xc0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4 };
+static const u16 NCT6106_REG_TEMP_CRIT_H[] = {
+       0xc1, 0xc5, 0xc9, 0xcf, 0xd1, 0xd5 };
+static const u16 NCT6106_REG_TEMP_OFFSET[] = { 0x311, 0x312, 0x313 };
+static const u16 NCT6106_REG_TEMP_CONFIG[] = {
+       0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc };
+
+static const u16 NCT6106_REG_FAN[] = { 0x20, 0x22, 0x24 };
+static const u16 NCT6106_REG_FAN_MIN[] = { 0xe0, 0xe2, 0xe4 };
+static const u16 NCT6106_REG_FAN_PULSES[] = { 0xf6, 0xf6, 0xf6, 0, 0 };
+static const u16 NCT6106_FAN_PULSE_SHIFT[] = { 0, 2, 4, 0, 0 };
+
+static const u8 NCT6106_REG_PWM_MODE[] = { 0xf3, 0xf3, 0xf3 };
+static const u8 NCT6106_PWM_MODE_MASK[] = { 0x01, 0x02, 0x04 };
+static const u16 NCT6106_REG_PWM[] = { 0x119, 0x129, 0x139 };
+static const u16 NCT6106_REG_PWM_READ[] = { 0x4a, 0x4b, 0x4c };
+static const u16 NCT6106_REG_FAN_MODE[] = { 0x113, 0x123, 0x133 };
+static const u16 NCT6106_REG_TEMP_SEL[] = { 0x110, 0x120, 0x130 };
+static const u16 NCT6106_REG_TEMP_SOURCE[] = {
+       0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5 };
+
+static const u16 NCT6106_REG_CRITICAL_TEMP[] = { 0x11a, 0x12a, 0x13a };
+static const u16 NCT6106_REG_CRITICAL_TEMP_TOLERANCE[] = {
+       0x11b, 0x12b, 0x13b };
+
+static const u16 NCT6106_REG_CRITICAL_PWM_ENABLE[] = { 0x11c, 0x12c, 0x13c };
+#define NCT6106_CRITICAL_PWM_ENABLE_MASK       0x10
+static const u16 NCT6106_REG_CRITICAL_PWM[] = { 0x11d, 0x12d, 0x13d };
+
+static const u16 NCT6106_REG_FAN_STEP_UP_TIME[] = { 0x114, 0x124, 0x134 };
+static const u16 NCT6106_REG_FAN_STEP_DOWN_TIME[] = { 0x115, 0x125, 0x135 };
+static const u16 NCT6106_REG_FAN_STOP_OUTPUT[] = { 0x116, 0x126, 0x136 };
+static const u16 NCT6106_REG_FAN_START_OUTPUT[] = { 0x117, 0x127, 0x137 };
+static const u16 NCT6106_REG_FAN_STOP_TIME[] = { 0x118, 0x128, 0x138 };
+static const u16 NCT6106_REG_TOLERANCE_H[] = { 0x112, 0x122, 0x132 };
+
+static const u16 NCT6106_REG_TARGET[] = { 0x111, 0x121, 0x131 };
+
+static const u16 NCT6106_REG_WEIGHT_TEMP_SEL[] = { 0x168, 0x178, 0x188 };
+static const u16 NCT6106_REG_WEIGHT_TEMP_STEP[] = { 0x169, 0x179, 0x189 };
+static const u16 NCT6106_REG_WEIGHT_TEMP_STEP_TOL[] = { 0x16a, 0x17a, 0x18a };
+static const u16 NCT6106_REG_WEIGHT_DUTY_STEP[] = { 0x16b, 0x17b, 0x17c };
+static const u16 NCT6106_REG_WEIGHT_TEMP_BASE[] = { 0x16c, 0x17c, 0x18c };
+static const u16 NCT6106_REG_WEIGHT_DUTY_BASE[] = { 0x16d, 0x17d, 0x18d };
+
+static const u16 NCT6106_REG_AUTO_TEMP[] = { 0x160, 0x170, 0x180 };
+static const u16 NCT6106_REG_AUTO_PWM[] = { 0x164, 0x174, 0x184 };
+
+static const u16 NCT6106_REG_ALARM[NUM_REG_ALARM] = {
+       0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d };
+
+static const s8 NCT6106_ALARM_BITS[] = {
+       0, 1, 2, 3, 4, 5, 7, 8,         /* in0.. in7 */
+       9, -1, -1, -1, -1, -1, -1,      /* in8..in14 */
+       -1,                             /* unused */
+       32, 33, 34, -1, -1,             /* fan1..fan5 */
+       -1, -1, -1,                     /* unused */
+       16, 17, 18, 19, 20, 21,         /* temp1..temp6 */
+       48, -1                          /* intrusion0, intrusion1 */
+};
+
+static const u16 NCT6106_REG_BEEP[NUM_REG_BEEP] = {
+       0x3c0, 0x3c1, 0x3c2, 0x3c3, 0x3c4 };
+
+static const s8 NCT6106_BEEP_BITS[] = {
+       0, 1, 2, 3, 4, 5, 7, 8,         /* in0.. in7 */
+       9, 10, 11, 12, -1, -1, -1,      /* in8..in14 */
+       32,                             /* global beep enable */
+       24, 25, 26, 27, 28,             /* fan1..fan5 */
+       -1, -1, -1,                     /* unused */
+       16, 17, 18, 19, 20, 21,         /* temp1..temp6 */
+       34, -1                          /* intrusion0, intrusion1 */
+};
+
+static const u16 NCT6106_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6776_temp_label) - 1]
+       = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x51, 0x52, 0x54 };
+
+static const u16 NCT6106_REG_TEMP_CRIT[ARRAY_SIZE(nct6776_temp_label) - 1]
+       = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x204, 0x205 };
+
 static enum pwm_enable reg_to_pwm_enable(int pwm, int mode)
 {
        if (mode == 0 && pwm == 255)
@@ -550,13 +720,18 @@ static inline u8 in_to_reg(u32 val, u8 nr)
 
 struct nct6775_data {
        int addr;       /* IO base of hw monitor block */
+       int sioreg;     /* SIO register address */
        enum kinds kind;
        const char *name;
 
        struct device *hwmon_dev;
+       struct attribute_group *group_in;
+       struct attribute_group *group_fan;
+       struct attribute_group *group_temp;
+       struct attribute_group *group_pwm;
 
-       u16 reg_temp[4][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
-                                   * 3=temp_crit
+       u16 reg_temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
+                                   * 3=temp_crit, 4=temp_lcrit
                                    */
        u8 temp_src[NUM_TEMP];
        u16 reg_temp_config[NUM_TEMP];
@@ -566,8 +741,10 @@ struct nct6775_data {
        u16 REG_CONFIG;
        u16 REG_VBAT;
        u16 REG_DIODE;
+       u8 DIODE_MASK;
 
        const s8 *ALARM_BITS;
+       const s8 *BEEP_BITS;
 
        const u16 *REG_VIN;
        const u16 *REG_IN_MINMAX[2];
@@ -577,6 +754,7 @@ struct nct6775_data {
        const u16 *REG_FAN_MODE;
        const u16 *REG_FAN_MIN;
        const u16 *REG_FAN_PULSES;
+       const u16 *FAN_PULSE_SHIFT;
        const u16 *REG_FAN_TIME[3];
 
        const u16 *REG_TOLERANCE_H;
@@ -590,6 +768,10 @@ struct nct6775_data {
                                 */
        const u16 *REG_PWM_READ;
 
+       const u16 *REG_CRITICAL_PWM_ENABLE;
+       u8 CRITICAL_PWM_ENABLE_MASK;
+       const u16 *REG_CRITICAL_PWM;
+
        const u16 *REG_AUTO_TEMP;
        const u16 *REG_AUTO_PWM;
 
@@ -604,6 +786,7 @@ struct nct6775_data {
        const u16 *REG_TEMP_OFFSET;
 
        const u16 *REG_ALARM;
+       const u16 *REG_BEEP;
 
        unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg);
        unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg);
@@ -616,26 +799,30 @@ struct nct6775_data {
        u8 bank;                /* current register bank */
        u8 in_num;              /* number of in inputs we have */
        u8 in[15][3];           /* [0]=in, [1]=in_max, [2]=in_min */
-       unsigned int rpm[5];
-       u16 fan_min[5];
-       u8 fan_pulses[5];
-       u8 fan_div[5];
+       unsigned int rpm[NUM_FAN];
+       u16 fan_min[NUM_FAN];
+       u8 fan_pulses[NUM_FAN];
+       u8 fan_div[NUM_FAN];
        u8 has_pwm;
        u8 has_fan;             /* some fan inputs can be disabled */
        u8 has_fan_min;         /* some fans don't have min register */
        bool has_fan_div;
 
-       u8 num_temp_alarms;     /* 2 or 3 */
+       u8 num_temp_alarms;     /* 2, 3, or 6 */
+       u8 num_temp_beeps;      /* 2, 3, or 6 */
        u8 temp_fixed_num;      /* 3 or 6 */
        u8 temp_type[NUM_TEMP_FIXED];
        s8 temp_offset[NUM_TEMP_FIXED];
-       s16 temp[4][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
-                               * 3=temp_crit */
+       s16 temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
+                               * 3=temp_crit, 4=temp_lcrit */
        u64 alarms;
+       u64 beeps;
 
        u8 pwm_num;     /* number of pwm */
-       u8 pwm_mode[5]; /* 1->DC variable voltage, 0->PWM variable duty cycle */
-       enum pwm_enable pwm_enable[5];
+       u8 pwm_mode[NUM_FAN];   /* 1->DC variable voltage,
+                                * 0->PWM variable duty cycle
+                                */
+       enum pwm_enable pwm_enable[NUM_FAN];
                        /* 0->off
                         * 1->manual
                         * 2->thermal cruise mode (also called SmartFan I)
@@ -643,35 +830,37 @@ struct nct6775_data {
                         * 4->SmartFan III
                         * 5->enhanced variable thermal cruise (SmartFan IV)
                         */
-       u8 pwm[7][5];   /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
-                        * [3]=pwm_max, [4]=pwm_step,
-                        * [5]=weight_duty_step, [6]=weight_duty_base
-                        */
+       u8 pwm[7][NUM_FAN];     /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
+                                * [3]=pwm_max, [4]=pwm_step,
+                                * [5]=weight_duty_step, [6]=weight_duty_base
+                                */
 
-       u8 target_temp[5];
+       u8 target_temp[NUM_FAN];
        u8 target_temp_mask;
-       u32 target_speed[5];
-       u32 target_speed_tolerance[5];
+       u32 target_speed[NUM_FAN];
+       u32 target_speed_tolerance[NUM_FAN];
        u8 speed_tolerance_limit;
 
-       u8 temp_tolerance[2][5];
+       u8 temp_tolerance[2][NUM_FAN];
        u8 tolerance_mask;
 
-       u8 fan_time[3][5]; /* 0 = stop_time, 1 = step_up, 2 = step_down */
+       u8 fan_time[3][NUM_FAN]; /* 0 = stop_time, 1 = step_up, 2 = step_down */
 
        /* Automatic fan speed control registers */
        int auto_pwm_num;
-       u8 auto_pwm[5][7];
-       u8 auto_temp[5][7];
-       u8 pwm_temp_sel[5];
-       u8 pwm_weight_temp_sel[5];
-       u8 weight_temp[3][5];   /* 0->temp_step, 1->temp_step_tol,
-                                * 2->temp_base
-                                */
+       u8 auto_pwm[NUM_FAN][7];
+       u8 auto_temp[NUM_FAN][7];
+       u8 pwm_temp_sel[NUM_FAN];
+       u8 pwm_weight_temp_sel[NUM_FAN];
+       u8 weight_temp[3][NUM_FAN];     /* 0->temp_step, 1->temp_step_tol,
+                                        * 2->temp_base
+                                        */
 
        u8 vid;
        u8 vrm;
 
+       bool have_vid;
+
        u16 have_temp;
        u16 have_temp_fixed;
        u16 have_in;
@@ -688,9 +877,145 @@ struct nct6775_sio_data {
        enum kinds kind;
 };
 
+struct sensor_device_template {
+       struct device_attribute dev_attr;
+       union {
+               struct {
+                       u8 nr;
+                       u8 index;
+               } s;
+               int index;
+       } u;
+       bool s2;        /* true if both index and nr are used */
+};
+
+struct sensor_device_attr_u {
+       union {
+               struct sensor_device_attribute a1;
+               struct sensor_device_attribute_2 a2;
+       } u;
+       char name[32];
+};
+
+#define __TEMPLATE_ATTR(_template, _mode, _show, _store) {     \
+       .attr = {.name = _template, .mode = _mode },            \
+       .show   = _show,                                        \
+       .store  = _store,                                       \
+}
+
+#define SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, _index)        \
+       { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
+         .u.index = _index,                                            \
+         .s2 = false }
+
+#define SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store,      \
+                                _nr, _index)                           \
+       { .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store), \
+         .u.s.index = _index,                                          \
+         .u.s.nr = _nr,                                                \
+         .s2 = true }
+
+#define SENSOR_TEMPLATE(_name, _template, _mode, _show, _store, _index)        \
+static struct sensor_device_template sensor_dev_template_##_name       \
+       = SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store,       \
+                                _index)
+
+#define SENSOR_TEMPLATE_2(_name, _template, _mode, _show, _store,      \
+                         _nr, _index)                                  \
+static struct sensor_device_template sensor_dev_template_##_name       \
+       = SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store,     \
+                                _nr, _index)
+
+struct sensor_template_group {
+       struct sensor_device_template **templates;
+       umode_t (*is_visible)(struct kobject *, struct attribute *, int);
+       int base;
+};
+
+static struct attribute_group *
+nct6775_create_attr_group(struct device *dev, struct sensor_template_group *tg,
+                         int repeat)
+{
+       struct attribute_group *group;
+       struct sensor_device_attr_u *su;
+       struct sensor_device_attribute *a;
+       struct sensor_device_attribute_2 *a2;
+       struct attribute **attrs;
+       struct sensor_device_template **t;
+       int err, i, j, count;
+
+       if (repeat <= 0)
+               return ERR_PTR(-EINVAL);
+
+       t = tg->templates;
+       for (count = 0; *t; t++, count++)
+               ;
+
+       if (count == 0)
+               return ERR_PTR(-EINVAL);
+
+       group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL);
+       if (group == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       attrs = devm_kzalloc(dev, sizeof(*attrs) * (repeat * count + 1),
+                            GFP_KERNEL);
+       if (attrs == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       su = devm_kzalloc(dev, sizeof(*su) * repeat * count,
+                              GFP_KERNEL);
+       if (su == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       group->attrs = attrs;
+       group->is_visible = tg->is_visible;
+
+       for (i = 0; i < repeat; i++) {
+               t = tg->templates;
+               for (j = 0; *t != NULL; j++) {
+                       snprintf(su->name, sizeof(su->name),
+                                (*t)->dev_attr.attr.name, tg->base + i);
+                       if ((*t)->s2) {
+                               a2 = &su->u.a2;
+                               a2->dev_attr.attr.name = su->name;
+                               a2->nr = (*t)->u.s.nr + i;
+                               a2->index = (*t)->u.s.index;
+                               a2->dev_attr.attr.mode =
+                                 (*t)->dev_attr.attr.mode;
+                               a2->dev_attr.show = (*t)->dev_attr.show;
+                               a2->dev_attr.store = (*t)->dev_attr.store;
+                               *attrs = &a2->dev_attr.attr;
+                       } else {
+                               a = &su->u.a1;
+                               a->dev_attr.attr.name = su->name;
+                               a->index = (*t)->u.index + i;
+                               a->dev_attr.attr.mode =
+                                 (*t)->dev_attr.attr.mode;
+                               a->dev_attr.show = (*t)->dev_attr.show;
+                               a->dev_attr.store = (*t)->dev_attr.store;
+                               *attrs = &a->dev_attr.attr;
+                       }
+                       attrs++;
+                       su++;
+                       t++;
+               }
+       }
+
+       err = sysfs_create_group(&dev->kobj, group);
+       if (err)
+               return ERR_PTR(-ENOMEM);
+
+       return group;
+}
+
 static bool is_word_sized(struct nct6775_data *data, u16 reg)
 {
        switch (data->kind) {
+       case nct6106:
+               return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
+                 reg == 0xe0 || reg == 0xe2 || reg == 0xe4 ||
+                 reg == 0x111 || reg == 0x121 || reg == 0x131;
        case nct6775:
                return (((reg & 0xff00) == 0x100 ||
                    (reg & 0xff00) == 0x200) &&
@@ -714,8 +1039,9 @@ static bool is_word_sized(struct nct6775_data *data, u16 reg)
                  ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
                  reg == 0x73 || reg == 0x75 || reg == 0x77;
        case nct6779:
+       case nct6791:
                return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
-                 ((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x09) ||
+                 ((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x0b) ||
                  reg == 0x402 ||
                  reg == 0x63a || reg == 0x63c || reg == 0x63e ||
                  reg == 0x640 || reg == 0x642 ||
@@ -1056,15 +1382,17 @@ static void nct6775_update_pwm_limits(struct device *dev)
                case nct6776:
                        data->auto_pwm[i][data->auto_pwm_num] = 0xff;
                        break;
+               case nct6106:
                case nct6779:
+               case nct6791:
                        reg = nct6775_read_value(data,
-                                       NCT6779_REG_CRITICAL_PWM_ENABLE[i]);
-                       if (reg & 1)
-                               data->auto_pwm[i][data->auto_pwm_num] =
-                                 nct6775_read_value(data,
-                                       NCT6779_REG_CRITICAL_PWM[i]);
+                                       data->REG_CRITICAL_PWM_ENABLE[i]);
+                       if (reg & data->CRITICAL_PWM_ENABLE_MASK)
+                               reg = nct6775_read_value(data,
+                                       data->REG_CRITICAL_PWM[i]);
                        else
-                               data->auto_pwm[i][data->auto_pwm_num] = 0xff;
+                               reg = 0xff;
+                       data->auto_pwm[i][data->auto_pwm_num] = reg;
                        break;
                }
        }
@@ -1110,7 +1438,8 @@ static struct nct6775_data *nct6775_update_device(struct device *dev)
                                data->fan_min[i] = nct6775_read_value(data,
                                           data->REG_FAN_MIN[i]);
                        data->fan_pulses[i] =
-                         nct6775_read_value(data, data->REG_FAN_PULSES[i]);
+                         (nct6775_read_value(data, data->REG_FAN_PULSES[i])
+                               >> data->FAN_PULSE_SHIFT[i]) & 0x03;
 
                        nct6775_select_fan_div(dev, data, i, reg);
                }
@@ -1143,6 +1472,15 @@ static struct nct6775_data *nct6775_update_device(struct device *dev)
                        data->alarms |= ((u64)alarm) << (i << 3);
                }
 
+               data->beeps = 0;
+               for (i = 0; i < NUM_REG_BEEP; i++) {
+                       u8 beep;
+                       if (!data->REG_BEEP[i])
+                               continue;
+                       beep = nct6775_read_value(data, data->REG_BEEP[i]);
+                       data->beeps |= ((u64)beep) << (i << 3);
+               }
+
                data->last_updated = jiffies;
                data->valid = true;
        }
@@ -1230,224 +1568,138 @@ show_temp_alarm(struct device *dev, struct device_attribute *attr, char *buf)
        return sprintf(buf, "%u\n", alarm);
 }
 
-static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, show_in_reg, NULL, 0, 0);
-static SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, show_in_reg, NULL, 1, 0);
-static SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, show_in_reg, NULL, 2, 0);
-static SENSOR_DEVICE_ATTR_2(in3_input, S_IRUGO, show_in_reg, NULL, 3, 0);
-static SENSOR_DEVICE_ATTR_2(in4_input, S_IRUGO, show_in_reg, NULL, 4, 0);
-static SENSOR_DEVICE_ATTR_2(in5_input, S_IRUGO, show_in_reg, NULL, 5, 0);
-static SENSOR_DEVICE_ATTR_2(in6_input, S_IRUGO, show_in_reg, NULL, 6, 0);
-static SENSOR_DEVICE_ATTR_2(in7_input, S_IRUGO, show_in_reg, NULL, 7, 0);
-static SENSOR_DEVICE_ATTR_2(in8_input, S_IRUGO, show_in_reg, NULL, 8, 0);
-static SENSOR_DEVICE_ATTR_2(in9_input, S_IRUGO, show_in_reg, NULL, 9, 0);
-static SENSOR_DEVICE_ATTR_2(in10_input, S_IRUGO, show_in_reg, NULL, 10, 0);
-static SENSOR_DEVICE_ATTR_2(in11_input, S_IRUGO, show_in_reg, NULL, 11, 0);
-static SENSOR_DEVICE_ATTR_2(in12_input, S_IRUGO, show_in_reg, NULL, 12, 0);
-static SENSOR_DEVICE_ATTR_2(in13_input, S_IRUGO, show_in_reg, NULL, 13, 0);
-static SENSOR_DEVICE_ATTR_2(in14_input, S_IRUGO, show_in_reg, NULL, 14, 0);
-
-static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
-static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
-static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
-static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
-static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 4);
-static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 5);
-static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 6);
-static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 7);
-static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 8);
-static SENSOR_DEVICE_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 9);
-static SENSOR_DEVICE_ATTR(in10_alarm, S_IRUGO, show_alarm, NULL, 10);
-static SENSOR_DEVICE_ATTR(in11_alarm, S_IRUGO, show_alarm, NULL, 11);
-static SENSOR_DEVICE_ATTR(in12_alarm, S_IRUGO, show_alarm, NULL, 12);
-static SENSOR_DEVICE_ATTR(in13_alarm, S_IRUGO, show_alarm, NULL, 13);
-static SENSOR_DEVICE_ATTR(in14_alarm, S_IRUGO, show_alarm, NULL, 14);
-
-static SENSOR_DEVICE_ATTR_2(in0_min, S_IWUSR | S_IRUGO, show_in_reg,
-                           store_in_reg, 0, 1);
-static SENSOR_DEVICE_ATTR_2(in1_min, S_IWUSR | S_IRUGO, show_in_reg,
-                           store_in_reg, 1, 1);
-static SENSOR_DEVICE_ATTR_2(in2_min, S_IWUSR | S_IRUGO, show_in_reg,
-                           store_in_reg, 2, 1);
-static SENSOR_DEVICE_ATTR_2(in3_min, S_IWUSR | S_IRUGO, show_in_reg,
-                           store_in_reg, 3, 1);
-static SENSOR_DEVICE_ATTR_2(in4_min, S_IWUSR | S_IRUGO, show_in_reg,
-                           store_in_reg, 4, 1);
-static SENSOR_DEVICE_ATTR_2(in5_min, S_IWUSR | S_IRUGO, show_in_reg,
-                           store_in_reg, 5, 1);
-static SENSOR_DEVICE_ATTR_2(in6_min, S_IWUSR | S_IRUGO, show_in_reg,
-                           store_in_reg, 6, 1);
-static SENSOR_DEVICE_ATTR_2(in7_min, S_IWUSR | S_IRUGO, show_in_reg,
-                           store_in_reg, 7, 1);
-static SENSOR_DEVICE_ATTR_2(in8_min, S_IWUSR | S_IRUGO, show_in_reg,
-                           store_in_reg, 8, 1);
-static SENSOR_DEVICE_ATTR_2(in9_min, S_IWUSR | S_IRUGO, show_in_reg,
-                           store_in_reg, 9, 1);
-static SENSOR_DEVICE_ATTR_2(in10_min, S_IWUSR | S_IRUGO, show_in_reg,
-                           store_in_reg, 10, 1);
-static SENSOR_DEVICE_ATTR_2(in11_min, S_IWUSR | S_IRUGO, show_in_reg,
-                           store_in_reg, 11, 1);
-static SENSOR_DEVICE_ATTR_2(in12_min, S_IWUSR | S_IRUGO, show_in_reg,
-                           store_in_reg, 12, 1);
-static SENSOR_DEVICE_ATTR_2(in13_min, S_IWUSR | S_IRUGO, show_in_reg,
-                           store_in_reg, 13, 1);
-static SENSOR_DEVICE_ATTR_2(in14_min, S_IWUSR | S_IRUGO, show_in_reg,
-                           store_in_reg, 14, 1);
-
-static SENSOR_DEVICE_ATTR_2(in0_max, S_IWUSR | S_IRUGO, show_in_reg,
-                           store_in_reg, 0, 2);
-static SENSOR_DEVICE_ATTR_2(in1_max, S_IWUSR | S_IRUGO, show_in_reg,
-                           store_in_reg, 1, 2);
-static SENSOR_DEVICE_ATTR_2(in2_max, S_IWUSR | S_IRUGO, show_in_reg,
-                           store_in_reg, 2, 2);
-static SENSOR_DEVICE_ATTR_2(in3_max, S_IWUSR | S_IRUGO, show_in_reg,
-                           store_in_reg, 3, 2);
-static SENSOR_DEVICE_ATTR_2(in4_max, S_IWUSR | S_IRUGO, show_in_reg,
-                           store_in_reg, 4, 2);
-static SENSOR_DEVICE_ATTR_2(in5_max, S_IWUSR | S_IRUGO, show_in_reg,
-                           store_in_reg, 5, 2);
-static SENSOR_DEVICE_ATTR_2(in6_max, S_IWUSR | S_IRUGO, show_in_reg,
-                           store_in_reg, 6, 2);
-static SENSOR_DEVICE_ATTR_2(in7_max, S_IWUSR | S_IRUGO, show_in_reg,
-                           store_in_reg, 7, 2);
-static SENSOR_DEVICE_ATTR_2(in8_max, S_IWUSR | S_IRUGO, show_in_reg,
-                           store_in_reg, 8, 2);
-static SENSOR_DEVICE_ATTR_2(in9_max, S_IWUSR | S_IRUGO, show_in_reg,
-                           store_in_reg, 9, 2);
-static SENSOR_DEVICE_ATTR_2(in10_max, S_IWUSR | S_IRUGO, show_in_reg,
-                           store_in_reg, 10, 2);
-static SENSOR_DEVICE_ATTR_2(in11_max, S_IWUSR | S_IRUGO, show_in_reg,
-                           store_in_reg, 11, 2);
-static SENSOR_DEVICE_ATTR_2(in12_max, S_IWUSR | S_IRUGO, show_in_reg,
-                           store_in_reg, 12, 2);
-static SENSOR_DEVICE_ATTR_2(in13_max, S_IWUSR | S_IRUGO, show_in_reg,
-                           store_in_reg, 13, 2);
-static SENSOR_DEVICE_ATTR_2(in14_max, S_IWUSR | S_IRUGO, show_in_reg,
-                           store_in_reg, 14, 2);
-
-static struct attribute *nct6775_attributes_in[15][5] = {
-       {
-               &sensor_dev_attr_in0_input.dev_attr.attr,
-               &sensor_dev_attr_in0_min.dev_attr.attr,
-               &sensor_dev_attr_in0_max.dev_attr.attr,
-               &sensor_dev_attr_in0_alarm.dev_attr.attr,
-               NULL
-       },
-       {
-               &sensor_dev_attr_in1_input.dev_attr.attr,
-               &sensor_dev_attr_in1_min.dev_attr.attr,
-               &sensor_dev_attr_in1_max.dev_attr.attr,
-               &sensor_dev_attr_in1_alarm.dev_attr.attr,
-               NULL
-       },
-       {
-               &sensor_dev_attr_in2_input.dev_attr.attr,
-               &sensor_dev_attr_in2_min.dev_attr.attr,
-               &sensor_dev_attr_in2_max.dev_attr.attr,
-               &sensor_dev_attr_in2_alarm.dev_attr.attr,
-               NULL
-       },
-       {
-               &sensor_dev_attr_in3_input.dev_attr.attr,
-               &sensor_dev_attr_in3_min.dev_attr.attr,
-               &sensor_dev_attr_in3_max.dev_attr.attr,
-               &sensor_dev_attr_in3_alarm.dev_attr.attr,
-               NULL
-       },
-       {
-               &sensor_dev_attr_in4_input.dev_attr.attr,
-               &sensor_dev_attr_in4_min.dev_attr.attr,
-               &sensor_dev_attr_in4_max.dev_attr.attr,
-               &sensor_dev_attr_in4_alarm.dev_attr.attr,
-               NULL
-       },
-       {
-               &sensor_dev_attr_in5_input.dev_attr.attr,
-               &sensor_dev_attr_in5_min.dev_attr.attr,
-               &sensor_dev_attr_in5_max.dev_attr.attr,
-               &sensor_dev_attr_in5_alarm.dev_attr.attr,
-               NULL
-       },
-       {
-               &sensor_dev_attr_in6_input.dev_attr.attr,
-               &sensor_dev_attr_in6_min.dev_attr.attr,
-               &sensor_dev_attr_in6_max.dev_attr.attr,
-               &sensor_dev_attr_in6_alarm.dev_attr.attr,
-               NULL
-       },
-       {
-               &sensor_dev_attr_in7_input.dev_attr.attr,
-               &sensor_dev_attr_in7_min.dev_attr.attr,
-               &sensor_dev_attr_in7_max.dev_attr.attr,
-               &sensor_dev_attr_in7_alarm.dev_attr.attr,
-               NULL
-       },
-       {
-               &sensor_dev_attr_in8_input.dev_attr.attr,
-               &sensor_dev_attr_in8_min.dev_attr.attr,
-               &sensor_dev_attr_in8_max.dev_attr.attr,
-               &sensor_dev_attr_in8_alarm.dev_attr.attr,
-               NULL
-       },
-       {
-               &sensor_dev_attr_in9_input.dev_attr.attr,
-               &sensor_dev_attr_in9_min.dev_attr.attr,
-               &sensor_dev_attr_in9_max.dev_attr.attr,
-               &sensor_dev_attr_in9_alarm.dev_attr.attr,
-               NULL
-       },
-       {
-               &sensor_dev_attr_in10_input.dev_attr.attr,
-               &sensor_dev_attr_in10_min.dev_attr.attr,
-               &sensor_dev_attr_in10_max.dev_attr.attr,
-               &sensor_dev_attr_in10_alarm.dev_attr.attr,
-               NULL
-       },
-       {
-               &sensor_dev_attr_in11_input.dev_attr.attr,
-               &sensor_dev_attr_in11_min.dev_attr.attr,
-               &sensor_dev_attr_in11_max.dev_attr.attr,
-               &sensor_dev_attr_in11_alarm.dev_attr.attr,
-               NULL
-       },
-       {
-               &sensor_dev_attr_in12_input.dev_attr.attr,
-               &sensor_dev_attr_in12_min.dev_attr.attr,
-               &sensor_dev_attr_in12_max.dev_attr.attr,
-               &sensor_dev_attr_in12_alarm.dev_attr.attr,
-               NULL
-       },
-       {
-               &sensor_dev_attr_in13_input.dev_attr.attr,
-               &sensor_dev_attr_in13_min.dev_attr.attr,
-               &sensor_dev_attr_in13_max.dev_attr.attr,
-               &sensor_dev_attr_in13_alarm.dev_attr.attr,
-               NULL
-       },
-       {
-               &sensor_dev_attr_in14_input.dev_attr.attr,
-               &sensor_dev_attr_in14_min.dev_attr.attr,
-               &sensor_dev_attr_in14_max.dev_attr.attr,
-               &sensor_dev_attr_in14_alarm.dev_attr.attr,
-               NULL
-       },
+static ssize_t
+show_beep(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       struct nct6775_data *data = nct6775_update_device(dev);
+       int nr = data->BEEP_BITS[sattr->index];
+
+       return sprintf(buf, "%u\n",
+                      (unsigned int)((data->beeps >> nr) & 0x01));
+}
+
+static ssize_t
+store_beep(struct device *dev, struct device_attribute *attr, const char *buf,
+          size_t count)
+{
+       struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+       struct nct6775_data *data = dev_get_drvdata(dev);
+       int nr = data->BEEP_BITS[sattr->index];
+       int regindex = nr >> 3;
+       unsigned long val;
+
+       int err = kstrtoul(buf, 10, &val);
+       if (err < 0)
+               return err;
+       if (val > 1)
+               return -EINVAL;
+
+       mutex_lock(&data->update_lock);
+       if (val)
+               data->beeps |= (1ULL << nr);
+       else
+               data->beeps &= ~(1ULL << nr);
+       nct6775_write_value(data, data->REG_BEEP[regindex],
+                           (data->beeps >> (regindex << 3)) & 0xff);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static ssize_t
+show_temp_beep(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       struct nct6775_data *data = nct6775_update_device(dev);
+       unsigned int beep = 0;
+       int nr;
+
+       /*
+        * For temperatures, there is no fixed mapping from registers to beep
+        * enable bits. Beep enable bits are determined by the temperature
+        * source mapping.
+        */
+       nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
+       if (nr >= 0) {
+               int bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
+               beep = (data->beeps >> bit) & 0x01;
+       }
+       return sprintf(buf, "%u\n", beep);
+}
+
+static ssize_t
+store_temp_beep(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+       struct nct6775_data *data = dev_get_drvdata(dev);
+       int nr, bit, regindex;
+       unsigned long val;
+
+       int err = kstrtoul(buf, 10, &val);
+       if (err < 0)
+               return err;
+       if (val > 1)
+               return -EINVAL;
+
+       nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
+       if (nr < 0)
+               return -ENODEV;
+
+       bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
+       regindex = bit >> 3;
+
+       mutex_lock(&data->update_lock);
+       if (val)
+               data->beeps |= (1ULL << bit);
+       else
+               data->beeps &= ~(1ULL << bit);
+       nct6775_write_value(data, data->REG_BEEP[regindex],
+                           (data->beeps >> (regindex << 3)) & 0xff);
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static umode_t nct6775_in_is_visible(struct kobject *kobj,
+                                    struct attribute *attr, int index)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct nct6775_data *data = dev_get_drvdata(dev);
+       int in = index / 5;     /* voltage index */
+
+       if (!(data->have_in & (1 << in)))
+               return 0;
+
+       return attr->mode;
+}
+
+SENSOR_TEMPLATE_2(in_input, "in%d_input", S_IRUGO, show_in_reg, NULL, 0, 0);
+SENSOR_TEMPLATE(in_alarm, "in%d_alarm", S_IRUGO, show_alarm, NULL, 0);
+SENSOR_TEMPLATE(in_beep, "in%d_beep", S_IWUSR | S_IRUGO, show_beep, store_beep,
+               0);
+SENSOR_TEMPLATE_2(in_min, "in%d_min", S_IWUSR | S_IRUGO, show_in_reg,
+                 store_in_reg, 0, 1);
+SENSOR_TEMPLATE_2(in_max, "in%d_max", S_IWUSR | S_IRUGO, show_in_reg,
+                 store_in_reg, 0, 2);
+
+/*
+ * nct6775_in_is_visible uses the index into the following array
+ * to determine if attributes should be created or not.
+ * Any change in order or content must be matched.
+ */
+static struct sensor_device_template *nct6775_attributes_in_template[] = {
+       &sensor_dev_template_in_input,
+       &sensor_dev_template_in_alarm,
+       &sensor_dev_template_in_beep,
+       &sensor_dev_template_in_min,
+       &sensor_dev_template_in_max,
+       NULL
 };
 
-static const struct attribute_group nct6775_group_in[15] = {
-       { .attrs = nct6775_attributes_in[0] },
-       { .attrs = nct6775_attributes_in[1] },
-       { .attrs = nct6775_attributes_in[2] },
-       { .attrs = nct6775_attributes_in[3] },
-       { .attrs = nct6775_attributes_in[4] },
-       { .attrs = nct6775_attributes_in[5] },
-       { .attrs = nct6775_attributes_in[6] },
-       { .attrs = nct6775_attributes_in[7] },
-       { .attrs = nct6775_attributes_in[8] },
-       { .attrs = nct6775_attributes_in[9] },
-       { .attrs = nct6775_attributes_in[10] },
-       { .attrs = nct6775_attributes_in[11] },
-       { .attrs = nct6775_attributes_in[12] },
-       { .attrs = nct6775_attributes_in[13] },
-       { .attrs = nct6775_attributes_in[14] },
+static struct sensor_template_group nct6775_in_template_group = {
+       .templates = nct6775_attributes_in_template,
+       .is_visible = nct6775_in_is_visible,
 };
 
 static ssize_t
@@ -1592,6 +1844,7 @@ store_fan_pulses(struct device *dev, struct device_attribute *attr,
        int nr = sattr->index;
        unsigned long val;
        int err;
+       u8 reg;
 
        err = kstrtoul(buf, 10, &val);
        if (err < 0)
@@ -1602,60 +1855,68 @@ store_fan_pulses(struct device *dev, struct device_attribute *attr,
 
        mutex_lock(&data->update_lock);
        data->fan_pulses[nr] = val & 3;
-       nct6775_write_value(data, data->REG_FAN_PULSES[nr], val & 3);
+       reg = nct6775_read_value(data, data->REG_FAN_PULSES[nr]);
+       reg &= ~(0x03 << data->FAN_PULSE_SHIFT[nr]);
+       reg |= (val & 3) << data->FAN_PULSE_SHIFT[nr];
+       nct6775_write_value(data, data->REG_FAN_PULSES[nr], reg);
        mutex_unlock(&data->update_lock);
 
        return count;
 }
 
-static struct sensor_device_attribute sda_fan_input[] = {
-       SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
-       SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
-       SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
-       SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3),
-       SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4),
-};
+static umode_t nct6775_fan_is_visible(struct kobject *kobj,
+                                     struct attribute *attr, int index)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct nct6775_data *data = dev_get_drvdata(dev);
+       int fan = index / 6;    /* fan index */
+       int nr = index % 6;     /* attribute index */
 
-static struct sensor_device_attribute sda_fan_alarm[] = {
-       SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, FAN_ALARM_BASE),
-       SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, FAN_ALARM_BASE + 1),
-       SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, FAN_ALARM_BASE + 2),
-       SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, FAN_ALARM_BASE + 3),
-       SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, FAN_ALARM_BASE + 4),
-};
+       if (!(data->has_fan & (1 << fan)))
+               return 0;
 
-static struct sensor_device_attribute sda_fan_min[] = {
-       SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
-                   store_fan_min, 0),
-       SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min,
-                   store_fan_min, 1),
-       SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min,
-                   store_fan_min, 2),
-       SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min,
-                   store_fan_min, 3),
-       SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO, show_fan_min,
-                   store_fan_min, 4),
-};
+       if (nr == 1 && data->ALARM_BITS[FAN_ALARM_BASE + fan] == -1)
+               return 0;
+       if (nr == 2 && data->BEEP_BITS[FAN_ALARM_BASE + fan] == -1)
+               return 0;
+       if (nr == 4 && !(data->has_fan_min & (1 << fan)))
+               return 0;
+       if (nr == 5 && data->kind != nct6775)
+               return 0;
+
+       return attr->mode;
+}
 
-static struct sensor_device_attribute sda_fan_pulses[] = {
-       SENSOR_ATTR(fan1_pulses, S_IWUSR | S_IRUGO, show_fan_pulses,
-                   store_fan_pulses, 0),
-       SENSOR_ATTR(fan2_pulses, S_IWUSR | S_IRUGO, show_fan_pulses,
-                   store_fan_pulses, 1),
-       SENSOR_ATTR(fan3_pulses, S_IWUSR | S_IRUGO, show_fan_pulses,
-                   store_fan_pulses, 2),
-       SENSOR_ATTR(fan4_pulses, S_IWUSR | S_IRUGO, show_fan_pulses,
-                   store_fan_pulses, 3),
-       SENSOR_ATTR(fan5_pulses, S_IWUSR | S_IRUGO, show_fan_pulses,
-                   store_fan_pulses, 4),
+SENSOR_TEMPLATE(fan_input, "fan%d_input", S_IRUGO, show_fan, NULL, 0);
+SENSOR_TEMPLATE(fan_alarm, "fan%d_alarm", S_IRUGO, show_alarm, NULL,
+               FAN_ALARM_BASE);
+SENSOR_TEMPLATE(fan_beep, "fan%d_beep", S_IWUSR | S_IRUGO, show_beep,
+               store_beep, FAN_ALARM_BASE);
+SENSOR_TEMPLATE(fan_pulses, "fan%d_pulses", S_IWUSR | S_IRUGO, show_fan_pulses,
+               store_fan_pulses, 0);
+SENSOR_TEMPLATE(fan_min, "fan%d_min", S_IWUSR | S_IRUGO, show_fan_min,
+               store_fan_min, 0);
+SENSOR_TEMPLATE(fan_div, "fan%d_div", S_IRUGO, show_fan_div, NULL, 0);
+
+/*
+ * nct6775_fan_is_visible uses the index into the following array
+ * to determine if attributes should be created or not.
+ * Any change in order or content must be matched.
+ */
+static struct sensor_device_template *nct6775_attributes_fan_template[] = {
+       &sensor_dev_template_fan_input,
+       &sensor_dev_template_fan_alarm, /* 1 */
+       &sensor_dev_template_fan_beep,  /* 2 */
+       &sensor_dev_template_fan_pulses,
+       &sensor_dev_template_fan_min,   /* 4 */
+       &sensor_dev_template_fan_div,   /* 5 */
+       NULL
 };
 
-static struct sensor_device_attribute sda_fan_div[] = {
-       SENSOR_ATTR(fan1_div, S_IRUGO, show_fan_div, NULL, 0),
-       SENSOR_ATTR(fan2_div, S_IRUGO, show_fan_div, NULL, 1),
-       SENSOR_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2),
-       SENSOR_ATTR(fan4_div, S_IRUGO, show_fan_div, NULL, 3),
-       SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4),
+static struct sensor_template_group nct6775_fan_template_group = {
+       .templates = nct6775_attributes_fan_template,
+       .is_visible = nct6775_fan_is_visible,
+       .base = 1,
 };
 
 static ssize_t
@@ -1752,7 +2013,7 @@ store_temp_type(struct device *dev, struct device_attribute *attr,
        int nr = sattr->index;
        unsigned long val;
        int err;
-       u8 vbat, diode, bit;
+       u8 vbat, diode, vbit, dbit;
 
        err = kstrtoul(buf, 10, &val);
        if (err < 0)
@@ -1764,16 +2025,17 @@ store_temp_type(struct device *dev, struct device_attribute *attr,
        mutex_lock(&data->update_lock);
 
        data->temp_type[nr] = val;
-       vbat = nct6775_read_value(data, data->REG_VBAT) & ~(0x02 << nr);
-       diode = nct6775_read_value(data, data->REG_DIODE) & ~(0x02 << nr);
-       bit = 0x02 << nr;
+       vbit = 0x02 << nr;
+       dbit = data->DIODE_MASK << nr;
+       vbat = nct6775_read_value(data, data->REG_VBAT) & ~vbit;
+       diode = nct6775_read_value(data, data->REG_DIODE) & ~dbit;
        switch (val) {
        case 1: /* CPU diode (diode, current mode) */
-               vbat |= bit;
-               diode |= bit;
+               vbat |= vbit;
+               diode |= dbit;
                break;
        case 3: /* diode, voltage mode */
-               vbat |= bit;
+               vbat |= dbit;
                break;
        case 4: /* thermistor */
                break;
@@ -1785,142 +2047,83 @@ store_temp_type(struct device *dev, struct device_attribute *attr,
        return count;
 }
 
-static struct sensor_device_attribute_2 sda_temp_input[] = {
-       SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
-       SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 1, 0),
-       SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 2, 0),
-       SENSOR_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 3, 0),
-       SENSOR_ATTR_2(temp5_input, S_IRUGO, show_temp, NULL, 4, 0),
-       SENSOR_ATTR_2(temp6_input, S_IRUGO, show_temp, NULL, 5, 0),
-       SENSOR_ATTR_2(temp7_input, S_IRUGO, show_temp, NULL, 6, 0),
-       SENSOR_ATTR_2(temp8_input, S_IRUGO, show_temp, NULL, 7, 0),
-       SENSOR_ATTR_2(temp9_input, S_IRUGO, show_temp, NULL, 8, 0),
-       SENSOR_ATTR_2(temp10_input, S_IRUGO, show_temp, NULL, 9, 0),
-};
+static umode_t nct6775_temp_is_visible(struct kobject *kobj,
+                                      struct attribute *attr, int index)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct nct6775_data *data = dev_get_drvdata(dev);
+       int temp = index / 10;  /* temp index */
+       int nr = index % 10;    /* attribute index */
 
-static struct sensor_device_attribute sda_temp_label[] = {
-       SENSOR_ATTR(temp1_label, S_IRUGO, show_temp_label, NULL, 0),
-       SENSOR_ATTR(temp2_label, S_IRUGO, show_temp_label, NULL, 1),
-       SENSOR_ATTR(temp3_label, S_IRUGO, show_temp_label, NULL, 2),
-       SENSOR_ATTR(temp4_label, S_IRUGO, show_temp_label, NULL, 3),
-       SENSOR_ATTR(temp5_label, S_IRUGO, show_temp_label, NULL, 4),
-       SENSOR_ATTR(temp6_label, S_IRUGO, show_temp_label, NULL, 5),
-       SENSOR_ATTR(temp7_label, S_IRUGO, show_temp_label, NULL, 6),
-       SENSOR_ATTR(temp8_label, S_IRUGO, show_temp_label, NULL, 7),
-       SENSOR_ATTR(temp9_label, S_IRUGO, show_temp_label, NULL, 8),
-       SENSOR_ATTR(temp10_label, S_IRUGO, show_temp_label, NULL, 9),
-};
+       if (!(data->have_temp & (1 << temp)))
+               return 0;
 
-static struct sensor_device_attribute_2 sda_temp_max[] = {
-       SENSOR_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
-                     0, 1),
-       SENSOR_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
-                     1, 1),
-       SENSOR_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
-                     2, 1),
-       SENSOR_ATTR_2(temp4_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
-                     3, 1),
-       SENSOR_ATTR_2(temp5_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
-                     4, 1),
-       SENSOR_ATTR_2(temp6_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
-                     5, 1),
-       SENSOR_ATTR_2(temp7_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
-                     6, 1),
-       SENSOR_ATTR_2(temp8_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
-                     7, 1),
-       SENSOR_ATTR_2(temp9_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
-                     8, 1),
-       SENSOR_ATTR_2(temp10_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
-                     9, 1),
-};
+       if (nr == 2 && find_temp_source(data, temp, data->num_temp_alarms) < 0)
+               return 0;                               /* alarm */
 
-static struct sensor_device_attribute_2 sda_temp_max_hyst[] = {
-       SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
-                     0, 2),
-       SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
-                     1, 2),
-       SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
-                     2, 2),
-       SENSOR_ATTR_2(temp4_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
-                     3, 2),
-       SENSOR_ATTR_2(temp5_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
-                     4, 2),
-       SENSOR_ATTR_2(temp6_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
-                     5, 2),
-       SENSOR_ATTR_2(temp7_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
-                     6, 2),
-       SENSOR_ATTR_2(temp8_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
-                     7, 2),
-       SENSOR_ATTR_2(temp9_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
-                     8, 2),
-       SENSOR_ATTR_2(temp10_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
-                     9, 2),
-};
+       if (nr == 3 && find_temp_source(data, temp, data->num_temp_beeps) < 0)
+               return 0;                               /* beep */
 
-static struct sensor_device_attribute_2 sda_temp_crit[] = {
-       SENSOR_ATTR_2(temp1_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
-                     0, 3),
-       SENSOR_ATTR_2(temp2_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
-                     1, 3),
-       SENSOR_ATTR_2(temp3_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
-                     2, 3),
-       SENSOR_ATTR_2(temp4_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
-                     3, 3),
-       SENSOR_ATTR_2(temp5_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
-                     4, 3),
-       SENSOR_ATTR_2(temp6_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
-                     5, 3),
-       SENSOR_ATTR_2(temp7_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
-                     6, 3),
-       SENSOR_ATTR_2(temp8_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
-                     7, 3),
-       SENSOR_ATTR_2(temp9_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
-                     8, 3),
-       SENSOR_ATTR_2(temp10_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
-                     9, 3),
-};
+       if (nr == 4 && !data->reg_temp[1][temp])        /* max */
+               return 0;
 
-static struct sensor_device_attribute sda_temp_offset[] = {
-       SENSOR_ATTR(temp1_offset, S_IRUGO | S_IWUSR, show_temp_offset,
-                   store_temp_offset, 0),
-       SENSOR_ATTR(temp2_offset, S_IRUGO | S_IWUSR, show_temp_offset,
-                   store_temp_offset, 1),
-       SENSOR_ATTR(temp3_offset, S_IRUGO | S_IWUSR, show_temp_offset,
-                   store_temp_offset, 2),
-       SENSOR_ATTR(temp4_offset, S_IRUGO | S_IWUSR, show_temp_offset,
-                   store_temp_offset, 3),
-       SENSOR_ATTR(temp5_offset, S_IRUGO | S_IWUSR, show_temp_offset,
-                   store_temp_offset, 4),
-       SENSOR_ATTR(temp6_offset, S_IRUGO | S_IWUSR, show_temp_offset,
-                   store_temp_offset, 5),
-};
+       if (nr == 5 && !data->reg_temp[2][temp])        /* max_hyst */
+               return 0;
+
+       if (nr == 6 && !data->reg_temp[3][temp])        /* crit */
+               return 0;
+
+       if (nr == 7 && !data->reg_temp[4][temp])        /* lcrit */
+               return 0;
+
+       /* offset and type only apply to fixed sensors */
+       if (nr > 7 && !(data->have_temp_fixed & (1 << temp)))
+               return 0;
 
-static struct sensor_device_attribute sda_temp_type[] = {
-       SENSOR_ATTR(temp1_type, S_IRUGO | S_IWUSR, show_temp_type,
-                   store_temp_type, 0),
-       SENSOR_ATTR(temp2_type, S_IRUGO | S_IWUSR, show_temp_type,
-                   store_temp_type, 1),
-       SENSOR_ATTR(temp3_type, S_IRUGO | S_IWUSR, show_temp_type,
-                   store_temp_type, 2),
-       SENSOR_ATTR(temp4_type, S_IRUGO | S_IWUSR, show_temp_type,
-                   store_temp_type, 3),
-       SENSOR_ATTR(temp5_type, S_IRUGO | S_IWUSR, show_temp_type,
-                   store_temp_type, 4),
-       SENSOR_ATTR(temp6_type, S_IRUGO | S_IWUSR, show_temp_type,
-                   store_temp_type, 5),
+       return attr->mode;
+}
+
+SENSOR_TEMPLATE_2(temp_input, "temp%d_input", S_IRUGO, show_temp, NULL, 0, 0);
+SENSOR_TEMPLATE(temp_label, "temp%d_label", S_IRUGO, show_temp_label, NULL, 0);
+SENSOR_TEMPLATE_2(temp_max, "temp%d_max", S_IRUGO | S_IWUSR, show_temp,
+                 store_temp, 0, 1);
+SENSOR_TEMPLATE_2(temp_max_hyst, "temp%d_max_hyst", S_IRUGO | S_IWUSR,
+                 show_temp, store_temp, 0, 2);
+SENSOR_TEMPLATE_2(temp_crit, "temp%d_crit", S_IRUGO | S_IWUSR, show_temp,
+                 store_temp, 0, 3);
+SENSOR_TEMPLATE_2(temp_lcrit, "temp%d_lcrit", S_IRUGO | S_IWUSR, show_temp,
+                 store_temp, 0, 4);
+SENSOR_TEMPLATE(temp_offset, "temp%d_offset", S_IRUGO | S_IWUSR,
+               show_temp_offset, store_temp_offset, 0);
+SENSOR_TEMPLATE(temp_type, "temp%d_type", S_IRUGO | S_IWUSR, show_temp_type,
+               store_temp_type, 0);
+SENSOR_TEMPLATE(temp_alarm, "temp%d_alarm", S_IRUGO, show_temp_alarm, NULL, 0);
+SENSOR_TEMPLATE(temp_beep, "temp%d_beep", S_IRUGO | S_IWUSR, show_temp_beep,
+               store_temp_beep, 0);
+
+/*
+ * nct6775_temp_is_visible uses the index into the following array
+ * to determine if attributes should be created or not.
+ * Any change in order or content must be matched.
+ */
+static struct sensor_device_template *nct6775_attributes_temp_template[] = {
+       &sensor_dev_template_temp_input,
+       &sensor_dev_template_temp_label,
+       &sensor_dev_template_temp_alarm,        /* 2 */
+       &sensor_dev_template_temp_beep,         /* 3 */
+       &sensor_dev_template_temp_max,          /* 4 */
+       &sensor_dev_template_temp_max_hyst,     /* 5 */
+       &sensor_dev_template_temp_crit,         /* 6 */
+       &sensor_dev_template_temp_lcrit,        /* 7 */
+       &sensor_dev_template_temp_offset,       /* 8 */
+       &sensor_dev_template_temp_type,         /* 9 */
+       NULL
 };
 
-static struct sensor_device_attribute sda_temp_alarm[] = {
-       SENSOR_ATTR(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0),
-       SENSOR_ATTR(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 1),
-       SENSOR_ATTR(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 2),
-       SENSOR_ATTR(temp4_alarm, S_IRUGO, show_temp_alarm, NULL, 3),
-       SENSOR_ATTR(temp5_alarm, S_IRUGO, show_temp_alarm, NULL, 4),
-       SENSOR_ATTR(temp6_alarm, S_IRUGO, show_temp_alarm, NULL, 5),
-       SENSOR_ATTR(temp7_alarm, S_IRUGO, show_temp_alarm, NULL, 6),
-       SENSOR_ATTR(temp8_alarm, S_IRUGO, show_temp_alarm, NULL, 7),
-       SENSOR_ATTR(temp9_alarm, S_IRUGO, show_temp_alarm, NULL, 8),
-       SENSOR_ATTR(temp10_alarm, S_IRUGO, show_temp_alarm, NULL, 9),
+static struct sensor_template_group nct6775_temp_template_group = {
+       .templates = nct6775_attributes_temp_template,
+       .is_visible = nct6775_temp_is_visible,
+       .base = 1,
 };
 
 static ssize_t
@@ -2422,77 +2625,19 @@ store_speed_tolerance(struct device *dev, struct device_attribute *attr,
        return count;
 }
 
-static SENSOR_DEVICE_ATTR_2(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 0);
-static SENSOR_DEVICE_ATTR_2(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1, 0);
-static SENSOR_DEVICE_ATTR_2(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2, 0);
-static SENSOR_DEVICE_ATTR_2(pwm4, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3, 0);
-static SENSOR_DEVICE_ATTR_2(pwm5, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 4, 0);
-
-static SENSOR_DEVICE_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
-                         store_pwm_mode, 0);
-static SENSOR_DEVICE_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
-                         store_pwm_mode, 1);
-static SENSOR_DEVICE_ATTR(pwm3_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
-                         store_pwm_mode, 2);
-static SENSOR_DEVICE_ATTR(pwm4_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
-                         store_pwm_mode, 3);
-static SENSOR_DEVICE_ATTR(pwm5_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
-                         store_pwm_mode, 4);
-
-static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
-                         store_pwm_enable, 0);
-static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
-                         store_pwm_enable, 1);
-static SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
-                         store_pwm_enable, 2);
-static SENSOR_DEVICE_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
-                         store_pwm_enable, 3);
-static SENSOR_DEVICE_ATTR(pwm5_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
-                         store_pwm_enable, 4);
-
-static SENSOR_DEVICE_ATTR(pwm1_temp_sel, S_IWUSR | S_IRUGO,
-                           show_pwm_temp_sel, store_pwm_temp_sel, 0);
-static SENSOR_DEVICE_ATTR(pwm2_temp_sel, S_IWUSR | S_IRUGO,
-                           show_pwm_temp_sel, store_pwm_temp_sel, 1);
-static SENSOR_DEVICE_ATTR(pwm3_temp_sel, S_IWUSR | S_IRUGO,
-                           show_pwm_temp_sel, store_pwm_temp_sel, 2);
-static SENSOR_DEVICE_ATTR(pwm4_temp_sel, S_IWUSR | S_IRUGO,
-                           show_pwm_temp_sel, store_pwm_temp_sel, 3);
-static SENSOR_DEVICE_ATTR(pwm5_temp_sel, S_IWUSR | S_IRUGO,
-                           show_pwm_temp_sel, store_pwm_temp_sel, 4);
-
-static SENSOR_DEVICE_ATTR(pwm1_target_temp, S_IWUSR | S_IRUGO, show_target_temp,
-                         store_target_temp, 0);
-static SENSOR_DEVICE_ATTR(pwm2_target_temp, S_IWUSR | S_IRUGO, show_target_temp,
-                         store_target_temp, 1);
-static SENSOR_DEVICE_ATTR(pwm3_target_temp, S_IWUSR | S_IRUGO, show_target_temp,
-                         store_target_temp, 2);
-static SENSOR_DEVICE_ATTR(pwm4_target_temp, S_IWUSR | S_IRUGO, show_target_temp,
-                         store_target_temp, 3);
-static SENSOR_DEVICE_ATTR(pwm5_target_temp, S_IWUSR | S_IRUGO, show_target_temp,
-                         store_target_temp, 4);
-
-static SENSOR_DEVICE_ATTR(fan1_target, S_IWUSR | S_IRUGO, show_target_speed,
-                         store_target_speed, 0);
-static SENSOR_DEVICE_ATTR(fan2_target, S_IWUSR | S_IRUGO, show_target_speed,
-                         store_target_speed, 1);
-static SENSOR_DEVICE_ATTR(fan3_target, S_IWUSR | S_IRUGO, show_target_speed,
-                         store_target_speed, 2);
-static SENSOR_DEVICE_ATTR(fan4_target, S_IWUSR | S_IRUGO, show_target_speed,
-                         store_target_speed, 3);
-static SENSOR_DEVICE_ATTR(fan5_target, S_IWUSR | S_IRUGO, show_target_speed,
-                         store_target_speed, 4);
-
-static SENSOR_DEVICE_ATTR(fan1_tolerance, S_IWUSR | S_IRUGO,
-                           show_speed_tolerance, store_speed_tolerance, 0);
-static SENSOR_DEVICE_ATTR(fan2_tolerance, S_IWUSR | S_IRUGO,
-                           show_speed_tolerance, store_speed_tolerance, 1);
-static SENSOR_DEVICE_ATTR(fan3_tolerance, S_IWUSR | S_IRUGO,
-                           show_speed_tolerance, store_speed_tolerance, 2);
-static SENSOR_DEVICE_ATTR(fan4_tolerance, S_IWUSR | S_IRUGO,
-                           show_speed_tolerance, store_speed_tolerance, 3);
-static SENSOR_DEVICE_ATTR(fan5_tolerance, S_IWUSR | S_IRUGO,
-                           show_speed_tolerance, store_speed_tolerance, 4);
+SENSOR_TEMPLATE_2(pwm, "pwm%d", S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 0);
+SENSOR_TEMPLATE(pwm_mode, "pwm%d_mode", S_IWUSR | S_IRUGO, show_pwm_mode,
+               store_pwm_mode, 0);
+SENSOR_TEMPLATE(pwm_enable, "pwm%d_enable", S_IWUSR | S_IRUGO, show_pwm_enable,
+               store_pwm_enable, 0);
+SENSOR_TEMPLATE(pwm_temp_sel, "pwm%d_temp_sel", S_IWUSR | S_IRUGO,
+               show_pwm_temp_sel, store_pwm_temp_sel, 0);
+SENSOR_TEMPLATE(pwm_target_temp, "pwm%d_target_temp", S_IWUSR | S_IRUGO,
+               show_target_temp, store_target_temp, 0);
+SENSOR_TEMPLATE(fan_target, "fan%d_target", S_IWUSR | S_IRUGO,
+               show_target_speed, store_target_speed, 0);
+SENSOR_TEMPLATE(fan_tolerance, "fan%d_tolerance", S_IWUSR | S_IRUGO,
+               show_speed_tolerance, store_speed_tolerance, 0);
 
 /* Smart Fan registers */
 
@@ -2531,79 +2676,18 @@ store_weight_temp(struct device *dev, struct device_attribute *attr,
        return count;
 }
 
-static SENSOR_DEVICE_ATTR(pwm1_weight_temp_sel, S_IWUSR | S_IRUGO,
-                           show_pwm_weight_temp_sel, store_pwm_weight_temp_sel,
-                           0);
-static SENSOR_DEVICE_ATTR(pwm2_weight_temp_sel, S_IWUSR | S_IRUGO,
-                           show_pwm_weight_temp_sel, store_pwm_weight_temp_sel,
-                           1);
-static SENSOR_DEVICE_ATTR(pwm3_weight_temp_sel, S_IWUSR | S_IRUGO,
-                           show_pwm_weight_temp_sel, store_pwm_weight_temp_sel,
-                           2);
-static SENSOR_DEVICE_ATTR(pwm4_weight_temp_sel, S_IWUSR | S_IRUGO,
-                           show_pwm_weight_temp_sel, store_pwm_weight_temp_sel,
-                           3);
-static SENSOR_DEVICE_ATTR(pwm5_weight_temp_sel, S_IWUSR | S_IRUGO,
-                           show_pwm_weight_temp_sel, store_pwm_weight_temp_sel,
-                           4);
-
-static SENSOR_DEVICE_ATTR_2(pwm1_weight_temp_step, S_IWUSR | S_IRUGO,
-                           show_weight_temp, store_weight_temp, 0, 0);
-static SENSOR_DEVICE_ATTR_2(pwm2_weight_temp_step, S_IWUSR | S_IRUGO,
-                           show_weight_temp, store_weight_temp, 1, 0);
-static SENSOR_DEVICE_ATTR_2(pwm3_weight_temp_step, S_IWUSR | S_IRUGO,
-                           show_weight_temp, store_weight_temp, 2, 0);
-static SENSOR_DEVICE_ATTR_2(pwm4_weight_temp_step, S_IWUSR | S_IRUGO,
-                           show_weight_temp, store_weight_temp, 3, 0);
-static SENSOR_DEVICE_ATTR_2(pwm5_weight_temp_step, S_IWUSR | S_IRUGO,
-                           show_weight_temp, store_weight_temp, 4, 0);
-
-static SENSOR_DEVICE_ATTR_2(pwm1_weight_temp_step_tol, S_IWUSR | S_IRUGO,
-                           show_weight_temp, store_weight_temp, 0, 1);
-static SENSOR_DEVICE_ATTR_2(pwm2_weight_temp_step_tol, S_IWUSR | S_IRUGO,
-                           show_weight_temp, store_weight_temp, 1, 1);
-static SENSOR_DEVICE_ATTR_2(pwm3_weight_temp_step_tol, S_IWUSR | S_IRUGO,
-                           show_weight_temp, store_weight_temp, 2, 1);
-static SENSOR_DEVICE_ATTR_2(pwm4_weight_temp_step_tol, S_IWUSR | S_IRUGO,
-                           show_weight_temp, store_weight_temp, 3, 1);
-static SENSOR_DEVICE_ATTR_2(pwm5_weight_temp_step_tol, S_IWUSR | S_IRUGO,
-                           show_weight_temp, store_weight_temp, 4, 1);
-
-static SENSOR_DEVICE_ATTR_2(pwm1_weight_temp_step_base, S_IWUSR | S_IRUGO,
-                           show_weight_temp, store_weight_temp, 0, 2);
-static SENSOR_DEVICE_ATTR_2(pwm2_weight_temp_step_base, S_IWUSR | S_IRUGO,
-                           show_weight_temp, store_weight_temp, 1, 2);
-static SENSOR_DEVICE_ATTR_2(pwm3_weight_temp_step_base, S_IWUSR | S_IRUGO,
-                           show_weight_temp, store_weight_temp, 2, 2);
-static SENSOR_DEVICE_ATTR_2(pwm4_weight_temp_step_base, S_IWUSR | S_IRUGO,
-                           show_weight_temp, store_weight_temp, 3, 2);
-static SENSOR_DEVICE_ATTR_2(pwm5_weight_temp_step_base, S_IWUSR | S_IRUGO,
-                           show_weight_temp, store_weight_temp, 4, 2);
-
-static SENSOR_DEVICE_ATTR_2(pwm1_weight_duty_step, S_IWUSR | S_IRUGO,
-                           show_pwm, store_pwm, 0, 5);
-static SENSOR_DEVICE_ATTR_2(pwm2_weight_duty_step, S_IWUSR | S_IRUGO,
-                           show_pwm, store_pwm, 1, 5);
-static SENSOR_DEVICE_ATTR_2(pwm3_weight_duty_step, S_IWUSR | S_IRUGO,
-                           show_pwm, store_pwm, 2, 5);
-static SENSOR_DEVICE_ATTR_2(pwm4_weight_duty_step, S_IWUSR | S_IRUGO,
-                           show_pwm, store_pwm, 3, 5);
-static SENSOR_DEVICE_ATTR_2(pwm5_weight_duty_step, S_IWUSR | S_IRUGO,
-                           show_pwm, store_pwm, 4, 5);
-
-/* duty_base is not supported on all chips */
-static struct sensor_device_attribute_2 sda_weight_duty_base[] = {
-       SENSOR_ATTR_2(pwm1_weight_duty_base, S_IWUSR | S_IRUGO,
-                     show_pwm, store_pwm, 0, 6),
-       SENSOR_ATTR_2(pwm2_weight_duty_base, S_IWUSR | S_IRUGO,
-                     show_pwm, store_pwm, 1, 6),
-       SENSOR_ATTR_2(pwm3_weight_duty_base, S_IWUSR | S_IRUGO,
-                     show_pwm, store_pwm, 2, 6),
-       SENSOR_ATTR_2(pwm4_weight_duty_base, S_IWUSR | S_IRUGO,
-                     show_pwm, store_pwm, 3, 6),
-       SENSOR_ATTR_2(pwm5_weight_duty_base, S_IWUSR | S_IRUGO,
-                     show_pwm, store_pwm, 4, 6),
-};
+SENSOR_TEMPLATE(pwm_weight_temp_sel, "pwm%d_weight_temp_sel", S_IWUSR | S_IRUGO,
+                 show_pwm_weight_temp_sel, store_pwm_weight_temp_sel, 0);
+SENSOR_TEMPLATE_2(pwm_weight_temp_step, "pwm%d_weight_temp_step",
+                 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 0);
+SENSOR_TEMPLATE_2(pwm_weight_temp_step_tol, "pwm%d_weight_temp_step_tol",
+                 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 1);
+SENSOR_TEMPLATE_2(pwm_weight_temp_step_base, "pwm%d_weight_temp_step_base",
+                 S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 2);
+SENSOR_TEMPLATE_2(pwm_weight_duty_step, "pwm%d_weight_duty_step",
+                 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 5);
+SENSOR_TEMPLATE_2(pwm_weight_duty_base, "pwm%d_weight_duty_base",
+                 S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 6);
 
 static ssize_t
 show_fan_time(struct device *dev, struct device_attribute *attr, char *buf)
@@ -2651,227 +2735,6 @@ show_name(struct device *dev, struct device_attribute *attr, char *buf)
 
 static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
 
-static SENSOR_DEVICE_ATTR_2(pwm1_stop_time, S_IWUSR | S_IRUGO, show_fan_time,
-                           store_fan_time, 0, 0);
-static SENSOR_DEVICE_ATTR_2(pwm2_stop_time, S_IWUSR | S_IRUGO, show_fan_time,
-                           store_fan_time, 1, 0);
-static SENSOR_DEVICE_ATTR_2(pwm3_stop_time, S_IWUSR | S_IRUGO, show_fan_time,
-                           store_fan_time, 2, 0);
-static SENSOR_DEVICE_ATTR_2(pwm4_stop_time, S_IWUSR | S_IRUGO, show_fan_time,
-                           store_fan_time, 3, 0);
-static SENSOR_DEVICE_ATTR_2(pwm5_stop_time, S_IWUSR | S_IRUGO, show_fan_time,
-                           store_fan_time, 4, 0);
-
-static SENSOR_DEVICE_ATTR_2(pwm1_step_up_time, S_IWUSR | S_IRUGO, show_fan_time,
-                           store_fan_time, 0, 1);
-static SENSOR_DEVICE_ATTR_2(pwm2_step_up_time, S_IWUSR | S_IRUGO, show_fan_time,
-                           store_fan_time, 1, 1);
-static SENSOR_DEVICE_ATTR_2(pwm3_step_up_time, S_IWUSR | S_IRUGO, show_fan_time,
-                           store_fan_time, 2, 1);
-static SENSOR_DEVICE_ATTR_2(pwm4_step_up_time, S_IWUSR | S_IRUGO, show_fan_time,
-                           store_fan_time, 3, 1);
-static SENSOR_DEVICE_ATTR_2(pwm5_step_up_time, S_IWUSR | S_IRUGO, show_fan_time,
-                           store_fan_time, 4, 1);
-
-static SENSOR_DEVICE_ATTR_2(pwm1_step_down_time, S_IWUSR | S_IRUGO,
-                           show_fan_time, store_fan_time, 0, 2);
-static SENSOR_DEVICE_ATTR_2(pwm2_step_down_time, S_IWUSR | S_IRUGO,
-                           show_fan_time, store_fan_time, 1, 2);
-static SENSOR_DEVICE_ATTR_2(pwm3_step_down_time, S_IWUSR | S_IRUGO,
-                           show_fan_time, store_fan_time, 2, 2);
-static SENSOR_DEVICE_ATTR_2(pwm4_step_down_time, S_IWUSR | S_IRUGO,
-                           show_fan_time, store_fan_time, 3, 2);
-static SENSOR_DEVICE_ATTR_2(pwm5_step_down_time, S_IWUSR | S_IRUGO,
-                           show_fan_time, store_fan_time, 4, 2);
-
-static SENSOR_DEVICE_ATTR_2(pwm1_start, S_IWUSR | S_IRUGO, show_pwm,
-                           store_pwm, 0, 1);
-static SENSOR_DEVICE_ATTR_2(pwm2_start, S_IWUSR | S_IRUGO, show_pwm,
-                           store_pwm, 1, 1);
-static SENSOR_DEVICE_ATTR_2(pwm3_start, S_IWUSR | S_IRUGO, show_pwm,
-                           store_pwm, 2, 1);
-static SENSOR_DEVICE_ATTR_2(pwm4_start, S_IWUSR | S_IRUGO, show_pwm,
-                           store_pwm, 3, 1);
-static SENSOR_DEVICE_ATTR_2(pwm5_start, S_IWUSR | S_IRUGO, show_pwm,
-                           store_pwm, 4, 1);
-
-static SENSOR_DEVICE_ATTR_2(pwm1_floor, S_IWUSR | S_IRUGO, show_pwm,
-                           store_pwm, 0, 2);
-static SENSOR_DEVICE_ATTR_2(pwm2_floor, S_IWUSR | S_IRUGO, show_pwm,
-                           store_pwm, 1, 2);
-static SENSOR_DEVICE_ATTR_2(pwm3_floor, S_IWUSR | S_IRUGO, show_pwm,
-                           store_pwm, 2, 2);
-static SENSOR_DEVICE_ATTR_2(pwm4_floor, S_IWUSR | S_IRUGO, show_pwm,
-                           store_pwm, 3, 2);
-static SENSOR_DEVICE_ATTR_2(pwm5_floor, S_IWUSR | S_IRUGO, show_pwm,
-                           store_pwm, 4, 2);
-
-static SENSOR_DEVICE_ATTR_2(pwm1_temp_tolerance, S_IWUSR | S_IRUGO,
-                           show_temp_tolerance, store_temp_tolerance, 0, 0);
-static SENSOR_DEVICE_ATTR_2(pwm2_temp_tolerance, S_IWUSR | S_IRUGO,
-                           show_temp_tolerance, store_temp_tolerance, 1, 0);
-static SENSOR_DEVICE_ATTR_2(pwm3_temp_tolerance, S_IWUSR | S_IRUGO,
-                           show_temp_tolerance, store_temp_tolerance, 2, 0);
-static SENSOR_DEVICE_ATTR_2(pwm4_temp_tolerance, S_IWUSR | S_IRUGO,
-                           show_temp_tolerance, store_temp_tolerance, 3, 0);
-static SENSOR_DEVICE_ATTR_2(pwm5_temp_tolerance, S_IWUSR | S_IRUGO,
-                           show_temp_tolerance, store_temp_tolerance, 4, 0);
-
-static SENSOR_DEVICE_ATTR_2(pwm1_crit_temp_tolerance, S_IWUSR | S_IRUGO,
-                           show_temp_tolerance, store_temp_tolerance, 0, 1);
-static SENSOR_DEVICE_ATTR_2(pwm2_crit_temp_tolerance, S_IWUSR | S_IRUGO,
-                           show_temp_tolerance, store_temp_tolerance, 1, 1);
-static SENSOR_DEVICE_ATTR_2(pwm3_crit_temp_tolerance, S_IWUSR | S_IRUGO,
-                           show_temp_tolerance, store_temp_tolerance, 2, 1);
-static SENSOR_DEVICE_ATTR_2(pwm4_crit_temp_tolerance, S_IWUSR | S_IRUGO,
-                           show_temp_tolerance, store_temp_tolerance, 3, 1);
-static SENSOR_DEVICE_ATTR_2(pwm5_crit_temp_tolerance, S_IWUSR | S_IRUGO,
-                           show_temp_tolerance, store_temp_tolerance, 4, 1);
-
-/* pwm_max is not supported on all chips */
-static struct sensor_device_attribute_2 sda_pwm_max[] = {
-       SENSOR_ATTR_2(pwm1_max, S_IWUSR | S_IRUGO, show_pwm, store_pwm,
-                     0, 3),
-       SENSOR_ATTR_2(pwm2_max, S_IWUSR | S_IRUGO, show_pwm, store_pwm,
-                     1, 3),
-       SENSOR_ATTR_2(pwm3_max, S_IWUSR | S_IRUGO, show_pwm, store_pwm,
-                     2, 3),
-       SENSOR_ATTR_2(pwm4_max, S_IWUSR | S_IRUGO, show_pwm, store_pwm,
-                     3, 3),
-       SENSOR_ATTR_2(pwm5_max, S_IWUSR | S_IRUGO, show_pwm, store_pwm,
-                     4, 3),
-};
-
-/* pwm_step is not supported on all chips */
-static struct sensor_device_attribute_2 sda_pwm_step[] = {
-       SENSOR_ATTR_2(pwm1_step, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 4),
-       SENSOR_ATTR_2(pwm2_step, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1, 4),
-       SENSOR_ATTR_2(pwm3_step, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2, 4),
-       SENSOR_ATTR_2(pwm4_step, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3, 4),
-       SENSOR_ATTR_2(pwm5_step, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 4, 4),
-};
-
-static struct attribute *nct6775_attributes_pwm[5][20] = {
-       {
-               &sensor_dev_attr_pwm1.dev_attr.attr,
-               &sensor_dev_attr_pwm1_mode.dev_attr.attr,
-               &sensor_dev_attr_pwm1_enable.dev_attr.attr,
-               &sensor_dev_attr_pwm1_temp_sel.dev_attr.attr,
-               &sensor_dev_attr_pwm1_temp_tolerance.dev_attr.attr,
-               &sensor_dev_attr_pwm1_crit_temp_tolerance.dev_attr.attr,
-               &sensor_dev_attr_pwm1_target_temp.dev_attr.attr,
-               &sensor_dev_attr_fan1_target.dev_attr.attr,
-               &sensor_dev_attr_fan1_tolerance.dev_attr.attr,
-               &sensor_dev_attr_pwm1_stop_time.dev_attr.attr,
-               &sensor_dev_attr_pwm1_step_up_time.dev_attr.attr,
-               &sensor_dev_attr_pwm1_step_down_time.dev_attr.attr,
-               &sensor_dev_attr_pwm1_start.dev_attr.attr,
-               &sensor_dev_attr_pwm1_floor.dev_attr.attr,
-               &sensor_dev_attr_pwm1_weight_temp_sel.dev_attr.attr,
-               &sensor_dev_attr_pwm1_weight_temp_step.dev_attr.attr,
-               &sensor_dev_attr_pwm1_weight_temp_step_tol.dev_attr.attr,
-               &sensor_dev_attr_pwm1_weight_temp_step_base.dev_attr.attr,
-               &sensor_dev_attr_pwm1_weight_duty_step.dev_attr.attr,
-               NULL
-       },
-       {
-               &sensor_dev_attr_pwm2.dev_attr.attr,
-               &sensor_dev_attr_pwm2_mode.dev_attr.attr,
-               &sensor_dev_attr_pwm2_enable.dev_attr.attr,
-               &sensor_dev_attr_pwm2_temp_sel.dev_attr.attr,
-               &sensor_dev_attr_pwm2_temp_tolerance.dev_attr.attr,
-               &sensor_dev_attr_pwm2_crit_temp_tolerance.dev_attr.attr,
-               &sensor_dev_attr_pwm2_target_temp.dev_attr.attr,
-               &sensor_dev_attr_fan2_target.dev_attr.attr,
-               &sensor_dev_attr_fan2_tolerance.dev_attr.attr,
-               &sensor_dev_attr_pwm2_stop_time.dev_attr.attr,
-               &sensor_dev_attr_pwm2_step_up_time.dev_attr.attr,
-               &sensor_dev_attr_pwm2_step_down_time.dev_attr.attr,
-               &sensor_dev_attr_pwm2_start.dev_attr.attr,
-               &sensor_dev_attr_pwm2_floor.dev_attr.attr,
-               &sensor_dev_attr_pwm2_weight_temp_sel.dev_attr.attr,
-               &sensor_dev_attr_pwm2_weight_temp_step.dev_attr.attr,
-               &sensor_dev_attr_pwm2_weight_temp_step_tol.dev_attr.attr,
-               &sensor_dev_attr_pwm2_weight_temp_step_base.dev_attr.attr,
-               &sensor_dev_attr_pwm2_weight_duty_step.dev_attr.attr,
-               NULL
-       },
-       {
-               &sensor_dev_attr_pwm3.dev_attr.attr,
-               &sensor_dev_attr_pwm3_mode.dev_attr.attr,
-               &sensor_dev_attr_pwm3_enable.dev_attr.attr,
-               &sensor_dev_attr_pwm3_temp_sel.dev_attr.attr,
-               &sensor_dev_attr_pwm3_temp_tolerance.dev_attr.attr,
-               &sensor_dev_attr_pwm3_crit_temp_tolerance.dev_attr.attr,
-               &sensor_dev_attr_pwm3_target_temp.dev_attr.attr,
-               &sensor_dev_attr_fan3_target.dev_attr.attr,
-               &sensor_dev_attr_fan3_tolerance.dev_attr.attr,
-               &sensor_dev_attr_pwm3_stop_time.dev_attr.attr,
-               &sensor_dev_attr_pwm3_step_up_time.dev_attr.attr,
-               &sensor_dev_attr_pwm3_step_down_time.dev_attr.attr,
-               &sensor_dev_attr_pwm3_start.dev_attr.attr,
-               &sensor_dev_attr_pwm3_floor.dev_attr.attr,
-               &sensor_dev_attr_pwm3_weight_temp_sel.dev_attr.attr,
-               &sensor_dev_attr_pwm3_weight_temp_step.dev_attr.attr,
-               &sensor_dev_attr_pwm3_weight_temp_step_tol.dev_attr.attr,
-               &sensor_dev_attr_pwm3_weight_temp_step_base.dev_attr.attr,
-               &sensor_dev_attr_pwm3_weight_duty_step.dev_attr.attr,
-               NULL
-       },
-       {
-               &sensor_dev_attr_pwm4.dev_attr.attr,
-               &sensor_dev_attr_pwm4_mode.dev_attr.attr,
-               &sensor_dev_attr_pwm4_enable.dev_attr.attr,
-               &sensor_dev_attr_pwm4_temp_sel.dev_attr.attr,
-               &sensor_dev_attr_pwm4_temp_tolerance.dev_attr.attr,
-               &sensor_dev_attr_pwm4_crit_temp_tolerance.dev_attr.attr,
-               &sensor_dev_attr_pwm4_target_temp.dev_attr.attr,
-               &sensor_dev_attr_fan4_target.dev_attr.attr,
-               &sensor_dev_attr_fan4_tolerance.dev_attr.attr,
-               &sensor_dev_attr_pwm4_stop_time.dev_attr.attr,
-               &sensor_dev_attr_pwm4_step_up_time.dev_attr.attr,
-               &sensor_dev_attr_pwm4_step_down_time.dev_attr.attr,
-               &sensor_dev_attr_pwm4_start.dev_attr.attr,
-               &sensor_dev_attr_pwm4_floor.dev_attr.attr,
-               &sensor_dev_attr_pwm4_weight_temp_sel.dev_attr.attr,
-               &sensor_dev_attr_pwm4_weight_temp_step.dev_attr.attr,
-               &sensor_dev_attr_pwm4_weight_temp_step_tol.dev_attr.attr,
-               &sensor_dev_attr_pwm4_weight_temp_step_base.dev_attr.attr,
-               &sensor_dev_attr_pwm4_weight_duty_step.dev_attr.attr,
-               NULL
-       },
-       {
-               &sensor_dev_attr_pwm5.dev_attr.attr,
-               &sensor_dev_attr_pwm5_mode.dev_attr.attr,
-               &sensor_dev_attr_pwm5_enable.dev_attr.attr,
-               &sensor_dev_attr_pwm5_temp_sel.dev_attr.attr,
-               &sensor_dev_attr_pwm5_temp_tolerance.dev_attr.attr,
-               &sensor_dev_attr_pwm5_crit_temp_tolerance.dev_attr.attr,
-               &sensor_dev_attr_pwm5_target_temp.dev_attr.attr,
-               &sensor_dev_attr_fan5_target.dev_attr.attr,
-               &sensor_dev_attr_fan5_tolerance.dev_attr.attr,
-               &sensor_dev_attr_pwm5_stop_time.dev_attr.attr,
-               &sensor_dev_attr_pwm5_step_up_time.dev_attr.attr,
-               &sensor_dev_attr_pwm5_step_down_time.dev_attr.attr,
-               &sensor_dev_attr_pwm5_start.dev_attr.attr,
-               &sensor_dev_attr_pwm5_floor.dev_attr.attr,
-               &sensor_dev_attr_pwm5_weight_temp_sel.dev_attr.attr,
-               &sensor_dev_attr_pwm5_weight_temp_step.dev_attr.attr,
-               &sensor_dev_attr_pwm5_weight_temp_step_tol.dev_attr.attr,
-               &sensor_dev_attr_pwm5_weight_temp_step_base.dev_attr.attr,
-               &sensor_dev_attr_pwm5_weight_duty_step.dev_attr.attr,
-               NULL
-       },
-};
-
-static const struct attribute_group nct6775_group_pwm[5] = {
-       { .attrs = nct6775_attributes_pwm[0] },
-       { .attrs = nct6775_attributes_pwm[1] },
-       { .attrs = nct6775_attributes_pwm[2] },
-       { .attrs = nct6775_attributes_pwm[3] },
-       { .attrs = nct6775_attributes_pwm[4] },
-};
-
 static ssize_t
 show_auto_pwm(struct device *dev, struct device_attribute *attr, char *buf)
 {
@@ -2927,17 +2790,19 @@ store_auto_pwm(struct device *dev, struct device_attribute *attr,
                        break;
                case nct6776:
                        break; /* always enabled, nothing to do */
+               case nct6106:
                case nct6779:
-                       nct6775_write_value(data, NCT6779_REG_CRITICAL_PWM[nr],
+               case nct6791:
+                       nct6775_write_value(data, data->REG_CRITICAL_PWM[nr],
                                            val);
                        reg = nct6775_read_value(data,
-                                       NCT6779_REG_CRITICAL_PWM_ENABLE[nr]);
+                                       data->REG_CRITICAL_PWM_ENABLE[nr]);
                        if (val == 255)
-                               reg &= ~0x01;
+                               reg &= ~data->CRITICAL_PWM_ENABLE_MASK;
                        else
-                               reg |= 0x01;
+                               reg |= data->CRITICAL_PWM_ENABLE_MASK;
                        nct6775_write_value(data,
-                                           NCT6779_REG_CRITICAL_PWM_ENABLE[nr],
+                                           data->REG_CRITICAL_PWM_ENABLE[nr],
                                            reg);
                        break;
                }
@@ -2992,155 +2857,140 @@ store_auto_temp(struct device *dev, struct device_attribute *attr,
        return count;
 }
 
+static umode_t nct6775_pwm_is_visible(struct kobject *kobj,
+                                     struct attribute *attr, int index)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct nct6775_data *data = dev_get_drvdata(dev);
+       int pwm = index / 36;   /* pwm index */
+       int nr = index % 36;    /* attribute index */
+
+       if (!(data->has_pwm & (1 << pwm)))
+               return 0;
+
+       if (nr == 19 && data->REG_PWM[3] == NULL) /* pwm_max */
+               return 0;
+       if (nr == 20 && data->REG_PWM[4] == NULL) /* pwm_step */
+               return 0;
+       if (nr == 21 && data->REG_PWM[6] == NULL) /* weight_duty_base */
+               return 0;
+
+       if (nr >= 22 && nr <= 35) {             /* auto point */
+               int api = (nr - 22) / 2;        /* auto point index */
+
+               if (api > data->auto_pwm_num)
+                       return 0;
+       }
+       return attr->mode;
+}
+
+SENSOR_TEMPLATE_2(pwm_stop_time, "pwm%d_stop_time", S_IWUSR | S_IRUGO,
+                 show_fan_time, store_fan_time, 0, 0);
+SENSOR_TEMPLATE_2(pwm_step_up_time, "pwm%d_step_up_time", S_IWUSR | S_IRUGO,
+                 show_fan_time, store_fan_time, 0, 1);
+SENSOR_TEMPLATE_2(pwm_step_down_time, "pwm%d_step_down_time", S_IWUSR | S_IRUGO,
+                 show_fan_time, store_fan_time, 0, 2);
+SENSOR_TEMPLATE_2(pwm_start, "pwm%d_start", S_IWUSR | S_IRUGO, show_pwm,
+                 store_pwm, 0, 1);
+SENSOR_TEMPLATE_2(pwm_floor, "pwm%d_floor", S_IWUSR | S_IRUGO, show_pwm,
+                 store_pwm, 0, 2);
+SENSOR_TEMPLATE_2(pwm_temp_tolerance, "pwm%d_temp_tolerance", S_IWUSR | S_IRUGO,
+                 show_temp_tolerance, store_temp_tolerance, 0, 0);
+SENSOR_TEMPLATE_2(pwm_crit_temp_tolerance, "pwm%d_crit_temp_tolerance",
+                 S_IWUSR | S_IRUGO, show_temp_tolerance, store_temp_tolerance,
+                 0, 1);
+
+SENSOR_TEMPLATE_2(pwm_max, "pwm%d_max", S_IWUSR | S_IRUGO, show_pwm, store_pwm,
+                 0, 3);
+
+SENSOR_TEMPLATE_2(pwm_step, "pwm%d_step", S_IWUSR | S_IRUGO, show_pwm,
+                 store_pwm, 0, 4);
+
+SENSOR_TEMPLATE_2(pwm_auto_point1_pwm, "pwm%d_auto_point1_pwm",
+                 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 0);
+SENSOR_TEMPLATE_2(pwm_auto_point1_temp, "pwm%d_auto_point1_temp",
+                 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 0);
+
+SENSOR_TEMPLATE_2(pwm_auto_point2_pwm, "pwm%d_auto_point2_pwm",
+                 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 1);
+SENSOR_TEMPLATE_2(pwm_auto_point2_temp, "pwm%d_auto_point2_temp",
+                 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 1);
+
+SENSOR_TEMPLATE_2(pwm_auto_point3_pwm, "pwm%d_auto_point3_pwm",
+                 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 2);
+SENSOR_TEMPLATE_2(pwm_auto_point3_temp, "pwm%d_auto_point3_temp",
+                 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 2);
+
+SENSOR_TEMPLATE_2(pwm_auto_point4_pwm, "pwm%d_auto_point4_pwm",
+                 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 3);
+SENSOR_TEMPLATE_2(pwm_auto_point4_temp, "pwm%d_auto_point4_temp",
+                 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 3);
+
+SENSOR_TEMPLATE_2(pwm_auto_point5_pwm, "pwm%d_auto_point5_pwm",
+                 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 4);
+SENSOR_TEMPLATE_2(pwm_auto_point5_temp, "pwm%d_auto_point5_temp",
+                 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 4);
+
+SENSOR_TEMPLATE_2(pwm_auto_point6_pwm, "pwm%d_auto_point6_pwm",
+                 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 5);
+SENSOR_TEMPLATE_2(pwm_auto_point6_temp, "pwm%d_auto_point6_temp",
+                 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 5);
+
+SENSOR_TEMPLATE_2(pwm_auto_point7_pwm, "pwm%d_auto_point7_pwm",
+                 S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 6);
+SENSOR_TEMPLATE_2(pwm_auto_point7_temp, "pwm%d_auto_point7_temp",
+                 S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 6);
+
 /*
- * The number of auto-point trip points is chip dependent.
- * Need to check support while generating/removing attribute files.
+ * nct6775_pwm_is_visible uses the index into the following array
+ * to determine if attributes should be created or not.
+ * Any change in order or content must be matched.
  */
-static struct sensor_device_attribute_2 sda_auto_pwm_arrays[] = {
-       SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IWUSR | S_IRUGO,
-                     show_auto_pwm, store_auto_pwm, 0, 0),
-       SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IWUSR | S_IRUGO,
-                     show_auto_temp, store_auto_temp, 0, 0),
-       SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IWUSR | S_IRUGO,
-                     show_auto_pwm, store_auto_pwm, 0, 1),
-       SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IWUSR | S_IRUGO,
-                     show_auto_temp, store_auto_temp, 0, 1),
-       SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IWUSR | S_IRUGO,
-                     show_auto_pwm, store_auto_pwm, 0, 2),
-       SENSOR_ATTR_2(pwm1_auto_point3_temp, S_IWUSR | S_IRUGO,
-                     show_auto_temp, store_auto_temp, 0, 2),
-       SENSOR_ATTR_2(pwm1_auto_point4_pwm, S_IWUSR | S_IRUGO,
-                     show_auto_pwm, store_auto_pwm, 0, 3),
-       SENSOR_ATTR_2(pwm1_auto_point4_temp, S_IWUSR | S_IRUGO,
-                     show_auto_temp, store_auto_temp, 0, 3),
-       SENSOR_ATTR_2(pwm1_auto_point5_pwm, S_IWUSR | S_IRUGO,
-                     show_auto_pwm, store_auto_pwm, 0, 4),
-       SENSOR_ATTR_2(pwm1_auto_point5_temp, S_IWUSR | S_IRUGO,
-                     show_auto_temp, store_auto_temp, 0, 4),
-       SENSOR_ATTR_2(pwm1_auto_point6_pwm, S_IWUSR | S_IRUGO,
-                     show_auto_pwm, store_auto_pwm, 0, 5),
-       SENSOR_ATTR_2(pwm1_auto_point6_temp, S_IWUSR | S_IRUGO,
-                     show_auto_temp, store_auto_temp, 0, 5),
-       SENSOR_ATTR_2(pwm1_auto_point7_pwm, S_IWUSR | S_IRUGO,
-                     show_auto_pwm, store_auto_pwm, 0, 6),
-       SENSOR_ATTR_2(pwm1_auto_point7_temp, S_IWUSR | S_IRUGO,
-                     show_auto_temp, store_auto_temp, 0, 6),
-
-       SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IWUSR | S_IRUGO,
-                     show_auto_pwm, store_auto_pwm, 1, 0),
-       SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IWUSR | S_IRUGO,
-                     show_auto_temp, store_auto_temp, 1, 0),
-       SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IWUSR | S_IRUGO,
-                     show_auto_pwm, store_auto_pwm, 1, 1),
-       SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IWUSR | S_IRUGO,
-                     show_auto_temp, store_auto_temp, 1, 1),
-       SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IWUSR | S_IRUGO,
-                     show_auto_pwm, store_auto_pwm, 1, 2),
-       SENSOR_ATTR_2(pwm2_auto_point3_temp, S_IWUSR | S_IRUGO,
-                     show_auto_temp, store_auto_temp, 1, 2),
-       SENSOR_ATTR_2(pwm2_auto_point4_pwm, S_IWUSR | S_IRUGO,
-                     show_auto_pwm, store_auto_pwm, 1, 3),
-       SENSOR_ATTR_2(pwm2_auto_point4_temp, S_IWUSR | S_IRUGO,
-                     show_auto_temp, store_auto_temp, 1, 3),
-       SENSOR_ATTR_2(pwm2_auto_point5_pwm, S_IWUSR | S_IRUGO,
-                     show_auto_pwm, store_auto_pwm, 1, 4),
-       SENSOR_ATTR_2(pwm2_auto_point5_temp, S_IWUSR | S_IRUGO,
-                     show_auto_temp, store_auto_temp, 1, 4),
-       SENSOR_ATTR_2(pwm2_auto_point6_pwm, S_IWUSR | S_IRUGO,
-                     show_auto_pwm, store_auto_pwm, 1, 5),
-       SENSOR_ATTR_2(pwm2_auto_point6_temp, S_IWUSR | S_IRUGO,
-                     show_auto_temp, store_auto_temp, 1, 5),
-       SENSOR_ATTR_2(pwm2_auto_point7_pwm, S_IWUSR | S_IRUGO,
-                     show_auto_pwm, store_auto_pwm, 1, 6),
-       SENSOR_ATTR_2(pwm2_auto_point7_temp, S_IWUSR | S_IRUGO,
-                     show_auto_temp, store_auto_temp, 1, 6),
-
-       SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IWUSR | S_IRUGO,
-                     show_auto_pwm, store_auto_pwm, 2, 0),
-       SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IWUSR | S_IRUGO,
-                     show_auto_temp, store_auto_temp, 2, 0),
-       SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IWUSR | S_IRUGO,
-                     show_auto_pwm, store_auto_pwm, 2, 1),
-       SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IWUSR | S_IRUGO,
-                     show_auto_temp, store_auto_temp, 2, 1),
-       SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IWUSR | S_IRUGO,
-                     show_auto_pwm, store_auto_pwm, 2, 2),
-       SENSOR_ATTR_2(pwm3_auto_point3_temp, S_IWUSR | S_IRUGO,
-                     show_auto_temp, store_auto_temp, 2, 2),
-       SENSOR_ATTR_2(pwm3_auto_point4_pwm, S_IWUSR | S_IRUGO,
-                     show_auto_pwm, store_auto_pwm, 2, 3),
-       SENSOR_ATTR_2(pwm3_auto_point4_temp, S_IWUSR | S_IRUGO,
-                     show_auto_temp, store_auto_temp, 2, 3),
-       SENSOR_ATTR_2(pwm3_auto_point5_pwm, S_IWUSR | S_IRUGO,
-                     show_auto_pwm, store_auto_pwm, 2, 4),
-       SENSOR_ATTR_2(pwm3_auto_point5_temp, S_IWUSR | S_IRUGO,
-                     show_auto_temp, store_auto_temp, 2, 4),
-       SENSOR_ATTR_2(pwm3_auto_point6_pwm, S_IWUSR | S_IRUGO,
-                     show_auto_pwm, store_auto_pwm, 2, 5),
-       SENSOR_ATTR_2(pwm3_auto_point6_temp, S_IWUSR | S_IRUGO,
-                     show_auto_temp, store_auto_temp, 2, 5),
-       SENSOR_ATTR_2(pwm3_auto_point7_pwm, S_IWUSR | S_IRUGO,
-                     show_auto_pwm, store_auto_pwm, 2, 6),
-       SENSOR_ATTR_2(pwm3_auto_point7_temp, S_IWUSR | S_IRUGO,
-                     show_auto_temp, store_auto_temp, 2, 6),
-
-       SENSOR_ATTR_2(pwm4_auto_point1_pwm, S_IWUSR | S_IRUGO,
-                     show_auto_pwm, store_auto_pwm, 3, 0),
-       SENSOR_ATTR_2(pwm4_auto_point1_temp, S_IWUSR | S_IRUGO,
-                     show_auto_temp, store_auto_temp, 3, 0),
-       SENSOR_ATTR_2(pwm4_auto_point2_pwm, S_IWUSR | S_IRUGO,
-                     show_auto_pwm, store_auto_pwm, 3, 1),
-       SENSOR_ATTR_2(pwm4_auto_point2_temp, S_IWUSR | S_IRUGO,
-                     show_auto_temp, store_auto_temp, 3, 1),
-       SENSOR_ATTR_2(pwm4_auto_point3_pwm, S_IWUSR | S_IRUGO,
-                     show_auto_pwm, store_auto_pwm, 3, 2),
-       SENSOR_ATTR_2(pwm4_auto_point3_temp, S_IWUSR | S_IRUGO,
-                     show_auto_temp, store_auto_temp, 3, 2),
-       SENSOR_ATTR_2(pwm4_auto_point4_pwm, S_IWUSR | S_IRUGO,
-                     show_auto_pwm, store_auto_pwm, 3, 3),
-       SENSOR_ATTR_2(pwm4_auto_point4_temp, S_IWUSR | S_IRUGO,
-                     show_auto_temp, store_auto_temp, 3, 3),
-       SENSOR_ATTR_2(pwm4_auto_point5_pwm, S_IWUSR | S_IRUGO,
-                     show_auto_pwm, store_auto_pwm, 3, 4),
-       SENSOR_ATTR_2(pwm4_auto_point5_temp, S_IWUSR | S_IRUGO,
-                     show_auto_temp, store_auto_temp, 3, 4),
-       SENSOR_ATTR_2(pwm4_auto_point6_pwm, S_IWUSR | S_IRUGO,
-                     show_auto_pwm, store_auto_pwm, 3, 5),
-       SENSOR_ATTR_2(pwm4_auto_point6_temp, S_IWUSR | S_IRUGO,
-                     show_auto_temp, store_auto_temp, 3, 5),
-       SENSOR_ATTR_2(pwm4_auto_point7_pwm, S_IWUSR | S_IRUGO,
-                     show_auto_pwm, store_auto_pwm, 3, 6),
-       SENSOR_ATTR_2(pwm4_auto_point7_temp, S_IWUSR | S_IRUGO,
-                     show_auto_temp, store_auto_temp, 3, 6),
-
-       SENSOR_ATTR_2(pwm5_auto_point1_pwm, S_IWUSR | S_IRUGO,
-                     show_auto_pwm, store_auto_pwm, 4, 0),
-       SENSOR_ATTR_2(pwm5_auto_point1_temp, S_IWUSR | S_IRUGO,
-                     show_auto_temp, store_auto_temp, 4, 0),
-       SENSOR_ATTR_2(pwm5_auto_point2_pwm, S_IWUSR | S_IRUGO,
-                     show_auto_pwm, store_auto_pwm, 4, 1),
-       SENSOR_ATTR_2(pwm5_auto_point2_temp, S_IWUSR | S_IRUGO,
-                     show_auto_temp, store_auto_temp, 4, 1),
-       SENSOR_ATTR_2(pwm5_auto_point3_pwm, S_IWUSR | S_IRUGO,
-                     show_auto_pwm, store_auto_pwm, 4, 2),
-       SENSOR_ATTR_2(pwm5_auto_point3_temp, S_IWUSR | S_IRUGO,
-                     show_auto_temp, store_auto_temp, 4, 2),
-       SENSOR_ATTR_2(pwm5_auto_point4_pwm, S_IWUSR | S_IRUGO,
-                     show_auto_pwm, store_auto_pwm, 4, 3),
-       SENSOR_ATTR_2(pwm5_auto_point4_temp, S_IWUSR | S_IRUGO,
-                     show_auto_temp, store_auto_temp, 4, 3),
-       SENSOR_ATTR_2(pwm5_auto_point5_pwm, S_IWUSR | S_IRUGO,
-                     show_auto_pwm, store_auto_pwm, 4, 4),
-       SENSOR_ATTR_2(pwm5_auto_point5_temp, S_IWUSR | S_IRUGO,
-                     show_auto_temp, store_auto_temp, 4, 4),
-       SENSOR_ATTR_2(pwm5_auto_point6_pwm, S_IWUSR | S_IRUGO,
-                     show_auto_pwm, store_auto_pwm, 4, 5),
-       SENSOR_ATTR_2(pwm5_auto_point6_temp, S_IWUSR | S_IRUGO,
-                     show_auto_temp, store_auto_temp, 4, 5),
-       SENSOR_ATTR_2(pwm5_auto_point7_pwm, S_IWUSR | S_IRUGO,
-                     show_auto_pwm, store_auto_pwm, 4, 6),
-       SENSOR_ATTR_2(pwm5_auto_point7_temp, S_IWUSR | S_IRUGO,
-                     show_auto_temp, store_auto_temp, 4, 6),
+static struct sensor_device_template *nct6775_attributes_pwm_template[] = {
+       &sensor_dev_template_pwm,
+       &sensor_dev_template_pwm_mode,
+       &sensor_dev_template_pwm_enable,
+       &sensor_dev_template_pwm_temp_sel,
+       &sensor_dev_template_pwm_temp_tolerance,
+       &sensor_dev_template_pwm_crit_temp_tolerance,
+       &sensor_dev_template_pwm_target_temp,
+       &sensor_dev_template_fan_target,
+       &sensor_dev_template_fan_tolerance,
+       &sensor_dev_template_pwm_stop_time,
+       &sensor_dev_template_pwm_step_up_time,
+       &sensor_dev_template_pwm_step_down_time,
+       &sensor_dev_template_pwm_start,
+       &sensor_dev_template_pwm_floor,
+       &sensor_dev_template_pwm_weight_temp_sel,
+       &sensor_dev_template_pwm_weight_temp_step,
+       &sensor_dev_template_pwm_weight_temp_step_tol,
+       &sensor_dev_template_pwm_weight_temp_step_base,
+       &sensor_dev_template_pwm_weight_duty_step,
+       &sensor_dev_template_pwm_max,                   /* 19 */
+       &sensor_dev_template_pwm_step,                  /* 20 */
+       &sensor_dev_template_pwm_weight_duty_base,      /* 21 */
+       &sensor_dev_template_pwm_auto_point1_pwm,       /* 22 */
+       &sensor_dev_template_pwm_auto_point1_temp,
+       &sensor_dev_template_pwm_auto_point2_pwm,
+       &sensor_dev_template_pwm_auto_point2_temp,
+       &sensor_dev_template_pwm_auto_point3_pwm,
+       &sensor_dev_template_pwm_auto_point3_temp,
+       &sensor_dev_template_pwm_auto_point4_pwm,
+       &sensor_dev_template_pwm_auto_point4_temp,
+       &sensor_dev_template_pwm_auto_point5_pwm,
+       &sensor_dev_template_pwm_auto_point5_temp,
+       &sensor_dev_template_pwm_auto_point6_pwm,
+       &sensor_dev_template_pwm_auto_point6_temp,
+       &sensor_dev_template_pwm_auto_point7_pwm,
+       &sensor_dev_template_pwm_auto_point7_temp,      /* 35 */
+
+       NULL
+};
+
+static struct sensor_template_group nct6775_pwm_template_group = {
+       .templates = nct6775_attributes_pwm_template,
+       .is_visible = nct6775_pwm_is_visible,
+       .base = 1,
 };
 
 static ssize_t
@@ -3159,7 +3009,6 @@ clear_caseopen(struct device *dev, struct device_attribute *attr,
               const char *buf, size_t count)
 {
        struct nct6775_data *data = dev_get_drvdata(dev);
-       struct nct6775_sio_data *sio_data = dev->platform_data;
        int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE;
        unsigned long val;
        u8 reg;
@@ -3175,19 +3024,19 @@ clear_caseopen(struct device *dev, struct device_attribute *attr,
         * The CR registers are the same for all chips, and not all chips
         * support clearing the caseopen status through "regular" registers.
         */
-       ret = superio_enter(sio_data->sioreg);
+       ret = superio_enter(data->sioreg);
        if (ret) {
                count = ret;
                goto error;
        }
 
-       superio_select(sio_data->sioreg, NCT6775_LD_ACPI);
-       reg = superio_inb(sio_data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
+       superio_select(data->sioreg, NCT6775_LD_ACPI);
+       reg = superio_inb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
        reg |= NCT6775_CR_CASEOPEN_CLR_MASK[nr];
-       superio_outb(sio_data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
+       superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
        reg &= ~NCT6775_CR_CASEOPEN_CLR_MASK[nr];
-       superio_outb(sio_data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
-       superio_exit(sio_data->sioreg);
+       superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
+       superio_exit(data->sioreg);
 
        data->valid = false;    /* Force cache refresh */
 error:
@@ -3195,71 +3044,79 @@ error:
        return count;
 }
 
-static struct sensor_device_attribute sda_caseopen[] = {
-       SENSOR_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm,
-                   clear_caseopen, INTRUSION_ALARM_BASE),
-       SENSOR_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_alarm,
-                   clear_caseopen, INTRUSION_ALARM_BASE + 1),
-};
-
-/*
- * Driver and device management
- */
-
-static void nct6775_device_remove_files(struct device *dev)
+static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm,
+                         clear_caseopen, INTRUSION_ALARM_BASE);
+static SENSOR_DEVICE_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_alarm,
+                         clear_caseopen, INTRUSION_ALARM_BASE + 1);
+static SENSOR_DEVICE_ATTR(intrusion0_beep, S_IWUSR | S_IRUGO, show_beep,
+                         store_beep, INTRUSION_ALARM_BASE);
+static SENSOR_DEVICE_ATTR(intrusion1_beep, S_IWUSR | S_IRUGO, show_beep,
+                         store_beep, INTRUSION_ALARM_BASE + 1);
+static SENSOR_DEVICE_ATTR(beep_enable, S_IWUSR | S_IRUGO, show_beep,
+                         store_beep, BEEP_ENABLE_BASE);
+
+static umode_t nct6775_other_is_visible(struct kobject *kobj,
+                                       struct attribute *attr, int index)
 {
-       /*
-        * some entries in the following arrays may not have been used in
-        * device_create_file(), but device_remove_file() will ignore them
-        */
-       int i;
+       struct device *dev = container_of(kobj, struct device, kobj);
        struct nct6775_data *data = dev_get_drvdata(dev);
 
-       for (i = 0; i < data->pwm_num; i++)
-               sysfs_remove_group(&dev->kobj, &nct6775_group_pwm[i]);
+       if (index == 1 && !data->have_vid)
+               return 0;
 
-       for (i = 0; i < ARRAY_SIZE(sda_pwm_max); i++)
-               device_remove_file(dev, &sda_pwm_max[i].dev_attr);
+       if (index == 2 || index == 3) {
+               if (data->ALARM_BITS[INTRUSION_ALARM_BASE + index - 2] < 0)
+                       return 0;
+       }
+
+       if (index == 4 || index == 5) {
+               if (data->BEEP_BITS[INTRUSION_ALARM_BASE + index - 4] < 0)
+                       return 0;
+       }
 
-       for (i = 0; i < ARRAY_SIZE(sda_pwm_step); i++)
-               device_remove_file(dev, &sda_pwm_step[i].dev_attr);
+       return attr->mode;
+}
 
-       for (i = 0; i < ARRAY_SIZE(sda_weight_duty_base); i++)
-               device_remove_file(dev, &sda_weight_duty_base[i].dev_attr);
+/*
+ * nct6775_other_is_visible uses the index into the following array
+ * to determine if attributes should be created or not.
+ * Any change in order or content must be matched.
+ */
+static struct attribute *nct6775_attributes_other[] = {
+       &dev_attr_name.attr,
+       &dev_attr_cpu0_vid.attr,                                /* 1 */
+       &sensor_dev_attr_intrusion0_alarm.dev_attr.attr,        /* 2 */
+       &sensor_dev_attr_intrusion1_alarm.dev_attr.attr,        /* 3 */
+       &sensor_dev_attr_intrusion0_beep.dev_attr.attr,         /* 4 */
+       &sensor_dev_attr_intrusion1_beep.dev_attr.attr,         /* 5 */
+       &sensor_dev_attr_beep_enable.dev_attr.attr,             /* 6 */
+
+       NULL
+};
 
-       for (i = 0; i < ARRAY_SIZE(sda_auto_pwm_arrays); i++)
-               device_remove_file(dev, &sda_auto_pwm_arrays[i].dev_attr);
+static const struct attribute_group nct6775_group_other = {
+       .attrs = nct6775_attributes_other,
+       .is_visible = nct6775_other_is_visible,
+};
 
-       for (i = 0; i < data->in_num; i++)
-               sysfs_remove_group(&dev->kobj, &nct6775_group_in[i]);
+/*
+ * Driver and device management
+ */
 
-       for (i = 0; i < 5; i++) {
-               device_remove_file(dev, &sda_fan_input[i].dev_attr);
-               device_remove_file(dev, &sda_fan_alarm[i].dev_attr);
-               device_remove_file(dev, &sda_fan_div[i].dev_attr);
-               device_remove_file(dev, &sda_fan_min[i].dev_attr);
-               device_remove_file(dev, &sda_fan_pulses[i].dev_attr);
-       }
-       for (i = 0; i < NUM_TEMP; i++) {
-               if (!(data->have_temp & (1 << i)))
-                       continue;
-               device_remove_file(dev, &sda_temp_input[i].dev_attr);
-               device_remove_file(dev, &sda_temp_label[i].dev_attr);
-               device_remove_file(dev, &sda_temp_max[i].dev_attr);
-               device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr);
-               device_remove_file(dev, &sda_temp_crit[i].dev_attr);
-               device_remove_file(dev, &sda_temp_alarm[i].dev_attr);
-               if (!(data->have_temp_fixed & (1 << i)))
-                       continue;
-               device_remove_file(dev, &sda_temp_type[i].dev_attr);
-               device_remove_file(dev, &sda_temp_offset[i].dev_attr);
-       }
+static void nct6775_device_remove_files(struct device *dev)
+{
+       struct nct6775_data *data = dev_get_drvdata(dev);
 
-       device_remove_file(dev, &sda_caseopen[0].dev_attr);
-       device_remove_file(dev, &sda_caseopen[1].dev_attr);
+       if (data->group_pwm)
+               sysfs_remove_group(&dev->kobj, data->group_pwm);
+       if (data->group_in)
+               sysfs_remove_group(&dev->kobj, data->group_in);
+       if (data->group_fan)
+               sysfs_remove_group(&dev->kobj, data->group_fan);
+       if (data->group_temp)
+               sysfs_remove_group(&dev->kobj, data->group_temp);
 
-       device_remove_file(dev, &dev_attr_name);
-       device_remove_file(dev, &dev_attr_cpu0_vid);
+       sysfs_remove_group(&dev->kobj, &nct6775_group_other);
 }
 
 /* Get the monitoring functions started */
@@ -3297,68 +3154,78 @@ static inline void nct6775_init_device(struct nct6775_data *data)
        for (i = 0; i < data->temp_fixed_num; i++) {
                if (!(data->have_temp_fixed & (1 << i)))
                        continue;
-               if ((tmp & (0x02 << i)))        /* diode */
-                       data->temp_type[i] = 3 - ((diode >> i) & 0x02);
+               if ((tmp & (data->DIODE_MASK << i)))    /* diode */
+                       data->temp_type[i]
+                         = 3 - ((diode >> i) & data->DIODE_MASK);
                else                            /* thermistor */
                        data->temp_type[i] = 4;
        }
 }
 
-static int
-nct6775_check_fan_inputs(const struct nct6775_sio_data *sio_data,
-                        struct nct6775_data *data)
+static void
+nct6775_check_fan_inputs(struct nct6775_data *data)
 {
+       bool fan3pin, fan4pin, fan4min, fan5pin, fan6pin;
+       bool pwm3pin, pwm4pin, pwm5pin, pwm6pin;
+       int sioreg = data->sioreg;
        int regval;
-       bool fan3pin, fan3min, fan4pin, fan4min, fan5pin;
-       bool pwm3pin, pwm4pin, pwm5pin;
-       int ret;
-
-       ret = superio_enter(sio_data->sioreg);
-       if (ret)
-               return ret;
 
        /* fan4 and fan5 share some pins with the GPIO and serial flash */
        if (data->kind == nct6775) {
-               regval = superio_inb(sio_data->sioreg, 0x2c);
+               regval = superio_inb(sioreg, 0x2c);
 
                fan3pin = regval & (1 << 6);
-               fan3min = fan3pin;
                pwm3pin = regval & (1 << 7);
 
                /* On NCT6775, fan4 shares pins with the fdc interface */
-               fan4pin = !(superio_inb(sio_data->sioreg, 0x2A) & 0x80);
-               fan4min = 0;
-               fan5pin = 0;
-               pwm4pin = 0;
-               pwm5pin = 0;
+               fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80);
+               fan4min = false;
+               fan5pin = false;
+               fan6pin = false;
+               pwm4pin = false;
+               pwm5pin = false;
+               pwm6pin = false;
        } else if (data->kind == nct6776) {
-               bool gpok = superio_inb(sio_data->sioreg, 0x27) & 0x80;
+               bool gpok = superio_inb(sioreg, 0x27) & 0x80;
 
-               superio_select(sio_data->sioreg, NCT6775_LD_HWM);
-               regval = superio_inb(sio_data->sioreg, SIO_REG_ENABLE);
+               superio_select(sioreg, NCT6775_LD_HWM);
+               regval = superio_inb(sioreg, SIO_REG_ENABLE);
 
                if (regval & 0x80)
                        fan3pin = gpok;
                else
-                       fan3pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x40);
+                       fan3pin = !(superio_inb(sioreg, 0x24) & 0x40);
 
                if (regval & 0x40)
                        fan4pin = gpok;
                else
-                       fan4pin = superio_inb(sio_data->sioreg, 0x1C) & 0x01;
+                       fan4pin = superio_inb(sioreg, 0x1C) & 0x01;
 
                if (regval & 0x20)
                        fan5pin = gpok;
                else
-                       fan5pin = superio_inb(sio_data->sioreg, 0x1C) & 0x02;
+                       fan5pin = superio_inb(sioreg, 0x1C) & 0x02;
 
                fan4min = fan4pin;
-               fan3min = fan3pin;
+               fan6pin = false;
                pwm3pin = fan3pin;
-               pwm4pin = 0;
-               pwm5pin = 0;
-       } else {        /* NCT6779D */
-               regval = superio_inb(sio_data->sioreg, 0x1c);
+               pwm4pin = false;
+               pwm5pin = false;
+               pwm6pin = false;
+       } else if (data->kind == nct6106) {
+               regval = superio_inb(sioreg, 0x24);
+               fan3pin = !(regval & 0x80);
+               pwm3pin = regval & 0x08;
+
+               fan4pin = false;
+               fan4min = false;
+               fan5pin = false;
+               fan6pin = false;
+               pwm4pin = false;
+               pwm5pin = false;
+               pwm6pin = false;
+       } else {        /* NCT6779D or NCT6791D */
+               regval = superio_inb(sioreg, 0x1c);
 
                fan3pin = !(regval & (1 << 5));
                fan4pin = !(regval & (1 << 6));
@@ -3368,22 +3235,25 @@ nct6775_check_fan_inputs(const struct nct6775_sio_data *sio_data,
                pwm4pin = !(regval & (1 << 1));
                pwm5pin = !(regval & (1 << 2));
 
-               fan3min = fan3pin;
                fan4min = fan4pin;
-       }
-
-       superio_exit(sio_data->sioreg);
 
-       data->has_fan = data->has_fan_min = 0x03; /* fan1 and fan2 */
-       data->has_fan |= fan3pin << 2;
-       data->has_fan_min |= fan3min << 2;
-
-       data->has_fan |= (fan4pin << 3) | (fan5pin << 4);
-       data->has_fan_min |= (fan4min << 3) | (fan5pin << 4);
-
-       data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) | (pwm5pin << 4);
+               if (data->kind == nct6791) {
+                       regval = superio_inb(sioreg, 0x2d);
+                       fan6pin = (regval & (1 << 1));
+                       pwm6pin = (regval & (1 << 0));
+               } else {        /* NCT6779D */
+                       fan6pin = false;
+                       pwm6pin = false;
+               }
+       }
 
-       return 0;
+       /* fan 1 and 2 (0x03) are always present */
+       data->has_fan = 0x03 | (fan3pin << 2) | (fan4pin << 3) |
+               (fan5pin << 4) | (fan6pin << 5);
+       data->has_fan_min = 0x03 | (fan3pin << 2) | (fan4min << 3) |
+               (fan5pin << 4);
+       data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) |
+               (pwm5pin << 4) | (pwm6pin << 5);
 }
 
 static void add_temp_sensors(struct nct6775_data *data, const u16 *regp,
@@ -3415,16 +3285,17 @@ static void add_temp_sensors(struct nct6775_data *data, const u16 *regp,
 static int nct6775_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct nct6775_sio_data *sio_data = dev->platform_data;
+       struct nct6775_sio_data *sio_data = dev_get_platdata(dev);
        struct nct6775_data *data;
        struct resource *res;
        int i, s, err = 0;
        int src, mask, available;
        const u16 *reg_temp, *reg_temp_over, *reg_temp_hyst, *reg_temp_config;
        const u16 *reg_temp_alternate, *reg_temp_crit;
+       const u16 *reg_temp_crit_l = NULL, *reg_temp_crit_h = NULL;
        int num_reg_temp;
-       bool have_vid = false;
        u8 cr2a;
+       struct attribute_group *group;
 
        res = platform_get_resource(pdev, IORESOURCE_IO, 0);
        if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH,
@@ -3437,6 +3308,7 @@ static int nct6775_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        data->kind = sio_data->kind;
+       data->sioreg = sio_data->sioreg;
        data->addr = res->start;
        mutex_init(&data->update_lock);
        data->name = nct6775_device_names[data->kind];
@@ -3444,6 +3316,75 @@ static int nct6775_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, data);
 
        switch (data->kind) {
+       case nct6106:
+               data->in_num = 9;
+               data->pwm_num = 3;
+               data->auto_pwm_num = 4;
+               data->temp_fixed_num = 3;
+               data->num_temp_alarms = 6;
+               data->num_temp_beeps = 6;
+
+               data->fan_from_reg = fan_from_reg13;
+               data->fan_from_reg_min = fan_from_reg13;
+
+               data->temp_label = nct6776_temp_label;
+               data->temp_label_num = ARRAY_SIZE(nct6776_temp_label);
+
+               data->REG_VBAT = NCT6106_REG_VBAT;
+               data->REG_DIODE = NCT6106_REG_DIODE;
+               data->DIODE_MASK = NCT6106_DIODE_MASK;
+               data->REG_VIN = NCT6106_REG_IN;
+               data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN;
+               data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX;
+               data->REG_TARGET = NCT6106_REG_TARGET;
+               data->REG_FAN = NCT6106_REG_FAN;
+               data->REG_FAN_MODE = NCT6106_REG_FAN_MODE;
+               data->REG_FAN_MIN = NCT6106_REG_FAN_MIN;
+               data->REG_FAN_PULSES = NCT6106_REG_FAN_PULSES;
+               data->FAN_PULSE_SHIFT = NCT6106_FAN_PULSE_SHIFT;
+               data->REG_FAN_TIME[0] = NCT6106_REG_FAN_STOP_TIME;
+               data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME;
+               data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME;
+               data->REG_PWM[0] = NCT6106_REG_PWM;
+               data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT;
+               data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT;
+               data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
+               data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
+               data->REG_PWM_READ = NCT6106_REG_PWM_READ;
+               data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
+               data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
+               data->REG_AUTO_TEMP = NCT6106_REG_AUTO_TEMP;
+               data->REG_AUTO_PWM = NCT6106_REG_AUTO_PWM;
+               data->REG_CRITICAL_TEMP = NCT6106_REG_CRITICAL_TEMP;
+               data->REG_CRITICAL_TEMP_TOLERANCE
+                 = NCT6106_REG_CRITICAL_TEMP_TOLERANCE;
+               data->REG_CRITICAL_PWM_ENABLE = NCT6106_REG_CRITICAL_PWM_ENABLE;
+               data->CRITICAL_PWM_ENABLE_MASK
+                 = NCT6106_CRITICAL_PWM_ENABLE_MASK;
+               data->REG_CRITICAL_PWM = NCT6106_REG_CRITICAL_PWM;
+               data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
+               data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE;
+               data->REG_TEMP_SEL = NCT6106_REG_TEMP_SEL;
+               data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
+               data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
+               data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
+               data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
+               data->REG_ALARM = NCT6106_REG_ALARM;
+               data->ALARM_BITS = NCT6106_ALARM_BITS;
+               data->REG_BEEP = NCT6106_REG_BEEP;
+               data->BEEP_BITS = NCT6106_BEEP_BITS;
+
+               reg_temp = NCT6106_REG_TEMP;
+               num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
+               reg_temp_over = NCT6106_REG_TEMP_OVER;
+               reg_temp_hyst = NCT6106_REG_TEMP_HYST;
+               reg_temp_config = NCT6106_REG_TEMP_CONFIG;
+               reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
+               reg_temp_crit = NCT6106_REG_TEMP_CRIT;
+               reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
+               reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
+
+               break;
        case nct6775:
                data->in_num = 9;
                data->pwm_num = 3;
@@ -3451,8 +3392,10 @@ static int nct6775_probe(struct platform_device *pdev)
                data->has_fan_div = true;
                data->temp_fixed_num = 3;
                data->num_temp_alarms = 3;
+               data->num_temp_beeps = 3;
 
                data->ALARM_BITS = NCT6775_ALARM_BITS;
+               data->BEEP_BITS = NCT6775_BEEP_BITS;
 
                data->fan_from_reg = fan_from_reg16;
                data->fan_from_reg_min = fan_from_reg8;
@@ -3466,6 +3409,7 @@ static int nct6775_probe(struct platform_device *pdev)
                data->REG_CONFIG = NCT6775_REG_CONFIG;
                data->REG_VBAT = NCT6775_REG_VBAT;
                data->REG_DIODE = NCT6775_REG_DIODE;
+               data->DIODE_MASK = NCT6775_DIODE_MASK;
                data->REG_VIN = NCT6775_REG_IN;
                data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
                data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
@@ -3474,6 +3418,7 @@ static int nct6775_probe(struct platform_device *pdev)
                data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
                data->REG_FAN_MIN = NCT6775_REG_FAN_MIN;
                data->REG_FAN_PULSES = NCT6775_REG_FAN_PULSES;
+               data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
                data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
                data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
                data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
@@ -3499,6 +3444,7 @@ static int nct6775_probe(struct platform_device *pdev)
                data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
                data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
                data->REG_ALARM = NCT6775_REG_ALARM;
+               data->REG_BEEP = NCT6775_REG_BEEP;
 
                reg_temp = NCT6775_REG_TEMP;
                num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
@@ -3516,8 +3462,10 @@ static int nct6775_probe(struct platform_device *pdev)
                data->has_fan_div = false;
                data->temp_fixed_num = 3;
                data->num_temp_alarms = 3;
+               data->num_temp_beeps = 6;
 
                data->ALARM_BITS = NCT6776_ALARM_BITS;
+               data->BEEP_BITS = NCT6776_BEEP_BITS;
 
                data->fan_from_reg = fan_from_reg13;
                data->fan_from_reg_min = fan_from_reg13;
@@ -3531,6 +3479,7 @@ static int nct6775_probe(struct platform_device *pdev)
                data->REG_CONFIG = NCT6775_REG_CONFIG;
                data->REG_VBAT = NCT6775_REG_VBAT;
                data->REG_DIODE = NCT6775_REG_DIODE;
+               data->DIODE_MASK = NCT6775_DIODE_MASK;
                data->REG_VIN = NCT6775_REG_IN;
                data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
                data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
@@ -3539,6 +3488,7 @@ static int nct6775_probe(struct platform_device *pdev)
                data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
                data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
                data->REG_FAN_PULSES = NCT6776_REG_FAN_PULSES;
+               data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
                data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
                data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
                data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
@@ -3564,6 +3514,7 @@ static int nct6775_probe(struct platform_device *pdev)
                data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
                data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
                data->REG_ALARM = NCT6775_REG_ALARM;
+               data->REG_BEEP = NCT6776_REG_BEEP;
 
                reg_temp = NCT6775_REG_TEMP;
                num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
@@ -3581,8 +3532,10 @@ static int nct6775_probe(struct platform_device *pdev)
                data->has_fan_div = false;
                data->temp_fixed_num = 6;
                data->num_temp_alarms = 2;
+               data->num_temp_beeps = 2;
 
                data->ALARM_BITS = NCT6779_ALARM_BITS;
+               data->BEEP_BITS = NCT6779_BEEP_BITS;
 
                data->fan_from_reg = fan_from_reg13;
                data->fan_from_reg_min = fan_from_reg13;
@@ -3596,6 +3549,7 @@ static int nct6775_probe(struct platform_device *pdev)
                data->REG_CONFIG = NCT6775_REG_CONFIG;
                data->REG_VBAT = NCT6775_REG_VBAT;
                data->REG_DIODE = NCT6775_REG_DIODE;
+               data->DIODE_MASK = NCT6775_DIODE_MASK;
                data->REG_VIN = NCT6779_REG_IN;
                data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
                data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
@@ -3604,6 +3558,7 @@ static int nct6775_probe(struct platform_device *pdev)
                data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
                data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
                data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
+               data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
                data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
                data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
                data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
@@ -3621,6 +3576,10 @@ static int nct6775_probe(struct platform_device *pdev)
                data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
                data->REG_CRITICAL_TEMP_TOLERANCE
                  = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
+               data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
+               data->CRITICAL_PWM_ENABLE_MASK
+                 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
+               data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
                data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
                data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
                data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
@@ -3629,6 +3588,81 @@ static int nct6775_probe(struct platform_device *pdev)
                data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
                data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
                data->REG_ALARM = NCT6779_REG_ALARM;
+               data->REG_BEEP = NCT6776_REG_BEEP;
+
+               reg_temp = NCT6779_REG_TEMP;
+               num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
+               reg_temp_over = NCT6779_REG_TEMP_OVER;
+               reg_temp_hyst = NCT6779_REG_TEMP_HYST;
+               reg_temp_config = NCT6779_REG_TEMP_CONFIG;
+               reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
+               reg_temp_crit = NCT6779_REG_TEMP_CRIT;
+
+               break;
+       case nct6791:
+               data->in_num = 15;
+               data->pwm_num = 6;
+               data->auto_pwm_num = 4;
+               data->has_fan_div = false;
+               data->temp_fixed_num = 6;
+               data->num_temp_alarms = 2;
+               data->num_temp_beeps = 2;
+
+               data->ALARM_BITS = NCT6791_ALARM_BITS;
+               data->BEEP_BITS = NCT6779_BEEP_BITS;
+
+               data->fan_from_reg = fan_from_reg13;
+               data->fan_from_reg_min = fan_from_reg13;
+               data->target_temp_mask = 0xff;
+               data->tolerance_mask = 0x07;
+               data->speed_tolerance_limit = 63;
+
+               data->temp_label = nct6779_temp_label;
+               data->temp_label_num = ARRAY_SIZE(nct6779_temp_label);
+
+               data->REG_CONFIG = NCT6775_REG_CONFIG;
+               data->REG_VBAT = NCT6775_REG_VBAT;
+               data->REG_DIODE = NCT6775_REG_DIODE;
+               data->DIODE_MASK = NCT6775_DIODE_MASK;
+               data->REG_VIN = NCT6779_REG_IN;
+               data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
+               data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
+               data->REG_TARGET = NCT6775_REG_TARGET;
+               data->REG_FAN = NCT6779_REG_FAN;
+               data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
+               data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
+               data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
+               data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
+               data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
+               data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
+               data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
+               data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
+               data->REG_PWM[0] = NCT6775_REG_PWM;
+               data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
+               data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
+               data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
+               data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
+               data->REG_PWM_READ = NCT6775_REG_PWM_READ;
+               data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
+               data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
+               data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
+               data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
+               data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
+               data->REG_CRITICAL_TEMP_TOLERANCE
+                 = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
+               data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
+               data->CRITICAL_PWM_ENABLE_MASK
+                 = NCT6779_CRITICAL_PWM_ENABLE_MASK;
+               data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
+               data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
+               data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
+               data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
+               data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
+               data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
+               data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
+               data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
+               data->REG_ALARM = NCT6791_REG_ALARM;
+               data->REG_BEEP = NCT6776_REG_BEEP;
 
                reg_temp = NCT6779_REG_TEMP;
                num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
@@ -3700,6 +3734,13 @@ static int nct6775_probe(struct platform_device *pdev)
                        data->reg_temp[0][src - 1] = reg_temp[i];
                        data->reg_temp[1][src - 1] = reg_temp_over[i];
                        data->reg_temp[2][src - 1] = reg_temp_hyst[i];
+                       if (reg_temp_crit_h && reg_temp_crit_h[i])
+                               data->reg_temp[3][src - 1] = reg_temp_crit_h[i];
+                       else if (reg_temp_crit[src - 1])
+                               data->reg_temp[3][src - 1]
+                                 = reg_temp_crit[src - 1];
+                       if (reg_temp_crit_l && reg_temp_crit_l[i])
+                               data->reg_temp[4][src - 1] = reg_temp_crit_l[i];
                        data->reg_temp_config[src - 1] = reg_temp_config[i];
                        data->temp_src[src - 1] = src;
                        continue;
@@ -3714,8 +3755,12 @@ static int nct6775_probe(struct platform_device *pdev)
                data->reg_temp[1][s] = reg_temp_over[i];
                data->reg_temp[2][s] = reg_temp_hyst[i];
                data->reg_temp_config[s] = reg_temp_config[i];
-               if (reg_temp_crit[src - 1])
+               if (reg_temp_crit_h && reg_temp_crit_h[i])
+                       data->reg_temp[3][s] = reg_temp_crit_h[i];
+               else if (reg_temp_crit[src - 1])
                        data->reg_temp[3][s] = reg_temp_crit[src - 1];
+               if (reg_temp_crit_l && reg_temp_crit_l[i])
+                       data->reg_temp[4][s] = reg_temp_crit_l[i];
 
                data->temp_src[s] = src;
                s++;
@@ -3767,12 +3812,14 @@ static int nct6775_probe(struct platform_device *pdev)
        cr2a = superio_inb(sio_data->sioreg, 0x2a);
        switch (data->kind) {
        case nct6775:
-               have_vid = (cr2a & 0x40);
+               data->have_vid = (cr2a & 0x40);
                break;
        case nct6776:
-               have_vid = (cr2a & 0x60) == 0x40;
+               data->have_vid = (cr2a & 0x60) == 0x40;
                break;
+       case nct6106:
        case nct6779:
+       case nct6791:
                break;
        }
 
@@ -3780,7 +3827,7 @@ static int nct6775_probe(struct platform_device *pdev)
         * Read VID value
         * We can get the VID input values directly at logical device D 0xe3.
         */
-       if (have_vid) {
+       if (data->have_vid) {
                superio_select(sio_data->sioreg, NCT6775_LD_VID);
                data->vid = superio_inb(sio_data->sioreg, 0xe3);
                data->vrm = vid_which_vrm();
@@ -3793,6 +3840,9 @@ static int nct6775_probe(struct platform_device *pdev)
                tmp = superio_inb(sio_data->sioreg,
                                  NCT6775_REG_CR_FAN_DEBOUNCE);
                switch (data->kind) {
+               case nct6106:
+                       tmp |= 0xe0;
+                       break;
                case nct6775:
                        tmp |= 0x1e;
                        break;
@@ -3800,6 +3850,9 @@ static int nct6775_probe(struct platform_device *pdev)
                case nct6779:
                        tmp |= 0x3e;
                        break;
+               case nct6791:
+                       tmp |= 0x7e;
+                       break;
                }
                superio_outb(sio_data->sioreg, NCT6775_REG_CR_FAN_DEBOUNCE,
                             tmp);
@@ -3807,157 +3860,47 @@ static int nct6775_probe(struct platform_device *pdev)
                         data->name);
        }
 
-       superio_exit(sio_data->sioreg);
-
-       if (have_vid) {
-               err = device_create_file(dev, &dev_attr_cpu0_vid);
-               if (err)
-                       return err;
-       }
+       nct6775_check_fan_inputs(data);
 
-       err = nct6775_check_fan_inputs(sio_data, data);
-       if (err)
-               goto exit_remove;
+       superio_exit(sio_data->sioreg);
 
        /* Read fan clock dividers immediately */
        nct6775_init_fan_common(dev, data);
 
        /* Register sysfs hooks */
-       for (i = 0; i < data->pwm_num; i++) {
-               if (!(data->has_pwm & (1 << i)))
-                       continue;
-
-               err = sysfs_create_group(&dev->kobj, &nct6775_group_pwm[i]);
-               if (err)
-                       goto exit_remove;
-
-               if (data->REG_PWM[3]) {
-                       err = device_create_file(dev,
-                                       &sda_pwm_max[i].dev_attr);
-                       if (err)
-                               goto exit_remove;
-               }
-               if (data->REG_PWM[4]) {
-                       err = device_create_file(dev,
-                                       &sda_pwm_step[i].dev_attr);
-                       if (err)
-                               goto exit_remove;
-               }
-               if (data->REG_PWM[6]) {
-                       err = device_create_file(dev,
-                                       &sda_weight_duty_base[i].dev_attr);
-                       if (err)
-                               goto exit_remove;
-               }
-       }
-       for (i = 0; i < ARRAY_SIZE(sda_auto_pwm_arrays); i++) {
-               struct sensor_device_attribute_2 *attr =
-                       &sda_auto_pwm_arrays[i];
-
-               if (!(data->has_pwm & (1 << attr->nr)))
-                       continue;
-               if (attr->index > data->auto_pwm_num)
-                       continue;
-               err = device_create_file(dev, &attr->dev_attr);
-               if (err)
-                       goto exit_remove;
-       }
-
-       for (i = 0; i < data->in_num; i++) {
-               if (!(data->have_in & (1 << i)))
-                       continue;
-               err = sysfs_create_group(&dev->kobj, &nct6775_group_in[i]);
-               if (err)
-                       goto exit_remove;
+       group = nct6775_create_attr_group(dev, &nct6775_pwm_template_group,
+                                         data->pwm_num);
+       if (IS_ERR(group)) {
+               err = PTR_ERR(group);
+               goto exit_remove;
        }
+       data->group_pwm = group;
 
-       for (i = 0; i < 5; i++) {
-               if (data->has_fan & (1 << i)) {
-                       err = device_create_file(dev,
-                                                &sda_fan_input[i].dev_attr);
-                       if (err)
-                               goto exit_remove;
-                       if (data->ALARM_BITS[FAN_ALARM_BASE + i] >= 0) {
-                               err = device_create_file(dev,
-                                               &sda_fan_alarm[i].dev_attr);
-                               if (err)
-                                       goto exit_remove;
-                       }
-                       if (data->kind != nct6776 &&
-                           data->kind != nct6779) {
-                               err = device_create_file(dev,
-                                               &sda_fan_div[i].dev_attr);
-                               if (err)
-                                       goto exit_remove;
-                       }
-                       if (data->has_fan_min & (1 << i)) {
-                               err = device_create_file(dev,
-                                               &sda_fan_min[i].dev_attr);
-                               if (err)
-                                       goto exit_remove;
-                       }
-                       err = device_create_file(dev,
-                                               &sda_fan_pulses[i].dev_attr);
-                       if (err)
-                               goto exit_remove;
-               }
+       group = nct6775_create_attr_group(dev, &nct6775_in_template_group,
+                                         fls(data->have_in));
+       if (IS_ERR(group)) {
+               err = PTR_ERR(group);
+               goto exit_remove;
        }
+       data->group_in = group;
 
-       for (i = 0; i < NUM_TEMP; i++) {
-               if (!(data->have_temp & (1 << i)))
-                       continue;
-               err = device_create_file(dev, &sda_temp_input[i].dev_attr);
-               if (err)
-                       goto exit_remove;
-               if (data->temp_label) {
-                       err = device_create_file(dev,
-                                                &sda_temp_label[i].dev_attr);
-                       if (err)
-                               goto exit_remove;
-               }
-               if (data->reg_temp[1][i]) {
-                       err = device_create_file(dev,
-                                                &sda_temp_max[i].dev_attr);
-                       if (err)
-                               goto exit_remove;
-               }
-               if (data->reg_temp[2][i]) {
-                       err = device_create_file(dev,
-                                       &sda_temp_max_hyst[i].dev_attr);
-                       if (err)
-                               goto exit_remove;
-               }
-               if (data->reg_temp[3][i]) {
-                       err = device_create_file(dev,
-                                                &sda_temp_crit[i].dev_attr);
-                       if (err)
-                               goto exit_remove;
-               }
-               if (find_temp_source(data, i, data->num_temp_alarms) >= 0) {
-                       err = device_create_file(dev,
-                                                &sda_temp_alarm[i].dev_attr);
-                       if (err)
-                               goto exit_remove;
-               }
-               if (!(data->have_temp_fixed & (1 << i)))
-                       continue;
-               err = device_create_file(dev, &sda_temp_type[i].dev_attr);
-               if (err)
-                       goto exit_remove;
-               err = device_create_file(dev, &sda_temp_offset[i].dev_attr);
-               if (err)
-                       goto exit_remove;
+       group = nct6775_create_attr_group(dev, &nct6775_fan_template_group,
+                                         fls(data->has_fan));
+       if (IS_ERR(group)) {
+               err = PTR_ERR(group);
+               goto exit_remove;
        }
+       data->group_fan = group;
 
-       for (i = 0; i < ARRAY_SIZE(sda_caseopen); i++) {
-               if (data->ALARM_BITS[INTRUSION_ALARM_BASE + i] < 0)
-                       continue;
-               err = device_create_file(dev, &sda_caseopen[i].dev_attr);
-               if (err)
-                       goto exit_remove;
+       group = nct6775_create_attr_group(dev, &nct6775_temp_template_group,
+                                         fls(data->have_temp));
+       if (IS_ERR(group)) {
+               err = PTR_ERR(group);
+               goto exit_remove;
        }
+       data->group_temp = group;
 
-       err = device_create_file(dev, &dev_attr_name);
+       err = sysfs_create_group(&dev->kobj, &nct6775_group_other);
        if (err)
                goto exit_remove;
 
@@ -3988,11 +3931,10 @@ static int nct6775_remove(struct platform_device *pdev)
 static int nct6775_suspend(struct device *dev)
 {
        struct nct6775_data *data = nct6775_update_device(dev);
-       struct nct6775_sio_data *sio_data = dev->platform_data;
 
        mutex_lock(&data->update_lock);
        data->vbat = nct6775_read_value(data, data->REG_VBAT);
-       if (sio_data->kind == nct6775) {
+       if (data->kind == nct6775) {
                data->fandiv1 = nct6775_read_value(data, NCT6775_REG_FANDIV1);
                data->fandiv2 = nct6775_read_value(data, NCT6775_REG_FANDIV2);
        }
@@ -4004,7 +3946,6 @@ static int nct6775_suspend(struct device *dev)
 static int nct6775_resume(struct device *dev)
 {
        struct nct6775_data *data = dev_get_drvdata(dev);
-       struct nct6775_sio_data *sio_data = dev->platform_data;
        int i, j;
 
        mutex_lock(&data->update_lock);
@@ -4041,7 +3982,7 @@ static int nct6775_resume(struct device *dev)
 
        /* Restore other settings */
        nct6775_write_value(data, data->REG_VBAT, data->vbat);
-       if (sio_data->kind == nct6775) {
+       if (data->kind == nct6775) {
                nct6775_write_value(data, NCT6775_REG_FANDIV1, data->fandiv1);
                nct6775_write_value(data, NCT6775_REG_FANDIV2, data->fandiv2);
        }
@@ -4056,6 +3997,8 @@ static int nct6775_resume(struct device *dev)
 static const struct dev_pm_ops nct6775_dev_pm_ops = {
        .suspend = nct6775_suspend,
        .resume = nct6775_resume,
+       .freeze = nct6775_suspend,
+       .restore = nct6775_resume
 };
 
 #define NCT6775_DEV_PM_OPS     (&nct6775_dev_pm_ops)
@@ -4074,17 +4017,19 @@ static struct platform_driver nct6775_driver = {
 };
 
 static const char * const nct6775_sio_names[] __initconst = {
+       "NCT6106D",
        "NCT6775F",
        "NCT6776D/F",
        "NCT6779D",
+       "NCT6791D",
 };
 
 /* nct6775_find() looks for a '627 in the Super-I/O config space */
-static int __init nct6775_find(int sioaddr, unsigned short *addr,
-                              struct nct6775_sio_data *sio_data)
+static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
 {
        u16 val;
        int err;
+       int addr;
 
        err = superio_enter(sioaddr);
        if (err)
@@ -4096,6 +4041,9 @@ static int __init nct6775_find(int sioaddr, unsigned short *addr,
                val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
                    | superio_inb(sioaddr, SIO_REG_DEVID + 1);
        switch (val & SIO_ID_MASK) {
+       case SIO_NCT6106_ID:
+               sio_data->kind = nct6106;
+               break;
        case SIO_NCT6775_ID:
                sio_data->kind = nct6775;
                break;
@@ -4105,6 +4053,9 @@ static int __init nct6775_find(int sioaddr, unsigned short *addr,
        case SIO_NCT6779_ID:
                sio_data->kind = nct6779;
                break;
+       case SIO_NCT6791_ID:
+               sio_data->kind = nct6791;
+               break;
        default:
                if (val != 0xffff)
                        pr_debug("unsupported chip ID: 0x%04x\n", val);
@@ -4116,8 +4067,8 @@ static int __init nct6775_find(int sioaddr, unsigned short *addr,
        superio_select(sioaddr, NCT6775_LD_HWM);
        val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
            | superio_inb(sioaddr, SIO_REG_ADDR + 1);
-       *addr = val & IOREGION_ALIGNMENT;
-       if (*addr == 0) {
+       addr = val & IOREGION_ALIGNMENT;
+       if (addr == 0) {
                pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
                superio_exit(sioaddr);
                return -ENODEV;
@@ -4129,13 +4080,22 @@ static int __init nct6775_find(int sioaddr, unsigned short *addr,
                pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
                superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
        }
+       if (sio_data->kind == nct6791) {
+               val = superio_inb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE);
+               if (val & 0x10) {
+                       pr_info("Enabling hardware monitor logical device mappings.\n");
+                       superio_outb(sioaddr,
+                                    NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE,
+                                    val & ~0x10);
+               }
+       }
 
        superio_exit(sioaddr);
-       pr_info("Found %s or compatible chip at %#x\n",
-               nct6775_sio_names[sio_data->kind], *addr);
+       pr_info("Found %s or compatible chip at %#x:%#x\n",
+               nct6775_sio_names[sio_data->kind], sioaddr, addr);
        sio_data->sioreg = sioaddr;
 
-       return 0;
+       return addr;
 }
 
 /*
@@ -4144,14 +4104,20 @@ static int __init nct6775_find(int sioaddr, unsigned short *addr,
  * track of the nct6775 driver. But since we platform_device_alloc(), we
  * must keep track of the device
  */
-static struct platform_device *pdev;
+static struct platform_device *pdev[2];
 
 static int __init sensors_nct6775_init(void)
 {
-       int err;
-       unsigned short address;
+       int i, err;
+       bool found = false;
+       int address;
        struct resource res;
        struct nct6775_sio_data sio_data;
+       int sioaddr[2] = { 0x2e, 0x4e };
+
+       err = platform_driver_register(&nct6775_driver);
+       if (err)
+               return err;
 
        /*
         * initialize sio_data->kind and sio_data->sioreg.
@@ -4160,64 +4126,71 @@ static int __init sensors_nct6775_init(void)
         * driver will probe 0x2e and 0x4e and auto-detect the presence of a
         * nct6775 hardware monitor, and call probe()
         */
-       if (nct6775_find(0x2e, &address, &sio_data) &&
-           nct6775_find(0x4e, &address, &sio_data))
-               return -ENODEV;
-
-       err = platform_driver_register(&nct6775_driver);
-       if (err)
-               goto exit;
+       for (i = 0; i < ARRAY_SIZE(pdev); i++) {
+               address = nct6775_find(sioaddr[i], &sio_data);
+               if (address <= 0)
+                       continue;
 
-       pdev = platform_device_alloc(DRVNAME, address);
-       if (!pdev) {
-               err = -ENOMEM;
-               pr_err("Device allocation failed\n");
-               goto exit_unregister;
-       }
+               found = true;
 
-       err = platform_device_add_data(pdev, &sio_data,
-                                      sizeof(struct nct6775_sio_data));
-       if (err) {
-               pr_err("Platform data allocation failed\n");
-               goto exit_device_put;
-       }
+               pdev[i] = platform_device_alloc(DRVNAME, address);
+               if (!pdev[i]) {
+                       err = -ENOMEM;
+                       goto exit_device_put;
+               }
 
-       memset(&res, 0, sizeof(res));
-       res.name = DRVNAME;
-       res.start = address + IOREGION_OFFSET;
-       res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
-       res.flags = IORESOURCE_IO;
+               err = platform_device_add_data(pdev[i], &sio_data,
+                                              sizeof(struct nct6775_sio_data));
+               if (err)
+                       goto exit_device_put;
+
+               memset(&res, 0, sizeof(res));
+               res.name = DRVNAME;
+               res.start = address + IOREGION_OFFSET;
+               res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
+               res.flags = IORESOURCE_IO;
+
+               err = acpi_check_resource_conflict(&res);
+               if (err) {
+                       platform_device_put(pdev[i]);
+                       pdev[i] = NULL;
+                       continue;
+               }
 
-       err = acpi_check_resource_conflict(&res);
-       if (err)
-               goto exit_device_put;
+               err = platform_device_add_resources(pdev[i], &res, 1);
+               if (err)
+                       goto exit_device_put;
 
-       err = platform_device_add_resources(pdev, &res, 1);
-       if (err) {
-               pr_err("Device resource addition failed (%d)\n", err);
-               goto exit_device_put;
+               /* platform_device_add calls probe() */
+               err = platform_device_add(pdev[i]);
+               if (err)
+                       goto exit_device_put;
        }
-
-       /* platform_device_add calls probe() */
-       err = platform_device_add(pdev);
-       if (err) {
-               pr_err("Device addition failed (%d)\n", err);
-               goto exit_device_put;
+       if (!found) {
+               err = -ENODEV;
+               goto exit_unregister;
        }
 
        return 0;
 
 exit_device_put:
-       platform_device_put(pdev);
+       for (i = 0; i < ARRAY_SIZE(pdev); i++) {
+               if (pdev[i])
+                       platform_device_put(pdev[i]);
+       }
 exit_unregister:
        platform_driver_unregister(&nct6775_driver);
-exit:
        return err;
 }
 
 static void __exit sensors_nct6775_exit(void)
 {
-       platform_device_unregister(pdev);
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(pdev); i++) {
+               if (pdev[i])
+                       platform_device_unregister(pdev[i]);
+       }
        platform_driver_unregister(&nct6775_driver);
 }
 
index 830a842d796af833c0b6a04785e1eff09b73599d..8c23203915af3644cd138b13ec99faef572b49b5 100644 (file)
@@ -424,7 +424,7 @@ static int ntc_thermistor_probe(struct platform_device *pdev)
        if (IS_ERR(pdata))
                return PTR_ERR(pdata);
        else if (pdata == NULL)
-               pdata = pdev->dev.platform_data;
+               pdata = dev_get_platdata(&pdev->dev);
 
        if (!pdata) {
                dev_err(&pdev->dev, "No platform init data supplied.\n");
index ea606860d2b203b8a9f679c62bc3d2cbfbfedbc0..6e6ea4437bb6947692ebd5b4fcc55e698a675b3f 100644 (file)
@@ -983,7 +983,7 @@ static int pc87427_request_regions(struct platform_device *pdev,
 
 static void pc87427_init_device(struct device *dev)
 {
-       struct pc87427_sio_data *sio_data = dev->platform_data;
+       struct pc87427_sio_data *sio_data = dev_get_platdata(dev);
        struct pc87427_data *data = dev_get_drvdata(dev);
        int i;
        u8 reg;
@@ -1075,7 +1075,7 @@ static void pc87427_remove_files(struct device *dev)
 
 static int pc87427_probe(struct platform_device *pdev)
 {
-       struct pc87427_sio_data *sio_data = pdev->dev.platform_data;
+       struct pc87427_sio_data *sio_data = dev_get_platdata(&pdev->dev);
        struct pc87427_data *data;
        int i, err, res_count;
 
index 9add60920ac00ed5aa70ca0e1113887836e0ae7d..9319fcf142d96656040eabcc0d411699f61f4b06 100644 (file)
@@ -1726,7 +1726,7 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
                   struct pmbus_driver_info *info)
 {
        struct device *dev = &client->dev;
-       const struct pmbus_platform_data *pdata = dev->platform_data;
+       const struct pmbus_platform_data *pdata = dev_get_platdata(dev);
        struct pmbus_data *data;
        int ret;
 
index a9f7e804f1e4f6c3d580ff6d444b3ff7506d589a..73bd64e8c30a8bc8ad6dfdd947cf7a33bf52f142 100644 (file)
@@ -165,7 +165,7 @@ static ssize_t s3c_hwmon_ch_show(struct device *dev,
 {
        struct sensor_device_attribute *sen_attr = to_sensor_dev_attr(attr);
        struct s3c_hwmon *hwmon = platform_get_drvdata(to_platform_device(dev));
-       struct s3c_hwmon_pdata *pdata = dev->platform_data;
+       struct s3c_hwmon_pdata *pdata = dev_get_platdata(dev);
        struct s3c_hwmon_chcfg *cfg;
        int ret;
 
@@ -194,7 +194,7 @@ static ssize_t s3c_hwmon_label_show(struct device *dev,
                                    char *buf)
 {
        struct sensor_device_attribute *sen_attr = to_sensor_dev_attr(attr);
-       struct s3c_hwmon_pdata *pdata = dev->platform_data;
+       struct s3c_hwmon_pdata *pdata = dev_get_platdata(dev);
        struct s3c_hwmon_chcfg *cfg;
 
        cfg = pdata->in[sen_attr->index];
@@ -274,7 +274,7 @@ static void s3c_hwmon_remove_attr(struct device *dev,
 */
 static int s3c_hwmon_probe(struct platform_device *dev)
 {
-       struct s3c_hwmon_pdata *pdata = dev->dev.platform_data;
+       struct s3c_hwmon_pdata *pdata = dev_get_platdata(&dev->dev);
        struct s3c_hwmon *hwmon;
        int ret = 0;
        int i;
index 2507f902fb7aa4ea450079a69bbbf8234e7e0ef4..883d291ff49a126129a8e541f551119866ba6984 100644 (file)
@@ -940,11 +940,11 @@ static int sht15_probe(struct platform_device *pdev)
        data->dev = &pdev->dev;
        init_waitqueue_head(&data->wait_queue);
 
-       if (pdev->dev.platform_data == NULL) {
+       if (dev_get_platdata(&pdev->dev) == NULL) {
                dev_err(&pdev->dev, "no platform data supplied\n");
                return -EINVAL;
        }
-       data->pdata = pdev->dev.platform_data;
+       data->pdata = dev_get_platdata(&pdev->dev);
        data->supply_uv = data->pdata->supply_mv * 1000;
        if (data->pdata->checksum)
                data->checksumming = true;
index 6d8255ccf07afb1a9d31955f82e91392a824a4ba..05cb814539cb609d42e7bd9bc84abe178cb6b7a7 100644 (file)
@@ -668,7 +668,7 @@ static void smsc47m1_remove_files(struct device *dev)
 static int __init smsc47m1_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct smsc47m1_sio_data *sio_data = dev->platform_data;
+       struct smsc47m1_sio_data *sio_data = dev_get_platdata(dev);
        struct smsc47m1_data *data;
        struct resource *res;
        int err;
@@ -940,7 +940,7 @@ exit_device:
 static void __exit sm_smsc47m1_exit(void)
 {
        platform_driver_unregister(&smsc47m1_driver);
-       smsc47m1_restore(pdev->dev.platform_data);
+       smsc47m1_restore(dev_get_platdata(&pdev->dev));
        platform_device_unregister(pdev);
 }
 
index 004801e6fbb9756d8bdeed3aac25899a7f00edaa..286ca7bae97cd9da89d8866f6c21f69d2ef74339 100644 (file)
@@ -673,7 +673,7 @@ static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr)
 static void w83627ehf_write_fan_div_common(struct device *dev,
                                           struct w83627ehf_data *data, int nr)
 {
-       struct w83627ehf_sio_data *sio_data = dev->platform_data;
+       struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
 
        if (sio_data->kind == nct6776)
                ; /* no dividers, do nothing */
@@ -724,7 +724,7 @@ static void w83627ehf_update_fan_div(struct w83627ehf_data *data)
 static void w83627ehf_update_fan_div_common(struct device *dev,
                                            struct w83627ehf_data *data)
 {
-       struct w83627ehf_sio_data *sio_data = dev->platform_data;
+       struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
 
        if (sio_data->kind == nct6776)
                ; /* no dividers, do nothing */
@@ -781,7 +781,7 @@ static void w83627ehf_update_pwm(struct w83627ehf_data *data)
 static void w83627ehf_update_pwm_common(struct device *dev,
                                        struct w83627ehf_data *data)
 {
-       struct w83627ehf_sio_data *sio_data = dev->platform_data;
+       struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
 
        if (sio_data->kind == nct6775 || sio_data->kind == nct6776)
                nct6775_update_pwm(data);
@@ -792,7 +792,7 @@ static void w83627ehf_update_pwm_common(struct device *dev,
 static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
 {
        struct w83627ehf_data *data = dev_get_drvdata(dev);
-       struct w83627ehf_sio_data *sio_data = dev->platform_data;
+       struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
 
        int i;
 
@@ -1392,7 +1392,7 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr,
 {
        struct w83627ehf_data *data = dev_get_drvdata(dev);
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
-       struct w83627ehf_sio_data *sio_data = dev->platform_data;
+       struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
        int nr = sensor_attr->index;
        unsigned long val;
        int err;
@@ -1448,7 +1448,7 @@ store_pwm_enable(struct device *dev, struct device_attribute *attr,
                        const char *buf, size_t count)
 {
        struct w83627ehf_data *data = dev_get_drvdata(dev);
-       struct w83627ehf_sio_data *sio_data = dev->platform_data;
+       struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
        int nr = sensor_attr->index;
        unsigned long val;
@@ -1527,7 +1527,7 @@ store_tolerance(struct device *dev, struct device_attribute *attr,
                        const char *buf, size_t count)
 {
        struct w83627ehf_data *data = dev_get_drvdata(dev);
-       struct w83627ehf_sio_data *sio_data = dev->platform_data;
+       struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
        int nr = sensor_attr->index;
        u16 reg;
@@ -2065,7 +2065,7 @@ w83627ehf_check_fan_inputs(const struct w83627ehf_sio_data *sio_data,
 static int w83627ehf_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct w83627ehf_sio_data *sio_data = dev->platform_data;
+       struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
        struct w83627ehf_data *data;
        struct resource *res;
        u8 en_vrm10;
@@ -2618,7 +2618,7 @@ static int w83627ehf_remove(struct platform_device *pdev)
 static int w83627ehf_suspend(struct device *dev)
 {
        struct w83627ehf_data *data = w83627ehf_update_device(dev);
-       struct w83627ehf_sio_data *sio_data = dev->platform_data;
+       struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
 
        mutex_lock(&data->update_lock);
        data->vbat = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
@@ -2634,7 +2634,7 @@ static int w83627ehf_suspend(struct device *dev)
 static int w83627ehf_resume(struct device *dev)
 {
        struct w83627ehf_data *data = dev_get_drvdata(dev);
-       struct w83627ehf_sio_data *sio_data = dev->platform_data;
+       struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
        int i;
 
        mutex_lock(&data->update_lock);
index 3b9ef2d23452801166e2f278b1014ace47b11639..cb9cd326ecb564147ec64474c14a296b1be764dd 100644 (file)
@@ -1415,7 +1415,7 @@ static const struct attribute_group w83627hf_group_opt = {
 static int w83627hf_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct w83627hf_sio_data *sio_data = dev->platform_data;
+       struct w83627hf_sio_data *sio_data = dev_get_platdata(dev);
        struct w83627hf_data *data;
        struct resource *res;
        int err, i;
@@ -1636,7 +1636,7 @@ static int w83627hf_read_value(struct w83627hf_data *data, u16 reg)
 
 static int w83627thf_read_gpio5(struct platform_device *pdev)
 {
-       struct w83627hf_sio_data *sio_data = pdev->dev.platform_data;
+       struct w83627hf_sio_data *sio_data = dev_get_platdata(&pdev->dev);
        int res = 0xff, sel;
 
        superio_enter(sio_data);
@@ -1669,7 +1669,7 @@ exit:
 
 static int w83687thf_read_vid(struct platform_device *pdev)
 {
-       struct w83627hf_sio_data *sio_data = pdev->dev.platform_data;
+       struct w83627hf_sio_data *sio_data = dev_get_platdata(&pdev->dev);
        int res = 0xff;
 
        superio_enter(sio_data);
index 0b804895be43361a9230b4632e101945091298ad..5febb43cb4c1032de659cbf3ec3ffa652c8c832f 100644 (file)
@@ -2,7 +2,7 @@
  * w83792d.c - Part of lm_sensors, Linux kernel modules for hardware
  *            monitoring
  * Copyright (C) 2004, 2005 Winbond Electronics Corp.
- *                         Chunhao Huang <DZShen@Winbond.com.tw>,
+ *                         Shane Huang,
  *                         Rudolf Marek <r.marek@assembler.cz>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -1665,6 +1665,6 @@ static void w83792d_print_debug(struct w83792d_data *data, struct device *dev)
 
 module_i2c_driver(w83792d_driver);
 
-MODULE_AUTHOR("Chunhao Huang @ Winbond <DZShen@Winbond.com.tw>");
+MODULE_AUTHOR("Shane Huang (Winbond)");
 MODULE_DESCRIPTION("W83792AD/D driver for linux-2.6");
 MODULE_LICENSE("GPL");
index f1a6796b165c154bffd18d9c6f99e407aac24d96..140c8ef505291129d6299d2b4d4931d3b728589e 100644 (file)
@@ -520,11 +520,12 @@ void ide_acpi_set_state(ide_hwif_t *hwif, int on)
        ide_port_for_each_present_dev(i, drive, hwif) {
                if (drive->acpidata->obj_handle)
                        acpi_bus_set_power(drive->acpidata->obj_handle,
-                                          on ? ACPI_STATE_D0 : ACPI_STATE_D3);
+                               on ? ACPI_STATE_D0 : ACPI_STATE_D3_COLD);
        }
 
        if (!on)
-               acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D3);
+               acpi_bus_set_power(hwif->acpidata->obj_handle,
+                                  ACPI_STATE_D3_COLD);
 }
 
 /**
index f1c279fabe646f80d3962f3354475087f9c37bf8..7c0f9535fb7d443bf2c4b1647b3494816292020a 100644 (file)
@@ -423,7 +423,7 @@ static int cma_resolve_ib_dev(struct rdma_id_private *id_priv)
        struct sockaddr_ib *addr;
        union ib_gid gid, sgid, *dgid;
        u16 pkey, index;
-       u8 port, p;
+       u8 p;
        int i;
 
        cma_dev = NULL;
@@ -443,7 +443,7 @@ static int cma_resolve_ib_dev(struct rdma_id_private *id_priv)
                                if (!memcmp(&gid, dgid, sizeof(gid))) {
                                        cma_dev = cur_dev;
                                        sgid = gid;
-                                       port = p;
+                                       id_priv->id.port_num = p;
                                        goto found;
                                }
 
@@ -451,7 +451,7 @@ static int cma_resolve_ib_dev(struct rdma_id_private *id_priv)
                                                 dgid->global.subnet_prefix)) {
                                        cma_dev = cur_dev;
                                        sgid = gid;
-                                       port = p;
+                                       id_priv->id.port_num = p;
                                }
                        }
                }
@@ -462,7 +462,6 @@ static int cma_resolve_ib_dev(struct rdma_id_private *id_priv)
 
 found:
        cma_attach_to_dev(id_priv, cma_dev);
-       id_priv->id.port_num = port;
        addr = (struct sockaddr_ib *) cma_src_addr(id_priv);
        memcpy(&addr->sib_addr, &sgid, sizeof sgid);
        cma_translate_ib(addr, &id_priv->id.route.addr.dev_addr);
@@ -880,7 +879,8 @@ static int cma_save_net_info(struct rdma_cm_id *id, struct rdma_cm_id *listen_id
 {
        struct cma_hdr *hdr;
 
-       if (listen_id->route.addr.src_addr.ss_family == AF_IB) {
+       if ((listen_id->route.addr.src_addr.ss_family == AF_IB) &&
+           (ib_event->event == IB_CM_REQ_RECEIVED)) {
                cma_save_ib_info(id, listen_id, ib_event->param.req_rcvd.primary_path);
                return 0;
        }
@@ -2677,29 +2677,32 @@ static int cma_resolve_ib_udp(struct rdma_id_private *id_priv,
 {
        struct ib_cm_sidr_req_param req;
        struct ib_cm_id *id;
+       void *private_data;
        int offset, ret;
 
+       memset(&req, 0, sizeof req);
        offset = cma_user_data_offset(id_priv);
        req.private_data_len = offset + conn_param->private_data_len;
        if (req.private_data_len < conn_param->private_data_len)
                return -EINVAL;
 
        if (req.private_data_len) {
-               req.private_data = kzalloc(req.private_data_len, GFP_ATOMIC);
-               if (!req.private_data)
+               private_data = kzalloc(req.private_data_len, GFP_ATOMIC);
+               if (!private_data)
                        return -ENOMEM;
        } else {
-               req.private_data = NULL;
+               private_data = NULL;
        }
 
        if (conn_param->private_data && conn_param->private_data_len)
-               memcpy((void *) req.private_data + offset,
-                      conn_param->private_data, conn_param->private_data_len);
+               memcpy(private_data + offset, conn_param->private_data,
+                      conn_param->private_data_len);
 
-       if (req.private_data) {
-               ret = cma_format_hdr((void *) req.private_data, id_priv);
+       if (private_data) {
+               ret = cma_format_hdr(private_data, id_priv);
                if (ret)
                        goto out;
+               req.private_data = private_data;
        }
 
        id = ib_create_cm_id(id_priv->id.device, cma_sidr_rep_handler,
@@ -2721,7 +2724,7 @@ static int cma_resolve_ib_udp(struct rdma_id_private *id_priv,
                id_priv->cm_id.ib = NULL;
        }
 out:
-       kfree(req.private_data);
+       kfree(private_data);
        return ret;
 }
 
index dc3fd1e8af07f0f8f4c6da455c38e315074a8e1e..4c837e66516b894f88f689d93c9a84c501fa6b47 100644 (file)
@@ -2663,6 +2663,7 @@ static int ib_mad_port_start(struct ib_mad_port_private *port_priv)
        int ret, i;
        struct ib_qp_attr *attr;
        struct ib_qp *qp;
+       u16 pkey_index;
 
        attr = kmalloc(sizeof *attr, GFP_KERNEL);
        if (!attr) {
@@ -2670,6 +2671,11 @@ static int ib_mad_port_start(struct ib_mad_port_private *port_priv)
                return -ENOMEM;
        }
 
+       ret = ib_find_pkey(port_priv->device, port_priv->port_num,
+                          IB_DEFAULT_PKEY_FULL, &pkey_index);
+       if (ret)
+               pkey_index = 0;
+
        for (i = 0; i < IB_MAD_QPS_CORE; i++) {
                qp = port_priv->qp_info[i].qp;
                if (!qp)
@@ -2680,7 +2686,7 @@ static int ib_mad_port_start(struct ib_mad_port_private *port_priv)
                 * one is needed for the Reset to Init transition
                 */
                attr->qp_state = IB_QPS_INIT;
-               attr->pkey_index = 0;
+               attr->pkey_index = pkey_index;
                attr->qkey = (qp->qp_num == 0) ? 0 : IB_QP1_QKEY;
                ret = ib_modify_qp(qp, attr, IB_QP_STATE |
                                             IB_QP_PKEY_INDEX | IB_QP_QKEY);
index e87f2201b220673030ca18a3957642b623d065a7..d2283837d45168070707eba5ac11aab4c2fe9c5e 100644 (file)
@@ -226,6 +226,7 @@ static struct ib_cq *iwch_create_cq(struct ib_device *ibdev, int entries, int ve
                        mm->len = PAGE_ALIGN(((1UL << uresp.size_log2) + 1) *
                                             sizeof(struct t3_cqe));
                        uresp.memsize = mm->len;
+                       uresp.reserved = 0;
                        resplen = sizeof uresp;
                }
                if (ib_copy_to_udata(udata, &uresp, resplen)) {
index 232040447e8a23803cc73e64c203734d36492c2e..a4975e1654a639960b214114648593564fcb0b27 100644 (file)
@@ -1657,6 +1657,8 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
                if (mm5) {
                        uresp.ma_sync_key = ucontext->key;
                        ucontext->key += PAGE_SIZE;
+               } else {
+                       uresp.ma_sync_key =  0;
                }
                uresp.sq_key = ucontext->key;
                ucontext->key += PAGE_SIZE;
index 4d599cedbb0b1ccceab997a4945be0d8d6e89fde..f2a3f48107e71e1d53b0abb61757f1f0ba38bb59 100644 (file)
@@ -1511,8 +1511,14 @@ static int create_pv_sqp(struct mlx4_ib_demux_pv_ctx *ctx,
 
        memset(&attr, 0, sizeof attr);
        attr.qp_state = IB_QPS_INIT;
-       attr.pkey_index =
-               to_mdev(ctx->ib_dev)->pkeys.virt2phys_pkey[ctx->slave][ctx->port - 1][0];
+       ret = 0;
+       if (create_tun)
+               ret = find_slave_port_pkey_ix(to_mdev(ctx->ib_dev), ctx->slave,
+                                             ctx->port, IB_DEFAULT_PKEY_FULL,
+                                             &attr.pkey_index);
+       if (ret || !create_tun)
+               attr.pkey_index =
+                       to_mdev(ctx->ib_dev)->pkeys.virt2phys_pkey[ctx->slave][ctx->port - 1][0];
        attr.qkey = IB_QP1_QKEY;
        attr.port_num = ctx->port;
        ret = ib_modify_qp(tun_qp->qp, &attr, qp_attr_mask_INIT);
index 8000fff4d4444168ac4091a78112593d11b212dd..3f831de9a4d8a901607afc26c81827cc5c1e3bd5 100644 (file)
@@ -619,7 +619,8 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev,
 
        resp.tot_uuars = req.total_num_uuars;
        resp.num_ports = dev->mdev.caps.num_ports;
-       err = ib_copy_to_udata(udata, &resp, sizeof(resp));
+       err = ib_copy_to_udata(udata, &resp,
+                              sizeof(resp) - sizeof(resp.reserved));
        if (err)
                goto out_uars;
 
@@ -1426,7 +1427,8 @@ static int init_one(struct pci_dev *pdev,
        if (err)
                goto err_eqs;
 
-       if (ib_register_device(&dev->ib_dev, NULL))
+       err = ib_register_device(&dev->ib_dev, NULL);
+       if (err)
                goto err_rsrc;
 
        err = create_umr_res(dev);
@@ -1434,8 +1436,9 @@ static int init_one(struct pci_dev *pdev,
                goto err_dev;
 
        for (i = 0; i < ARRAY_SIZE(mlx5_class_attributes); i++) {
-               if (device_create_file(&dev->ib_dev.dev,
-                                      mlx5_class_attributes[i]))
+               err = device_create_file(&dev->ib_dev.dev,
+                                        mlx5_class_attributes[i]);
+               if (err)
                        goto err_umrc;
        }
 
index 16ac54c9819f24c113ad02f594a47608a004a828..045f8cdbd303deba81e60c5f1f52330b536b9617 100644 (file)
@@ -199,7 +199,7 @@ static int set_rq_size(struct mlx5_ib_dev *dev, struct ib_qp_cap *cap,
 
 static int sq_overhead(enum ib_qp_type qp_type)
 {
-       int size;
+       int size = 0;
 
        switch (qp_type) {
        case IB_QPT_XRC_INI:
index 418004c93feb772c641dde6b102620fc2be45900..90200245c5ebfd5fe71000d17b78e52bfa8d4734 100644 (file)
@@ -3570,10 +3570,10 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
        tcp_state = (aeq_info & NES_AEQE_TCP_STATE_MASK) >> NES_AEQE_TCP_STATE_SHIFT;
        iwarp_state = (aeq_info & NES_AEQE_IWARP_STATE_MASK) >> NES_AEQE_IWARP_STATE_SHIFT;
        nes_debug(NES_DBG_AEQ, "aeid = 0x%04X, qp-cq id = %d, aeqe = %p,"
-                       " Tcp state = %d, iWARP state = %d\n",
+                       " Tcp state = %s, iWARP state = %s\n",
                        async_event_id,
                        le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]), aeqe,
-                       tcp_state, iwarp_state);
+                       nes_tcp_state_str[tcp_state], nes_iwarp_state_str[iwarp_state]);
 
        aeqe_cq_id = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]);
        if (aeq_info & NES_AEQE_QP) {
index 8f67fe2e91e623a87878a8790ff9f2e28db0c0b8..5b53ca5a22840c14e31ddb0d7e978dfac5c179b7 100644 (file)
@@ -1384,6 +1384,7 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd,
 
                        if (ibpd->uobject) {
                                uresp.mmap_sq_db_index = nesqp->mmap_sq_db_index;
+                               uresp.mmap_rq_db_index = 0;
                                uresp.actual_sq_size = sq_size;
                                uresp.actual_rq_size = rq_size;
                                uresp.qp_id = nesqp->hwqp.qp_id;
@@ -1767,7 +1768,7 @@ static struct ib_cq *nes_create_cq(struct ib_device *ibdev, int entries,
                resp.cq_id = nescq->hw_cq.cq_number;
                resp.cq_size = nescq->hw_cq.cq_size;
                resp.mmap_db_index = 0;
-               if (ib_copy_to_udata(udata, &resp, sizeof resp)) {
+               if (ib_copy_to_udata(udata, &resp, sizeof resp - sizeof resp.reserved)) {
                        nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
                        kfree(nescq);
                        return ERR_PTR(-EFAULT);
index a877a8ed79077dbd085d28d1fd834b3f1e01d019..f4c587c68f648055546deafce7f8708798f4d109 100644 (file)
@@ -29,7 +29,6 @@
 #include <net/netevent.h>
 
 #include <rdma/ib_addr.h>
-#include <rdma/ib_cache.h>
 
 #include "ocrdma.h"
 #include "ocrdma_verbs.h"
index dcfbab177faa63eee063a428ac7848e5763f8125..f36630e4b6be182c735b7aa81d357b4207266c82 100644 (file)
@@ -242,6 +242,7 @@ struct ib_ucontext *ocrdma_alloc_ucontext(struct ib_device *ibdev,
        memset(ctx->ah_tbl.va, 0, map_len);
        ctx->ah_tbl.len = map_len;
 
+       memset(&resp, 0, sizeof(resp));
        resp.ah_tbl_len = ctx->ah_tbl.len;
        resp.ah_tbl_page = ctx->ah_tbl.pa;
 
@@ -253,7 +254,6 @@ struct ib_ucontext *ocrdma_alloc_ucontext(struct ib_device *ibdev,
        resp.wqe_size = dev->attr.wqe_size;
        resp.rqe_size = dev->attr.rqe_size;
        resp.dpp_wqe_size = dev->attr.wqe_size;
-       resp.rsvd = 0;
 
        memcpy(resp.fw_ver, dev->attr.fw_ver, sizeof(resp.fw_ver));
        status = ib_copy_to_udata(udata, &resp, sizeof(resp));
@@ -338,6 +338,7 @@ static int ocrdma_copy_pd_uresp(struct ocrdma_pd *pd,
        struct ocrdma_alloc_pd_uresp rsp;
        struct ocrdma_ucontext *uctx = get_ocrdma_ucontext(ib_ctx);
 
+       memset(&rsp, 0, sizeof(rsp));
        rsp.id = pd->id;
        rsp.dpp_enabled = pd->dpp_enabled;
        db_page_addr = pd->dev->nic_info.unmapped_db +
@@ -692,6 +693,7 @@ static int ocrdma_copy_cq_uresp(struct ocrdma_cq *cq, struct ib_udata *udata,
        struct ocrdma_ucontext *uctx;
        struct ocrdma_create_cq_uresp uresp;
 
+       memset(&uresp, 0, sizeof(uresp));
        uresp.cq_id = cq->id;
        uresp.page_size = cq->len;
        uresp.num_pages = 1;
@@ -1460,6 +1462,7 @@ static int ocrdma_copy_srq_uresp(struct ocrdma_srq *srq, struct ib_udata *udata)
        int status;
        struct ocrdma_create_srq_uresp uresp;
 
+       memset(&uresp, 0, sizeof(uresp));
        uresp.rq_dbid = srq->rq.dbid;
        uresp.num_rq_pages = 1;
        uresp.rq_page_addr[0] = srq->rq.pa;
index 21e8b09d4bf87687a9c569ac87dae42108b7cd8a..016e7429adf66b9ffb945cb4fed168e358c57742 100644 (file)
@@ -1596,6 +1596,8 @@ static void sdma_7322_p_errors(struct qib_pportdata *ppd, u64 errs)
        struct qib_devdata *dd = ppd->dd;
 
        errs &= QIB_E_P_SDMAERRS;
+       err_decode(ppd->cpspec->sdmamsgbuf, sizeof(ppd->cpspec->sdmamsgbuf),
+                  errs, qib_7322p_error_msgs);
 
        if (errs & QIB_E_P_SDMAUNEXPDATA)
                qib_dev_err(dd, "IB%u:%u SDmaUnexpData\n", dd->unit,
index 32162d355370f95b56970b19da33783052c24c36..9b5322d8cd5accca85737745ba06973ca7212efe 100644 (file)
@@ -717,7 +717,7 @@ void dump_sdma_state(struct qib_pportdata *ppd)
        struct qib_sdma_txreq *txp, *txpnext;
        __le64 *descqp;
        u64 desc[2];
-       dma_addr_t addr;
+       u64 addr;
        u16 gen, dwlen, dwoffset;
        u16 head, tail, cnt;
 
index 2cfa76f5d99eac87bf788eb41bb2a7c3815ec700..196b1d13cbcbc09548e92a4be6c9a18cdc6aae36 100644 (file)
@@ -932,12 +932,47 @@ int ipoib_ib_dev_init(struct net_device *dev, struct ib_device *ca, int port)
        return 0;
 }
 
+/*
+ * Takes whatever value which is in pkey index 0 and updates priv->pkey
+ * returns 0 if the pkey value was changed.
+ */
+static inline int update_parent_pkey(struct ipoib_dev_priv *priv)
+{
+       int result;
+       u16 prev_pkey;
+
+       prev_pkey = priv->pkey;
+       result = ib_query_pkey(priv->ca, priv->port, 0, &priv->pkey);
+       if (result) {
+               ipoib_warn(priv, "ib_query_pkey port %d failed (ret = %d)\n",
+                          priv->port, result);
+               return result;
+       }
+
+       priv->pkey |= 0x8000;
+
+       if (prev_pkey != priv->pkey) {
+               ipoib_dbg(priv, "pkey changed from 0x%x to 0x%x\n",
+                         prev_pkey, priv->pkey);
+               /*
+                * Update the pkey in the broadcast address, while making sure to set
+                * the full membership bit, so that we join the right broadcast group.
+                */
+               priv->dev->broadcast[8] = priv->pkey >> 8;
+               priv->dev->broadcast[9] = priv->pkey & 0xff;
+               return 0;
+       }
+
+       return 1;
+}
+
 static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv,
                                enum ipoib_flush_level level)
 {
        struct ipoib_dev_priv *cpriv;
        struct net_device *dev = priv->dev;
        u16 new_index;
+       int result;
 
        mutex_lock(&priv->vlan_mutex);
 
@@ -951,6 +986,10 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv,
        mutex_unlock(&priv->vlan_mutex);
 
        if (!test_bit(IPOIB_FLAG_INITIALIZED, &priv->flags)) {
+               /* for non-child devices must check/update the pkey value here */
+               if (level == IPOIB_FLUSH_HEAVY &&
+                   !test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags))
+                       update_parent_pkey(priv);
                ipoib_dbg(priv, "Not flushing - IPOIB_FLAG_INITIALIZED not set.\n");
                return;
        }
@@ -961,21 +1000,32 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv,
        }
 
        if (level == IPOIB_FLUSH_HEAVY) {
-               if (ib_find_pkey(priv->ca, priv->port, priv->pkey, &new_index)) {
-                       clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags);
-                       ipoib_ib_dev_down(dev, 0);
-                       ipoib_ib_dev_stop(dev, 0);
-                       if (ipoib_pkey_dev_delay_open(dev))
+               /* child devices chase their origin pkey value, while non-child
+                * (parent) devices should always takes what present in pkey index 0
+                */
+               if (test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) {
+                       if (ib_find_pkey(priv->ca, priv->port, priv->pkey, &new_index)) {
+                               clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags);
+                               ipoib_ib_dev_down(dev, 0);
+                               ipoib_ib_dev_stop(dev, 0);
+                               if (ipoib_pkey_dev_delay_open(dev))
+                                       return;
+                       }
+                       /* restart QP only if P_Key index is changed */
+                       if (test_and_set_bit(IPOIB_PKEY_ASSIGNED, &priv->flags) &&
+                           new_index == priv->pkey_index) {
+                               ipoib_dbg(priv, "Not flushing - P_Key index not changed.\n");
                                return;
+                       }
+                       priv->pkey_index = new_index;
+               } else {
+                       result = update_parent_pkey(priv);
+                       /* restart QP only if P_Key value changed */
+                       if (result) {
+                               ipoib_dbg(priv, "Not flushing - P_Key value not changed.\n");
+                               return;
+                       }
                }
-
-               /* restart QP only if P_Key index is changed */
-               if (test_and_set_bit(IPOIB_PKEY_ASSIGNED, &priv->flags) &&
-                   new_index == priv->pkey_index) {
-                       ipoib_dbg(priv, "Not flushing - P_Key index not changed.\n");
-                       return;
-               }
-               priv->pkey_index = new_index;
        }
 
        if (level == IPOIB_FLUSH_LIGHT) {
index b6e049a3c7a853b92d5c9d126c61a2d850f290cb..c6f71a88c55ca9649b6098cc81d64de229857055 100644 (file)
@@ -1461,7 +1461,7 @@ static ssize_t create_child(struct device *dev,
        if (sscanf(buf, "%i", &pkey) != 1)
                return -EINVAL;
 
-       if (pkey < 0 || pkey > 0xffff)
+       if (pkey <= 0 || pkey > 0xffff || pkey == 0x8000)
                return -EINVAL;
 
        /*
index 74685936c9482be96c09a09e5af6f314bdc2b741..f81abe16cf093d6c74ad31dd179f03f7dc90b997 100644 (file)
@@ -119,6 +119,15 @@ static int ipoib_new_child_link(struct net *src_net, struct net_device *dev,
        } else
                child_pkey  = nla_get_u16(data[IFLA_IPOIB_PKEY]);
 
+       if (child_pkey == 0 || child_pkey == 0x8000)
+               return -EINVAL;
+
+       /*
+        * Set the full membership bit, so that we join the right
+        * broadcast group, etc.
+        */
+       child_pkey |= 0x8000;
+
        err = __ipoib_vlan_add(ppriv, netdev_priv(dev), child_pkey, IPOIB_RTNL_CHILD);
 
        if (!err && data)
index a7e4939787c957a0f7975c4ea3d8aaaa390e6d2b..7f910c76ca0a340a967737345c7e733e2c4eced4 100644 (file)
@@ -1307,11 +1307,11 @@ mode_hfcpci(struct bchannel *bch, int bc, int protocol)
                }
                if (fifo2 & 2) {
                        hc->hw.fifo_en &= ~HFCPCI_FIFOEN_B2;
-                       hc->hw.int_m1 &= ~(HFCPCI_INTS_B2TRANS +
+                       hc->hw.int_m1 &= ~(HFCPCI_INTS_B2TRANS |
                                           HFCPCI_INTS_B2REC);
                } else {
                        hc->hw.fifo_en &= ~HFCPCI_FIFOEN_B1;
-                       hc->hw.int_m1 &= ~(HFCPCI_INTS_B1TRANS +
+                       hc->hw.int_m1 &= ~(HFCPCI_INTS_B1TRANS |
                                           HFCPCI_INTS_B1REC);
                }
 #ifdef REVERSE_BITORDER
@@ -1346,14 +1346,14 @@ mode_hfcpci(struct bchannel *bch, int bc, int protocol)
                if (fifo2 & 2) {
                        hc->hw.fifo_en |= HFCPCI_FIFOEN_B2;
                        if (!tics)
-                               hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS +
+                               hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS |
                                                  HFCPCI_INTS_B2REC);
                        hc->hw.ctmt |= 2;
                        hc->hw.conn &= ~0x18;
                } else {
                        hc->hw.fifo_en |= HFCPCI_FIFOEN_B1;
                        if (!tics)
-                               hc->hw.int_m1 |= (HFCPCI_INTS_B1TRANS +
+                               hc->hw.int_m1 |= (HFCPCI_INTS_B1TRANS |
                                                  HFCPCI_INTS_B1REC);
                        hc->hw.ctmt |= 1;
                        hc->hw.conn &= ~0x03;
@@ -1375,14 +1375,14 @@ mode_hfcpci(struct bchannel *bch, int bc, int protocol)
                if (fifo2 & 2) {
                        hc->hw.last_bfifo_cnt[1] = 0;
                        hc->hw.fifo_en |= HFCPCI_FIFOEN_B2;
-                       hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS +
+                       hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS |
                                          HFCPCI_INTS_B2REC);
                        hc->hw.ctmt &= ~2;
                        hc->hw.conn &= ~0x18;
                } else {
                        hc->hw.last_bfifo_cnt[0] = 0;
                        hc->hw.fifo_en |= HFCPCI_FIFOEN_B1;
-                       hc->hw.int_m1 |= (HFCPCI_INTS_B1TRANS +
+                       hc->hw.int_m1 |= (HFCPCI_INTS_B1TRANS |
                                          HFCPCI_INTS_B1REC);
                        hc->hw.ctmt &= ~1;
                        hc->hw.conn &= ~0x03;
index 0b9a79b2f48aaded2397762ce500b032f25f77e1..82fc86a90c1a436d94ab8500334b62f4cce47dbc 100644 (file)
@@ -439,15 +439,15 @@ static void backside_setup_pid(void)
 
 /* Slots fan */
 static const struct wf_pid_param slots_param = {
-       .interval       = 5,
-       .history_len    = 2,
-       .gd             = 30 << 20,
-       .gp             = 5 << 20,
-       .gr             = 0,
-       .itarget        = 40 << 16,
-       .additive       = 1,
-       .min            = 300,
-       .max            = 4000,
+       .interval       = 1,
+       .history_len    = 20,
+       .gd             = 0,
+       .gp             = 0,
+       .gr             = 0x00100000,
+       .itarget        = 3200000,
+       .additive       = 0,
+       .min            = 20,
+       .max            = 100,
 };
 
 static void slots_fan_tick(void)
index 9f13e13506efbb3859786879ed6a5ff42eb72e8f..b71d75e239008c138353474876e010e81b438b87 100644 (file)
@@ -602,9 +602,9 @@ static struct mddev * mddev_find(dev_t unit)
        goto retry;
 }
 
-static inline int mddev_lock(struct mddev * mddev)
+int md_queue_misc_work(struct work_struct *work)
 {
-       return mutex_lock_interruptible(&mddev->reconfig_mutex);
+       return queue_work(md_misc_wq, work);
 }
 
 static inline int mddev_is_locked(struct mddev *mddev)
@@ -619,7 +619,7 @@ static inline int mddev_trylock(struct mddev * mddev)
 
 static struct attribute_group md_redundancy_group;
 
-static void mddev_unlock(struct mddev * mddev)
+void mddev_unlock(struct mddev * mddev)
 {
        if (mddev->to_remove) {
                /* These cannot be removed under reconfig_mutex as
@@ -5628,10 +5628,7 @@ static int get_bitmap_file(struct mddev * mddev, void __user * arg)
        char *ptr, *buf = NULL;
        int err = -ENOMEM;
 
-       if (md_allow_write(mddev))
-               file = kmalloc(sizeof(*file), GFP_NOIO);
-       else
-               file = kmalloc(sizeof(*file), GFP_KERNEL);
+       file = kmalloc(sizeof(*file), GFP_NOIO);
 
        if (!file)
                goto out;
@@ -8681,6 +8678,8 @@ EXPORT_SYMBOL(md_unregister_thread);
 EXPORT_SYMBOL(md_wakeup_thread);
 EXPORT_SYMBOL(md_check_recovery);
 EXPORT_SYMBOL(md_reap_sync_thread);
+EXPORT_SYMBOL(mddev_unlock);
+EXPORT_SYMBOL(md_queue_misc_work);
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("MD RAID framework");
 MODULE_ALIAS("md");
index 20f02c0b5f2d6d99ac69a36067135f0b8196d9a7..77924d3a851eef729aef2aaedc28717f198c1934 100644 (file)
@@ -621,4 +621,12 @@ static inline int mddev_check_plugged(struct mddev *mddev)
        return !!blk_check_plugged(md_unplug, mddev,
                                   sizeof(struct blk_plug_cb));
 }
+
+static inline int mddev_lock(struct mddev * mddev)
+{
+       return mutex_lock_interruptible(&mddev->reconfig_mutex);
+}
+extern void mddev_unlock(struct mddev *mddev);
+extern int md_queue_misc_work(struct work_struct *work);
+
 #endif /* _MD_MD_H */
index 78ea44336e75e06d5769b4a6158f2a1e506214e0..840d0dded676e9dcf718f0dff4c7641b15776c60 100644 (file)
@@ -200,6 +200,21 @@ static int stripe_operations_active(struct stripe_head *sh)
               test_bit(STRIPE_COMPUTE_RUN, &sh->state);
 }
 
+static void raid5_wakeup_stripe_thread(struct stripe_head *sh)
+{
+       struct r5conf *conf = sh->raid_conf;
+       struct raid5_percpu *percpu;
+       int i, orphaned = 1;
+
+       percpu = per_cpu_ptr(conf->percpu, sh->cpu);
+       for_each_cpu(i, &percpu->handle_threads) {
+               md_wakeup_thread(conf->aux_threads[i]->thread);
+               orphaned = 0;
+       }
+       if (orphaned)
+               md_wakeup_thread(conf->mddev->thread);
+}
+
 static void do_release_stripe(struct r5conf *conf, struct stripe_head *sh)
 {
        BUG_ON(!list_empty(&sh->lru));
@@ -212,9 +227,19 @@ static void do_release_stripe(struct r5conf *conf, struct stripe_head *sh)
                           sh->bm_seq - conf->seq_write > 0)
                        list_add_tail(&sh->lru, &conf->bitmap_list);
                else {
+                       int cpu = sh->cpu;
+                       struct raid5_percpu *percpu;
+                       if (!cpu_online(cpu)) {
+                               cpu = cpumask_any(cpu_online_mask);
+                               sh->cpu = cpu;
+                       }
+                       percpu = per_cpu_ptr(conf->percpu, cpu);
+
                        clear_bit(STRIPE_DELAYED, &sh->state);
                        clear_bit(STRIPE_BIT_DELAY, &sh->state);
-                       list_add_tail(&sh->lru, &conf->handle_list);
+                       list_add_tail(&sh->lru, &percpu->handle_list);
+                       raid5_wakeup_stripe_thread(sh);
+                       return;
                }
                md_wakeup_thread(conf->mddev->thread);
        } else {
@@ -239,12 +264,47 @@ static void __release_stripe(struct r5conf *conf, struct stripe_head *sh)
                do_release_stripe(conf, sh);
 }
 
+/* should hold conf->device_lock already */
+static int release_stripe_list(struct r5conf *conf)
+{
+       struct stripe_head *sh;
+       int count = 0;
+       struct llist_node *head;
+
+       head = llist_del_all(&conf->released_stripes);
+       while (head) {
+               sh = llist_entry(head, struct stripe_head, release_list);
+               head = llist_next(head);
+               /* sh could be readded after STRIPE_ON_RELEASE_LIST is cleard */
+               smp_mb();
+               clear_bit(STRIPE_ON_RELEASE_LIST, &sh->state);
+               /*
+                * Don't worry the bit is set here, because if the bit is set
+                * again, the count is always > 1. This is true for
+                * STRIPE_ON_UNPLUG_LIST bit too.
+                */
+               __release_stripe(conf, sh);
+               count++;
+       }
+
+       return count;
+}
+
 static void release_stripe(struct stripe_head *sh)
 {
        struct r5conf *conf = sh->raid_conf;
        unsigned long flags;
+       bool wakeup;
 
+       if (test_and_set_bit(STRIPE_ON_RELEASE_LIST, &sh->state))
+               goto slow_path;
+       wakeup = llist_add(&sh->release_list, &conf->released_stripes);
+       if (wakeup)
+               md_wakeup_thread(conf->mddev->thread);
+       return;
+slow_path:
        local_irq_save(flags);
+       /* we are ok here if STRIPE_ON_RELEASE_LIST is set or not */
        if (atomic_dec_and_lock(&sh->count, &conf->device_lock)) {
                do_release_stripe(conf, sh);
                spin_unlock(&conf->device_lock);
@@ -359,6 +419,7 @@ static void init_stripe(struct stripe_head *sh, sector_t sector, int previous)
                raid5_build_block(sh, i, previous);
        }
        insert_hash(conf, sh);
+       sh->cpu = smp_processor_id();
 }
 
 static struct stripe_head *__find_stripe(struct r5conf *conf, sector_t sector,
@@ -491,7 +552,8 @@ get_active_stripe(struct r5conf *conf, sector_t sector,
                        if (atomic_read(&sh->count)) {
                                BUG_ON(!list_empty(&sh->lru)
                                    && !test_bit(STRIPE_EXPANDING, &sh->state)
-                                   && !test_bit(STRIPE_ON_UNPLUG_LIST, &sh->state));
+                                   && !test_bit(STRIPE_ON_UNPLUG_LIST, &sh->state)
+                                   && !test_bit(STRIPE_ON_RELEASE_LIST, &sh->state));
                        } else {
                                if (!test_bit(STRIPE_HANDLE, &sh->state))
                                        atomic_inc(&conf->active_stripes);
@@ -3773,12 +3835,19 @@ static void raid5_activate_delayed(struct r5conf *conf)
                while (!list_empty(&conf->delayed_list)) {
                        struct list_head *l = conf->delayed_list.next;
                        struct stripe_head *sh;
+                       int cpu;
                        sh = list_entry(l, struct stripe_head, lru);
                        list_del_init(l);
                        clear_bit(STRIPE_DELAYED, &sh->state);
                        if (!test_and_set_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
                                atomic_inc(&conf->preread_active_stripes);
                        list_add_tail(&sh->lru, &conf->hold_list);
+                       cpu = sh->cpu;
+                       if (!cpu_online(cpu)) {
+                               cpu = cpumask_any(cpu_online_mask);
+                               sh->cpu = cpu;
+                       }
+                       raid5_wakeup_stripe_thread(sh);
                }
        }
 }
@@ -4058,18 +4127,29 @@ static int chunk_aligned_read(struct mddev *mddev, struct bio * raid_bio)
  * head of the hold_list has changed, i.e. the head was promoted to the
  * handle_list.
  */
-static struct stripe_head *__get_priority_stripe(struct r5conf *conf)
-{
-       struct stripe_head *sh;
-
+static struct stripe_head *__get_priority_stripe(struct r5conf *conf,
+       cpumask_t *mask)
+{
+       struct stripe_head *sh = NULL, *tmp;
+       struct list_head *handle_list = NULL;
+       int cpu;
+
+       /* Should we take action to avoid starvation of latter CPUs ? */
+       for_each_cpu(cpu, mask) {
+               struct raid5_percpu *percpu = per_cpu_ptr(conf->percpu, cpu);
+               if (!list_empty(&percpu->handle_list)) {
+                       handle_list = &percpu->handle_list;
+                       break;
+               }
+       }
        pr_debug("%s: handle: %s hold: %s full_writes: %d bypass_count: %d\n",
                  __func__,
-                 list_empty(&conf->handle_list) ? "empty" : "busy",
+                 !handle_list ? "empty" : "busy",
                  list_empty(&conf->hold_list) ? "empty" : "busy",
                  atomic_read(&conf->pending_full_writes), conf->bypass_count);
 
-       if (!list_empty(&conf->handle_list)) {
-               sh = list_entry(conf->handle_list.next, typeof(*sh), lru);
+       if (handle_list) {
+               sh = list_entry(handle_list->next, typeof(*sh), lru);
 
                if (list_empty(&conf->hold_list))
                        conf->bypass_count = 0;
@@ -4087,12 +4167,23 @@ static struct stripe_head *__get_priority_stripe(struct r5conf *conf)
                   ((conf->bypass_threshold &&
                     conf->bypass_count > conf->bypass_threshold) ||
                    atomic_read(&conf->pending_full_writes) == 0)) {
-               sh = list_entry(conf->hold_list.next,
-                               typeof(*sh), lru);
-               conf->bypass_count -= conf->bypass_threshold;
-               if (conf->bypass_count < 0)
-                       conf->bypass_count = 0;
-       } else
+
+               list_for_each_entry(tmp, &conf->hold_list,  lru) {
+                       if (cpumask_test_cpu(tmp->cpu, mask) ||
+                           !cpu_online(tmp->cpu)) {
+                               sh = tmp;
+                               break;
+                       }
+               }
+
+               if (sh) {
+                       conf->bypass_count -= conf->bypass_threshold;
+                       if (conf->bypass_count < 0)
+                               conf->bypass_count = 0;
+               }
+       }
+
+       if (!sh)
                return NULL;
 
        list_del_init(&sh->lru);
@@ -4127,6 +4218,10 @@ static void raid5_unplug(struct blk_plug_cb *blk_cb, bool from_schedule)
                         */
                        smp_mb__before_clear_bit();
                        clear_bit(STRIPE_ON_UNPLUG_LIST, &sh->state);
+                       /*
+                        * STRIPE_ON_RELEASE_LIST could be set here. In that
+                        * case, the count is always > 1 here
+                        */
                        __release_stripe(conf, sh);
                        cnt++;
                }
@@ -4789,13 +4884,13 @@ static int  retry_aligned_read(struct r5conf *conf, struct bio *raid_bio)
 }
 
 #define MAX_STRIPE_BATCH 8
-static int handle_active_stripes(struct r5conf *conf)
+static int handle_active_stripes(struct r5conf *conf, cpumask_t *mask)
 {
        struct stripe_head *batch[MAX_STRIPE_BATCH], *sh;
        int i, batch_size = 0;
 
        while (batch_size < MAX_STRIPE_BATCH &&
-                       (sh = __get_priority_stripe(conf)) != NULL)
+                       (sh = __get_priority_stripe(conf, mask)) != NULL)
                batch[batch_size++] = sh;
 
        if (batch_size == 0)
@@ -4813,6 +4908,37 @@ static int handle_active_stripes(struct r5conf *conf)
        return batch_size;
 }
 
+static void raid5auxd(struct md_thread *thread)
+{
+       struct mddev *mddev = thread->mddev;
+       struct r5conf *conf = mddev->private;
+       struct blk_plug plug;
+       int handled;
+       struct raid5_auxth *auxth = thread->private;
+
+       pr_debug("+++ raid5auxd active\n");
+
+       blk_start_plug(&plug);
+       handled = 0;
+       spin_lock_irq(&conf->device_lock);
+       while (1) {
+               int batch_size, released;
+
+               released = release_stripe_list(conf);
+
+               batch_size = handle_active_stripes(conf, &auxth->work_mask);
+               if (!batch_size && !released)
+                       break;
+               handled += batch_size;
+       }
+       pr_debug("%d stripes handled\n", handled);
+
+       spin_unlock_irq(&conf->device_lock);
+       blk_finish_plug(&plug);
+
+       pr_debug("--- raid5auxd inactive\n");
+}
+
 /*
  * This is our raid5 kernel thread.
  *
@@ -4836,7 +4962,9 @@ static void raid5d(struct md_thread *thread)
        spin_lock_irq(&conf->device_lock);
        while (1) {
                struct bio *bio;
-               int batch_size;
+               int batch_size, released;
+
+               released = release_stripe_list(conf);
 
                if (
                    !list_empty(&conf->bitmap_list)) {
@@ -4860,8 +4988,8 @@ static void raid5d(struct md_thread *thread)
                        handled++;
                }
 
-               batch_size = handle_active_stripes(conf);
-               if (!batch_size)
+               batch_size = handle_active_stripes(conf, &conf->work_mask);
+               if (!batch_size && !released)
                        break;
                handled += batch_size;
 
@@ -4989,10 +5117,270 @@ stripe_cache_active_show(struct mddev *mddev, char *page)
 static struct md_sysfs_entry
 raid5_stripecache_active = __ATTR_RO(stripe_cache_active);
 
+static void raid5_update_threads_handle_mask(struct mddev *mddev)
+{
+       int cpu, i;
+       struct raid5_percpu *percpu;
+       struct r5conf *conf = mddev->private;
+
+       for_each_online_cpu(cpu) {
+               percpu = per_cpu_ptr(conf->percpu, cpu);
+               cpumask_clear(&percpu->handle_threads);
+       }
+       cpumask_copy(&conf->work_mask, cpu_online_mask);
+
+       for (i = 0; i < conf->aux_thread_num; i++) {
+               cpumask_t *work_mask = &conf->aux_threads[i]->work_mask;
+               for_each_cpu(cpu, work_mask) {
+                       percpu = per_cpu_ptr(conf->percpu, cpu);
+                       cpumask_set_cpu(i, &percpu->handle_threads);
+               }
+               cpumask_andnot(&conf->work_mask, &conf->work_mask,
+                               work_mask);
+       }
+}
+
+struct raid5_auxth_sysfs {
+       struct attribute attr;
+       ssize_t (*show)(struct mddev *, struct raid5_auxth *, char *);
+       ssize_t (*store)(struct mddev *, struct raid5_auxth *,
+               const char *, size_t);
+};
+
+static ssize_t raid5_show_thread_cpulist(struct mddev *mddev,
+       struct raid5_auxth *thread, char *page)
+{
+       if (!mddev->private)
+               return 0;
+       return cpulist_scnprintf(page, PAGE_SIZE, &thread->work_mask);
+}
+
+static ssize_t
+raid5_store_thread_cpulist(struct mddev *mddev, struct raid5_auxth *thread,
+       const char *page, size_t len)
+{
+       struct r5conf *conf = mddev->private;
+       cpumask_var_t mask;
+
+       if (!conf)
+               return -ENODEV;
+       if (!alloc_cpumask_var(&mask, GFP_KERNEL))
+               return -ENOMEM;
+
+       if (cpulist_parse(page, mask)) {
+               free_cpumask_var(mask);
+               return -EINVAL;
+       }
+
+       get_online_cpus();
+       spin_lock_irq(&conf->device_lock);
+       cpumask_copy(&thread->work_mask, mask);
+       raid5_update_threads_handle_mask(mddev);
+       spin_unlock_irq(&conf->device_lock);
+       put_online_cpus();
+       set_cpus_allowed_ptr(thread->thread->tsk, mask);
+
+       free_cpumask_var(mask);
+       return len;
+}
+
+static struct raid5_auxth_sysfs thread_cpulist =
+__ATTR(cpulist, S_IRUGO|S_IWUSR, raid5_show_thread_cpulist,
+       raid5_store_thread_cpulist);
+
+static struct attribute *auxth_attrs[] = {
+       &thread_cpulist.attr,
+       NULL,
+};
+
+static ssize_t
+raid5_auxth_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
+{
+       struct raid5_auxth_sysfs *entry = container_of(attr,
+               struct raid5_auxth_sysfs, attr);
+       struct raid5_auxth *thread = container_of(kobj,
+               struct raid5_auxth, kobj);
+       struct mddev *mddev = thread->thread->mddev;
+       ssize_t ret;
+
+       if (!entry->show)
+               return -EIO;
+       mddev_lock(mddev);
+       ret = entry->show(mddev, thread, page);
+       mddev_unlock(mddev);
+       return ret;
+}
+
+static ssize_t
+raid5_auxth_attr_store(struct kobject *kobj, struct attribute *attr,
+             const char *page, size_t length)
+{
+       struct raid5_auxth_sysfs *entry = container_of(attr,
+               struct raid5_auxth_sysfs, attr);
+       struct raid5_auxth *thread = container_of(kobj,
+               struct raid5_auxth, kobj);
+       struct mddev *mddev = thread->thread->mddev;
+       ssize_t ret;
+
+       if (!entry->store)
+               return -EIO;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EACCES;
+       mddev_lock(mddev);
+       ret = entry->store(mddev, thread, page, length);
+       mddev_unlock(mddev);
+       return ret;
+}
+
+static void raid5_auxth_release(struct kobject *kobj)
+{
+       struct raid5_auxth *thread = container_of(kobj,
+               struct raid5_auxth, kobj);
+       kfree(thread);
+}
+
+static const struct sysfs_ops raid5_auxth_sysfsops = {
+       .show = raid5_auxth_attr_show,
+       .store = raid5_auxth_attr_store,
+};
+static struct kobj_type raid5_auxth_ktype = {
+       .release = raid5_auxth_release,
+       .sysfs_ops = &raid5_auxth_sysfsops,
+       .default_attrs = auxth_attrs,
+};
+
+static ssize_t
+raid5_show_auxthread_number(struct mddev *mddev, char *page)
+{
+       struct r5conf *conf = mddev->private;
+       if (conf)
+               return sprintf(page, "%d\n", conf->aux_thread_num);
+       else
+               return 0;
+}
+
+static void raid5_auxth_delete(struct work_struct *ws)
+{
+       struct raid5_auxth *thread = container_of(ws, struct raid5_auxth,
+               del_work);
+
+       kobject_del(&thread->kobj);
+       kobject_put(&thread->kobj);
+}
+
+static void __free_aux_thread(struct mddev *mddev, struct raid5_auxth *thread)
+{
+       md_unregister_thread(&thread->thread);
+       INIT_WORK(&thread->del_work, raid5_auxth_delete);
+       kobject_get(&thread->kobj);
+       md_queue_misc_work(&thread->del_work);
+}
+
+static struct raid5_auxth *__create_aux_thread(struct mddev *mddev, int i)
+{
+       struct raid5_auxth *thread;
+       char name[10];
+
+       thread = kzalloc(sizeof(*thread), GFP_KERNEL);
+       if (!thread)
+               return NULL;
+       snprintf(name, 10, "aux%d", i);
+       thread->thread = md_register_thread(raid5auxd, mddev, name);
+       if (!thread->thread) {
+               kfree(thread);
+               return NULL;
+       }
+       thread->thread->private = thread;
+
+       cpumask_copy(&thread->work_mask, cpu_online_mask);
+
+       if (kobject_init_and_add(&thread->kobj, &raid5_auxth_ktype,
+           &mddev->kobj, "auxth%d", i)) {
+               md_unregister_thread(&thread->thread);
+               kfree(thread);
+               return NULL;
+       }
+       return thread;
+}
+
+static ssize_t
+raid5_store_auxthread_number(struct mddev *mddev, const char *page, size_t len)
+{
+       struct r5conf *conf = mddev->private;
+       unsigned long new;
+       int i;
+       struct raid5_auxth **threads;
+
+       if (len >= PAGE_SIZE)
+               return -EINVAL;
+       if (!conf)
+               return -ENODEV;
+
+       if (kstrtoul(page, 10, &new))
+               return -EINVAL;
+
+       if (new == conf->aux_thread_num)
+               return len;
+
+       /* There is no point creating more threads than cpu number */
+       if (new > num_online_cpus())
+               return -EINVAL;
+
+       if (new > conf->aux_thread_num) {
+               threads = kzalloc(sizeof(struct raid5_auxth *) * new,
+                               GFP_KERNEL);
+               if (!threads)
+                       return -ENOMEM;
+
+               i = conf->aux_thread_num;
+               while (i < new) {
+                       threads[i] = __create_aux_thread(mddev, i);
+                       if (!threads[i])
+                               goto error;
+
+                       i++;
+               }
+               memcpy(threads, conf->aux_threads,
+                       sizeof(struct raid5_auxth *) * conf->aux_thread_num);
+               get_online_cpus();
+               spin_lock_irq(&conf->device_lock);
+               kfree(conf->aux_threads);
+               conf->aux_threads = threads;
+               conf->aux_thread_num = new;
+               raid5_update_threads_handle_mask(mddev);
+               spin_unlock_irq(&conf->device_lock);
+               put_online_cpus();
+       } else {
+               int old = conf->aux_thread_num;
+
+               get_online_cpus();
+               spin_lock_irq(&conf->device_lock);
+               conf->aux_thread_num = new;
+               raid5_update_threads_handle_mask(mddev);
+               spin_unlock_irq(&conf->device_lock);
+               put_online_cpus();
+               for (i = new; i < old; i++)
+                       __free_aux_thread(mddev, conf->aux_threads[i]);
+       }
+
+       return len;
+error:
+       while (--i >= conf->aux_thread_num)
+               __free_aux_thread(mddev, threads[i]);
+       kfree(threads);
+       return -ENOMEM;
+}
+
+static struct md_sysfs_entry
+raid5_auxthread_number = __ATTR(auxthread_number, S_IRUGO|S_IWUSR,
+                               raid5_show_auxthread_number,
+                               raid5_store_auxthread_number);
+
 static struct attribute *raid5_attrs[] =  {
        &raid5_stripecache_size.attr,
        &raid5_stripecache_active.attr,
        &raid5_preread_bypass_threshold.attr,
+       &raid5_auxthread_number.attr,
        NULL,
 };
 static struct attribute_group raid5_attrs_group = {
@@ -5040,6 +5428,7 @@ static void raid5_free_percpu(struct r5conf *conf)
 
 static void free_conf(struct r5conf *conf)
 {
+       kfree(conf->aux_threads);
        shrink_stripes(conf);
        raid5_free_percpu(conf);
        kfree(conf->disks);
@@ -5052,7 +5441,7 @@ static int raid456_cpu_notify(struct notifier_block *nfb, unsigned long action,
                              void *hcpu)
 {
        struct r5conf *conf = container_of(nfb, struct r5conf, cpu_notify);
-       long cpu = (long)hcpu;
+       long cpu = (long)hcpu, anycpu;
        struct raid5_percpu *percpu = per_cpu_ptr(conf->percpu, cpu);
 
        switch (action) {
@@ -5071,9 +5460,17 @@ static int raid456_cpu_notify(struct notifier_block *nfb, unsigned long action,
                               __func__, cpu);
                        return notifier_from_errno(-ENOMEM);
                }
+               INIT_LIST_HEAD(&(percpu->handle_list));
+               cpumask_clear(&percpu->handle_threads);
                break;
        case CPU_DEAD:
        case CPU_DEAD_FROZEN:
+               spin_lock_irq(&conf->device_lock);
+               anycpu = cpumask_any(cpu_online_mask);
+               list_splice_tail_init(&percpu->handle_list,
+                       &per_cpu_ptr(conf->percpu, anycpu)->handle_list);
+               spin_unlock_irq(&conf->device_lock);
+
                safe_put_page(percpu->spare_page);
                kfree(percpu->scribble);
                percpu->spare_page = NULL;
@@ -5082,6 +5479,10 @@ static int raid456_cpu_notify(struct notifier_block *nfb, unsigned long action,
        default:
                break;
        }
+
+       spin_lock_irq(&conf->device_lock);
+       raid5_update_threads_handle_mask(conf->mddev);
+       spin_unlock_irq(&conf->device_lock);
        return NOTIFY_OK;
 }
 #endif
@@ -5102,20 +5503,24 @@ static int raid5_alloc_percpu(struct r5conf *conf)
        get_online_cpus();
        err = 0;
        for_each_present_cpu(cpu) {
+               struct raid5_percpu *percpu = per_cpu_ptr(conf->percpu, cpu);
+
                if (conf->level == 6) {
                        spare_page = alloc_page(GFP_KERNEL);
                        if (!spare_page) {
                                err = -ENOMEM;
                                break;
                        }
-                       per_cpu_ptr(conf->percpu, cpu)->spare_page = spare_page;
+                       percpu->spare_page = spare_page;
                }
                scribble = kmalloc(conf->scribble_len, GFP_KERNEL);
                if (!scribble) {
                        err = -ENOMEM;
                        break;
                }
-               per_cpu_ptr(conf->percpu, cpu)->scribble = scribble;
+               percpu->scribble = scribble;
+               INIT_LIST_HEAD(&percpu->handle_list);
+               cpumask_clear(&percpu->handle_threads);
        }
 #ifdef CONFIG_HOTPLUG_CPU
        conf->cpu_notify.notifier_call = raid456_cpu_notify;
@@ -5171,17 +5576,19 @@ static struct r5conf *setup_conf(struct mddev *mddev)
        spin_lock_init(&conf->device_lock);
        init_waitqueue_head(&conf->wait_for_stripe);
        init_waitqueue_head(&conf->wait_for_overlap);
-       INIT_LIST_HEAD(&conf->handle_list);
        INIT_LIST_HEAD(&conf->hold_list);
        INIT_LIST_HEAD(&conf->delayed_list);
        INIT_LIST_HEAD(&conf->bitmap_list);
        INIT_LIST_HEAD(&conf->inactive_list);
+       init_llist_head(&conf->released_stripes);
        atomic_set(&conf->active_stripes, 0);
        atomic_set(&conf->preread_active_stripes, 0);
        atomic_set(&conf->active_aligned_reads, 0);
        conf->bypass_threshold = BYPASS_THRESHOLD;
        conf->recovery_disabled = mddev->recovery_disabled - 1;
 
+       cpumask_copy(&conf->work_mask, cpu_online_mask);
+
        conf->raid_disks = mddev->raid_disks;
        if (mddev->reshape_position == MaxSector)
                conf->previous_raid_disks = mddev->raid_disks;
@@ -5640,6 +6047,10 @@ abort:
 static int stop(struct mddev *mddev)
 {
        struct r5conf *conf = mddev->private;
+       int i;
+
+       for (i = 0; i < conf->aux_thread_num; i++)
+               __free_aux_thread(mddev, conf->aux_threads[i]);
 
        md_unregister_thread(&mddev->thread);
        if (mddev->queue)
index 70c49329ca9a23fbbad73061477ac0a0cfe80e6e..04540f302480332d364dccda2488a8c791e7270e 100644 (file)
@@ -197,6 +197,7 @@ enum reconstruct_states {
 struct stripe_head {
        struct hlist_node       hash;
        struct list_head        lru;          /* inactive_list or handle_list */
+       struct llist_node       release_list;
        struct r5conf           *raid_conf;
        short                   generation;     /* increments with every
                                                 * reshape */
@@ -211,6 +212,7 @@ struct stripe_head {
        enum check_states       check_state;
        enum reconstruct_states reconstruct_state;
        spinlock_t              stripe_lock;
+       int                     cpu;
        /**
         * struct stripe_operations
         * @target - STRIPE_OP_COMPUTE_BLK target
@@ -321,6 +323,7 @@ enum {
        STRIPE_OPS_REQ_PENDING,
        STRIPE_ON_UNPLUG_LIST,
        STRIPE_DISCARD,
+       STRIPE_ON_RELEASE_LIST,
 };
 
 /*
@@ -363,6 +366,14 @@ struct disk_info {
        struct md_rdev  *rdev, *replacement;
 };
 
+struct raid5_auxth {
+       struct md_thread        *thread;
+       /* which CPUs should the auxiliary thread handle stripes from */
+       cpumask_t               work_mask;
+       struct kobject          kobj;
+       struct work_struct      del_work;
+};
+
 struct r5conf {
        struct hlist_head       *stripe_hashtbl;
        struct mddev            *mddev;
@@ -431,6 +442,12 @@ struct r5conf {
                                              * lists and performing address
                                              * conversions
                                              */
+               struct list_head handle_list;
+               cpumask_t       handle_threads; /* Which threads can the CPU's
+                                                * stripes be handled. It really
+                                                * is a bitmap to aux_threads[],
+                                                * but has max bits NR_CPUS
+                                                */
        } __percpu *percpu;
        size_t                  scribble_len; /* size of scribble region must be
                                               * associated with conf to handle
@@ -445,6 +462,7 @@ struct r5conf {
         */
        atomic_t                active_stripes;
        struct list_head        inactive_list;
+       struct llist_head       released_stripes;
        wait_queue_head_t       wait_for_stripe;
        wait_queue_head_t       wait_for_overlap;
        int                     inactive_blocked;       /* release of inactive stripes blocked,
@@ -458,6 +476,10 @@ struct r5conf {
         * the new thread here until we fully activate the array.
         */
        struct md_thread        *thread;
+       int                     aux_thread_num;
+       struct raid5_auxth      **aux_threads;
+       /* which CPUs should raid5d thread handle stripes from */
+       cpumask_t               work_mask;
 };
 
 /*
index 886da16e14f23e16c0ef12c8b5a9e225e76820b0..419a2d6b43491d505fd386dd3468064f165ee1ff 100644 (file)
 #define USB_PID_TECHNISAT_USB2_DVB_S2                  0x0500
 #define USB_PID_CPYTO_REDI_PC50A                       0xa803
 #define USB_PID_CTVDIGDUAL_V2                          0xe410
+#define USB_PID_PCTV_2002E                              0x025c
+#define USB_PID_PCTV_2002E_SE                           0x025d
 #endif
index 7606218ec4a760bb14bd5fcfbe0813e480f89466..aeb56c53e39f563dea2768c005f2df33ad90df6c 100644 (file)
 #include <linux/uaccess.h>
 
 #include <media/adv7343.h>
+#include <media/v4l2-async.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
+#include <media/v4l2-of.h>
 
 #include "adv7343_regs.h"
 
@@ -226,12 +228,12 @@ static int adv7343_setoutput(struct v4l2_subdev *sd, u32 output_type)
        else
                val = state->pdata->mode_config.sleep_mode << 0 |
                      state->pdata->mode_config.pll_control << 1 |
-                     state->pdata->mode_config.dac_3 << 2 |
-                     state->pdata->mode_config.dac_2 << 3 |
-                     state->pdata->mode_config.dac_1 << 4 |
-                     state->pdata->mode_config.dac_6 << 5 |
-                     state->pdata->mode_config.dac_5 << 6 |
-                     state->pdata->mode_config.dac_4 << 7;
+                     state->pdata->mode_config.dac[2] << 2 |
+                     state->pdata->mode_config.dac[1] << 3 |
+                     state->pdata->mode_config.dac[0] << 4 |
+                     state->pdata->mode_config.dac[5] << 5 |
+                     state->pdata->mode_config.dac[4] << 6 |
+                     state->pdata->mode_config.dac[3] << 7;
 
        err = adv7343_write(sd, ADV7343_POWER_MODE_REG, val);
        if (err < 0)
@@ -250,15 +252,15 @@ static int adv7343_setoutput(struct v4l2_subdev *sd, u32 output_type)
        /* configure SD DAC Output 2 and SD DAC Output 1 bit to zero */
        val = state->reg82 & (SD_DAC_1_DI & SD_DAC_2_DI);
 
-       if (state->pdata && state->pdata->sd_config.sd_dac_out1)
-               val = val | (state->pdata->sd_config.sd_dac_out1 << 1);
-       else if (state->pdata && !state->pdata->sd_config.sd_dac_out1)
-               val = val & ~(state->pdata->sd_config.sd_dac_out1 << 1);
+       if (state->pdata && state->pdata->sd_config.sd_dac_out[0])
+               val = val | (state->pdata->sd_config.sd_dac_out[0] << 1);
+       else if (state->pdata && !state->pdata->sd_config.sd_dac_out[0])
+               val = val & ~(state->pdata->sd_config.sd_dac_out[0] << 1);
 
-       if (state->pdata && state->pdata->sd_config.sd_dac_out2)
-               val = val | (state->pdata->sd_config.sd_dac_out2 << 2);
-       else if (state->pdata && !state->pdata->sd_config.sd_dac_out2)
-               val = val & ~(state->pdata->sd_config.sd_dac_out2 << 2);
+       if (state->pdata && state->pdata->sd_config.sd_dac_out[1])
+               val = val | (state->pdata->sd_config.sd_dac_out[1] << 2);
+       else if (state->pdata && !state->pdata->sd_config.sd_dac_out[1])
+               val = val & ~(state->pdata->sd_config.sd_dac_out[1] << 2);
 
        err = adv7343_write(sd, ADV7343_SD_MODE_REG2, val);
        if (err < 0)
@@ -398,6 +400,40 @@ static int adv7343_initialize(struct v4l2_subdev *sd)
        return err;
 }
 
+static struct adv7343_platform_data *
+adv7343_get_pdata(struct i2c_client *client)
+{
+       struct adv7343_platform_data *pdata;
+       struct device_node *np;
+
+       if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
+               return client->dev.platform_data;
+
+       np = v4l2_of_get_next_endpoint(client->dev.of_node, NULL);
+       if (!np)
+               return NULL;
+
+       pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               goto done;
+
+       pdata->mode_config.sleep_mode =
+                       of_property_read_bool(np, "adi,power-mode-sleep-mode");
+
+       pdata->mode_config.pll_control =
+                       of_property_read_bool(np, "adi,power-mode-pll-ctrl");
+
+       of_property_read_u32_array(np, "adi,dac-enable",
+                                  pdata->mode_config.dac, 6);
+
+       of_property_read_u32_array(np, "adi,sd-dac-enable",
+                                  pdata->sd_config.sd_dac_out, 2);
+
+done:
+       of_node_put(np);
+       return pdata;
+}
+
 static int adv7343_probe(struct i2c_client *client,
                                const struct i2c_device_id *id)
 {
@@ -416,7 +452,7 @@ static int adv7343_probe(struct i2c_client *client,
                return -ENOMEM;
 
        /* Copy board specific information here */
-       state->pdata = client->dev.platform_data;
+       state->pdata = adv7343_get_pdata(client);
 
        state->reg00    = 0x80;
        state->reg01    = 0x00;
@@ -445,16 +481,21 @@ static int adv7343_probe(struct i2c_client *client,
                                       ADV7343_GAIN_DEF);
        state->sd.ctrl_handler = &state->hdl;
        if (state->hdl.error) {
-               int err = state->hdl.error;
-
-               v4l2_ctrl_handler_free(&state->hdl);
-               return err;
+               err = state->hdl.error;
+               goto done;
        }
        v4l2_ctrl_handler_setup(&state->hdl);
 
        err = adv7343_initialize(&state->sd);
        if (err)
+               goto done;
+
+       err = v4l2_async_register_subdev(&state->sd);
+
+done:
+       if (err < 0)
                v4l2_ctrl_handler_free(&state->hdl);
+
        return err;
 }
 
@@ -463,6 +504,7 @@ static int adv7343_remove(struct i2c_client *client)
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
        struct adv7343_state *state = to_state(sd);
 
+       v4l2_async_unregister_subdev(&state->sd);
        v4l2_device_unregister_subdev(sd);
        v4l2_ctrl_handler_free(&state->hdl);
 
@@ -476,8 +518,17 @@ static const struct i2c_device_id adv7343_id[] = {
 
 MODULE_DEVICE_TABLE(i2c, adv7343_id);
 
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id adv7343_of_match[] = {
+       {.compatible = "adi,adv7343", },
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, adv7343_of_match);
+#endif
+
 static struct i2c_driver adv7343_driver = {
        .driver = {
+               .of_match_table = of_match_ptr(adv7343_of_match),
                .owner  = THIS_MODULE,
                .name   = "adv7343",
        },
index efdc873e58d122d322d53a3876f88a46f4ddb04f..a9110d8bbbcd684e691ac63199d6fbb6c1902b95 100644 (file)
@@ -117,7 +117,7 @@ static int ml86v7667_s_ctrl(struct v4l2_ctrl *ctrl)
 {
        struct v4l2_subdev *sd = to_sd(ctrl);
        struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret;
+       int ret = -EINVAL;
 
        switch (ctrl->id) {
        case V4L2_CID_BRIGHTNESS:
@@ -157,7 +157,7 @@ static int ml86v7667_s_ctrl(struct v4l2_ctrl *ctrl)
                break;
        }
 
-       return 0;
+       return ret;
 }
 
 static int ml86v7667_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
@@ -209,7 +209,8 @@ static int ml86v7667_mbus_fmt(struct v4l2_subdev *sd,
 
        fmt->code = V4L2_MBUS_FMT_YUYV8_2X8;
        fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
-       fmt->field = V4L2_FIELD_INTERLACED;
+       /* The top field is always transferred first by the chip */
+       fmt->field = V4L2_FIELD_INTERLACED_TB;
        fmt->width = 720;
        fmt->height = priv->std & V4L2_STD_525_60 ? 480 : 576;
 
index a24f90c5261c5f149ca517f13be0b84e6cf19132..8a29810d155a1b50f13838ae14184ed131cf5562 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/module.h>
 #include <linux/v4l2-dv-timings.h>
 
+#include <media/v4l2-async.h>
 #include <media/v4l2-device.h>
 
 #include "ths8200_regs.h"
@@ -500,6 +501,7 @@ static int ths8200_probe(struct i2c_client *client,
 {
        struct ths8200_state *state;
        struct v4l2_subdev *sd;
+       int error;
 
        /* Check if the adapter supports the needed features */
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -517,6 +519,10 @@ static int ths8200_probe(struct i2c_client *client,
 
        ths8200_core_init(sd);
 
+       error = v4l2_async_register_subdev(&state->sd);
+       if (error)
+               return error;
+
        v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name,
                  client->addr << 1, client->adapter->name);
 
@@ -526,12 +532,13 @@ static int ths8200_probe(struct i2c_client *client,
 static int ths8200_remove(struct i2c_client *client)
 {
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct ths8200_state *decoder = to_state(sd);
 
        v4l2_dbg(1, debug, sd, "%s removed @ 0x%x (%s)\n", client->name,
                 client->addr << 1, client->adapter->name);
 
        ths8200_s_power(sd, false);
-
+       v4l2_async_unregister_subdev(&decoder->sd);
        v4l2_device_unregister_subdev(sd);
 
        return 0;
@@ -543,10 +550,19 @@ static struct i2c_device_id ths8200_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, ths8200_id);
 
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id ths8200_of_match[] = {
+       { .compatible = "ti,ths8200", },
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, ths8200_of_match);
+#endif
+
 static struct i2c_driver ths8200_driver = {
        .driver = {
                .owner = THIS_MODULE,
                .name = "ths8200",
+               .of_match_table = of_match_ptr(ths8200_of_match),
        },
        .probe = ths8200_probe,
        .remove = ths8200_remove,
index 9c6d66a9868f7ac30955dd369340012f6d74084e..91f3dd4cda1b66926ac9ac77e50e17ee30579160 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/module.h>
 #include <linux/v4l2-mediabus.h>
 
+#include <media/v4l2-async.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-mediabus.h>
@@ -1175,16 +1176,22 @@ tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
        sd->ctrl_handler = &decoder->hdl;
        if (decoder->hdl.error) {
                ret = decoder->hdl.error;
-
-               v4l2_ctrl_handler_free(&decoder->hdl);
-               return ret;
+               goto done;
        }
        v4l2_ctrl_handler_setup(&decoder->hdl);
 
-       v4l2_info(sd, "%s decoder driver registered !!\n", sd->name);
-
-       return 0;
+       ret = v4l2_async_register_subdev(&decoder->sd);
+       if (!ret)
+               v4l2_info(sd, "%s decoder driver registered !!\n", sd->name);
 
+done:
+       if (ret < 0) {
+               v4l2_ctrl_handler_free(&decoder->hdl);
+#if defined(CONFIG_MEDIA_CONTROLLER)
+               media_entity_cleanup(&decoder->sd.entity);
+#endif
+       }
+       return ret;
 }
 
 /**
@@ -1199,6 +1206,7 @@ static int tvp514x_remove(struct i2c_client *client)
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
        struct tvp514x_decoder *decoder = to_decoder(sd);
 
+       v4l2_async_unregister_subdev(&decoder->sd);
        v4l2_device_unregister_subdev(sd);
 #if defined(CONFIG_MEDIA_CONTROLLER)
        media_entity_cleanup(&decoder->sd.entity);
index a4e49483de6a2f0e77820591c85e114f603d090e..f6b1f3fe2608a7f789444de2543c6c81ecf1b392 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/module.h>
 #include <linux/v4l2-dv-timings.h>
 #include <media/tvp7002.h>
+#include <media/v4l2-async.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ctrls.h>
@@ -1039,6 +1040,10 @@ static int tvp7002_probe(struct i2c_client *c, const struct i2c_device_id *id)
        }
        v4l2_ctrl_handler_setup(&device->hdl);
 
+       error = v4l2_async_register_subdev(&device->sd);
+       if (error)
+               goto error;
+
        return 0;
 
 error:
@@ -1063,6 +1068,7 @@ static int tvp7002_remove(struct i2c_client *c)
 
        v4l2_dbg(1, debug, sd, "Removing tvp7002 adapter"
                                "on address 0x%x\n", c->addr);
+       v4l2_async_unregister_subdev(&device->sd);
 #if defined(CONFIG_MEDIA_CONTROLLER)
        media_entity_cleanup(&device->sd.entity);
 #endif
index e564aac0aa30fc67ee3eeb9cca5ea7f2dabdf6d5..d85cb0ace4dc654b541017a38fde5e0e004f3b1e 100644 (file)
@@ -4441,9 +4441,7 @@ static void tibetCS16_init(struct bttv *btv)
  * is {3, 0, 2, 1}, i.e. the first controller to be detected is logical
  * unit 3, the second (which is the master) is logical unit 0, etc.
  * We need to maintain the status of the analog switch (which of the 16
- * cameras is connected to which of the 4 controllers).  Rather than
- * add to the bttv structure for this, we use the data reserved for
- * the mbox (unused for this card type).
+ * cameras is connected to which of the 4 controllers) in sw_status array.
  */
 
 /*
@@ -4478,7 +4476,6 @@ static void kodicom4400r_write(struct bttv *btv,
  */
 static void kodicom4400r_muxsel(struct bttv *btv, unsigned int input)
 {
-       char *sw_status;
        int xaddr, yaddr;
        struct bttv *mctlr;
        static unsigned char map[4] = {3, 0, 2, 1};
@@ -4489,14 +4486,13 @@ static void kodicom4400r_muxsel(struct bttv *btv, unsigned int input)
        }
        yaddr = (btv->c.nr - mctlr->c.nr + 1) & 3; /* the '&' is for safety */
        yaddr = map[yaddr];
-       sw_status = (char *)(&mctlr->mbox_we);
        xaddr = input & 0xf;
        /* Check if the controller/camera pair has changed, else ignore */
-       if (sw_status[yaddr] != xaddr)
+       if (mctlr->sw_status[yaddr] != xaddr)
        {
                /* "open" the old switch, "close" the new one, save the new */
-               kodicom4400r_write(mctlr, sw_status[yaddr], yaddr, 0);
-               sw_status[yaddr] = xaddr;
+               kodicom4400r_write(mctlr, mctlr->sw_status[yaddr], yaddr, 0);
+               mctlr->sw_status[yaddr] = xaddr;
                kodicom4400r_write(mctlr, xaddr, yaddr, 1);
        }
 }
@@ -4509,7 +4505,6 @@ static void kodicom4400r_muxsel(struct bttv *btv, unsigned int input)
  */
 static void kodicom4400r_init(struct bttv *btv)
 {
-       char *sw_status = (char *)(&btv->mbox_we);
        int ix;
 
        gpio_inout(0x0003ff, 0x0003ff);
@@ -4517,7 +4512,7 @@ static void kodicom4400r_init(struct bttv *btv)
        gpio_write(0);
        /* Preset camera 0 to the 4 controllers */
        for (ix = 0; ix < 4; ix++) {
-               sw_status[ix] = ix;
+               btv->sw_status[ix] = ix;
                kodicom4400r_write(btv, ix, ix, 1);
        }
        /*
@@ -4794,7 +4789,6 @@ static void gv800s_write(struct bttv *btv,
 static void gv800s_muxsel(struct bttv *btv, unsigned int input)
 {
        struct bttv *mctlr;
-       char *sw_status;
        int xaddr, yaddr;
        static unsigned int map[4][4] = { { 0x0, 0x4, 0xa, 0x6 },
                                          { 0x1, 0x5, 0xb, 0x7 },
@@ -4807,14 +4801,13 @@ static void gv800s_muxsel(struct bttv *btv, unsigned int input)
                return;
        }
        yaddr = (btv->c.nr - mctlr->c.nr) & 3;
-       sw_status = (char *)(&mctlr->mbox_we);
        xaddr = map[yaddr][input] & 0xf;
 
        /* Check if the controller/camera pair has changed, ignore otherwise */
-       if (sw_status[yaddr] != xaddr) {
+       if (mctlr->sw_status[yaddr] != xaddr) {
                /* disable the old switch, enable the new one and save status */
-               gv800s_write(mctlr, sw_status[yaddr], yaddr, 0);
-               sw_status[yaddr] = xaddr;
+               gv800s_write(mctlr, mctlr->sw_status[yaddr], yaddr, 0);
+               mctlr->sw_status[yaddr] = xaddr;
                gv800s_write(mctlr, xaddr, yaddr, 1);
        }
 }
@@ -4822,7 +4815,6 @@ static void gv800s_muxsel(struct bttv *btv, unsigned int input)
 /* GeoVision GV-800(S) "master" chip init */
 static void gv800s_init(struct bttv *btv)
 {
-       char *sw_status = (char *)(&btv->mbox_we);
        int ix;
 
        gpio_inout(0xf107f, 0xf107f);
@@ -4831,7 +4823,7 @@ static void gv800s_init(struct bttv *btv)
 
        /* Preset camera 0 to the 4 controllers */
        for (ix = 0; ix < 4; ix++) {
-               sw_status[ix] = ix;
+               btv->sw_status[ix] = ix;
                gv800s_write(btv, ix, ix, 1);
        }
 
index 9c1cc2c50ee2abc9ef916dd3bf922ae5ab9505d5..6eefb595d0fa67509620627ed0b755ffa2747cfe 100644 (file)
@@ -459,6 +459,9 @@ struct bttv {
        int mbox_iow;
        int mbox_csel;
 
+       /* switch status for multi-controller cards */
+       char sw_status[4];
+
        /* risc memory management data
           - must acquire s_lock before changing these
           - only the irq handler is supported to touch top + bottom + vcurr */
index e958a01fd554c27ec8b8be330bffbc0749ebb044..c443b7ac5adfeb29806fd0cc345ac9b8d64c0c16 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "cx23885.h"
 #include "cx23885-av.h"
+#include "cx23885-video.h"
 
 void cx23885_av_work_handler(struct work_struct *work)
 {
@@ -32,5 +33,17 @@ void cx23885_av_work_handler(struct work_struct *work)
 
        v4l2_subdev_call(dev->sd_cx25840, core, interrupt_service_routine,
                         PCI_MSK_AV_CORE, &handled);
+
+       /* Getting here with the interrupt not handled
+          then probbaly flatiron does have pending interrupts.
+       */
+       if (!handled) {
+               /* clear left and right adc channel interrupt request flag */
+               cx23885_flatiron_write(dev, 0x1f,
+                       cx23885_flatiron_read(dev, 0x1f) | 0x80);
+               cx23885_flatiron_write(dev, 0x23,
+                       cx23885_flatiron_read(dev, 0x23) | 0x80);
+       }
+
        cx23885_irq_enable(dev, PCI_MSK_AV_CORE);
 }
index 9c5ed10b2c5eb8e5d1c03897d2bf5813f68a41fa..bb291c661143b501bc2523b3df484752c40fc8cc 100644 (file)
@@ -1249,6 +1249,10 @@ static int dvb_register(struct cx23885_tsport *port)
                fe0->dvb.frontend = dvb_attach(ds3000_attach,
                                        &tevii_ds3000_config,
                                        &i2c_bus->i2c_adap);
+               if (fe0->dvb.frontend != NULL) {
+                       dvb_attach(ts2020_attach, fe0->dvb.frontend,
+                               &tevii_ts2020_config, &i2c_bus->i2c_adap);
+               }
                break;
        case CX23885_BOARD_PROF_8000:
                i2c_bus = &dev->i2c_bus[0];
index e33d1a7dfdd09ee253e2d8160bdc31206f292c2b..161686832b2046c173756953485cda329c77b2c6 100644 (file)
@@ -32,6 +32,7 @@
 #include <asm/div64.h>
 
 #include "cx23885.h"
+#include "cx23885-video.h"
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include "cx23885-ioctl.h"
@@ -417,7 +418,7 @@ static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh,
        mutex_unlock(&dev->lock);
 }
 
-static int cx23885_flatiron_write(struct cx23885_dev *dev, u8 reg, u8 data)
+int cx23885_flatiron_write(struct cx23885_dev *dev, u8 reg, u8 data)
 {
        /* 8 bit registers, 8 bit values */
        u8 buf[] = { reg, data };
@@ -428,7 +429,7 @@ static int cx23885_flatiron_write(struct cx23885_dev *dev, u8 reg, u8 data)
        return i2c_transfer(&dev->i2c_bus[2].i2c_adap, &msg, 1);
 }
 
-static u8 cx23885_flatiron_read(struct cx23885_dev *dev, u8 reg)
+u8 cx23885_flatiron_read(struct cx23885_dev *dev, u8 reg)
 {
        /* 8 bit registers, 8 bit values */
        int ret;
diff --git a/drivers/media/pci/cx23885/cx23885-video.h b/drivers/media/pci/cx23885/cx23885-video.h
new file mode 100644 (file)
index 0000000..c961a2b
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ *  Driver for the Conexant CX23885/7/8 PCIe bridge
+ *
+ *  Copyright (C) 2010  Andy Walls <awalls@md.metrocast.net>
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+#ifndef _CX23885_VIDEO_H_
+#define _CX23885_VIDEO_H_
+int cx23885_flatiron_write(struct cx23885_dev *dev, u8 reg, u8 data);
+u8 cx23885_flatiron_read(struct cx23885_dev *dev, u8 reg);
+#endif
index df4ada880e4215519b33cc81ab3cdb5d2c8e6dce..66db0dfbadbfcd68f848c1df6b52a810b22e1192 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/irq.h>
+#include <linux/kfifo.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
@@ -28,6 +29,7 @@
 
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-mem2mem.h>
 #include <media/videobuf2-core.h>
 
 #define CODA_FMO_BUF_SIZE      32
 #define CODADX6_WORK_BUF_SIZE  (288 * 1024 + CODA_FMO_BUF_SIZE * 8 * 1024)
-#define CODA7_WORK_BUF_SIZE    (512 * 1024 + CODA_FMO_BUF_SIZE * 8 * 1024)
+#define CODA7_WORK_BUF_SIZE    (128 * 1024)
+#define CODA7_TEMP_BUF_SIZE    (304 * 1024)
 #define CODA_PARA_BUF_SIZE     (10 * 1024)
 #define CODA_ISRAM_SIZE        (2048 * 2)
 #define CODADX6_IRAM_SIZE      0xb000
-#define CODA7_IRAM_SIZE                0x14000 /* 81920 bytes */
+#define CODA7_IRAM_SIZE                0x14000
 
-#define CODA_MAX_FRAMEBUFFERS  2
+#define CODA7_PS_BUF_SIZE      0x28000
+
+#define CODA_MAX_FRAMEBUFFERS  8
 
 #define MAX_W          8192
 #define MAX_H          8192
@@ -129,6 +134,7 @@ struct coda_dev {
        struct clk              *clk_ahb;
 
        struct coda_aux_buf     codebuf;
+       struct coda_aux_buf     tempbuf;
        struct coda_aux_buf     workbuf;
        struct gen_pool         *iram_pool;
        long unsigned int       iram_vaddr;
@@ -153,6 +159,7 @@ struct coda_params {
        u8                      mpeg4_inter_qp;
        u8                      gop_size;
        int                     codec_mode;
+       int                     codec_mode_aux;
        enum v4l2_mpeg_video_multi_slice_mode slice_mode;
        u32                     framerate;
        u16                     bitrate;
@@ -160,13 +167,30 @@ struct coda_params {
        u32                     slice_max_mb;
 };
 
+struct coda_iram_info {
+       u32             axi_sram_use;
+       phys_addr_t     buf_bit_use;
+       phys_addr_t     buf_ip_ac_dc_use;
+       phys_addr_t     buf_dbk_y_use;
+       phys_addr_t     buf_dbk_c_use;
+       phys_addr_t     buf_ovl_use;
+       phys_addr_t     buf_btp_use;
+       phys_addr_t     search_ram_paddr;
+       int             search_ram_size;
+};
+
 struct coda_ctx {
        struct coda_dev                 *dev;
+       struct mutex                    buffer_mutex;
        struct list_head                list;
+       struct work_struct              skip_run;
        int                             aborting;
+       int                             initialized;
        int                             streamon_out;
        int                             streamon_cap;
        u32                             isequence;
+       u32                             qsequence;
+       u32                             osequence;
        struct coda_q_data              q_data[2];
        enum coda_inst_type             inst_type;
        struct coda_codec               *codec;
@@ -176,12 +200,25 @@ struct coda_ctx {
        struct v4l2_ctrl_handler        ctrls;
        struct v4l2_fh                  fh;
        int                             gopcounter;
+       int                             runcounter;
        char                            vpu_header[3][64];
        int                             vpu_header_size[3];
+       struct kfifo                    bitstream_fifo;
+       struct mutex                    bitstream_mutex;
+       struct coda_aux_buf             bitstream;
+       bool                            prescan_failed;
        struct coda_aux_buf             parabuf;
+       struct coda_aux_buf             psbuf;
+       struct coda_aux_buf             slicebuf;
        struct coda_aux_buf             internal_frames[CODA_MAX_FRAMEBUFFERS];
+       struct coda_aux_buf             workbuf;
        int                             num_internal_frames;
        int                             idx;
+       int                             reg_idx;
+       struct coda_iram_info           iram_info;
+       u32                             bit_stream_param;
+       u32                             frm_dis_flg;
+       int                             display_idx;
 };
 
 static const u8 coda_filler_nal[14] = { 0x00, 0x00, 0x00, 0x01, 0x0c, 0xff,
@@ -228,10 +265,22 @@ static int coda_wait_timeout(struct coda_dev *dev)
 static void coda_command_async(struct coda_ctx *ctx, int cmd)
 {
        struct coda_dev *dev = ctx->dev;
+
+       if (dev->devtype->product == CODA_7541) {
+               /* Restore context related registers to CODA */
+               coda_write(dev, ctx->bit_stream_param,
+                               CODA_REG_BIT_BIT_STREAM_PARAM);
+               coda_write(dev, ctx->frm_dis_flg,
+                               CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
+               coda_write(dev, ctx->workbuf.paddr, CODA_REG_BIT_WORK_BUF_ADDR);
+       }
+
        coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
 
        coda_write(dev, ctx->idx, CODA_REG_BIT_RUN_INDEX);
        coda_write(dev, ctx->params.codec_mode, CODA_REG_BIT_RUN_COD_STD);
+       coda_write(dev, ctx->params.codec_mode_aux, CODA7_REG_BIT_RUN_AUX_STD);
+
        coda_write(dev, cmd, CODA_REG_BIT_RUN_COMMAND);
 }
 
@@ -297,6 +346,8 @@ static struct coda_codec codadx6_codecs[] = {
 static struct coda_codec coda7_codecs[] = {
        CODA_CODEC(CODA7_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264,   1280, 720),
        CODA_CODEC(CODA7_MODE_ENCODE_MP4,  V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4,  1280, 720),
+       CODA_CODEC(CODA7_MODE_DECODE_H264, V4L2_PIX_FMT_H264,   V4L2_PIX_FMT_YUV420, 1920, 1080),
+       CODA_CODEC(CODA7_MODE_DECODE_MP4,  V4L2_PIX_FMT_MPEG4,  V4L2_PIX_FMT_YUV420, 1920, 1080),
 };
 
 static bool coda_format_is_yuv(u32 fourcc)
@@ -365,7 +416,7 @@ static int vidioc_querycap(struct file *file, void *priv,
 }
 
 static int enum_fmt(void *priv, struct v4l2_fmtdesc *f,
-                       enum v4l2_buf_type type)
+                       enum v4l2_buf_type type, int src_fourcc)
 {
        struct coda_ctx *ctx = fh_to_ctx(priv);
        struct coda_codec *codecs = ctx->dev->devtype->codecs;
@@ -377,7 +428,8 @@ static int enum_fmt(void *priv, struct v4l2_fmtdesc *f,
 
        for (i = 0; i < num_formats; i++) {
                /* Both uncompressed formats are always supported */
-               if (coda_format_is_yuv(formats[i].fourcc)) {
+               if (coda_format_is_yuv(formats[i].fourcc) &&
+                   !coda_format_is_yuv(src_fourcc)) {
                        if (num == f->index)
                                break;
                        ++num;
@@ -385,8 +437,10 @@ static int enum_fmt(void *priv, struct v4l2_fmtdesc *f,
                }
                /* Compressed formats may be supported, check the codec list */
                for (k = 0; k < num_codecs; k++) {
+                       /* if src_fourcc is set, only consider matching codecs */
                        if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-                           formats[i].fourcc == codecs[k].dst_fourcc)
+                           formats[i].fourcc == codecs[k].dst_fourcc &&
+                           (!src_fourcc || src_fourcc == codecs[k].src_fourcc))
                                break;
                        if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
                            formats[i].fourcc == codecs[k].src_fourcc)
@@ -413,13 +467,26 @@ static int enum_fmt(void *priv, struct v4l2_fmtdesc *f,
 static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
                                   struct v4l2_fmtdesc *f)
 {
-       return enum_fmt(priv, f, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+       struct coda_ctx *ctx = fh_to_ctx(priv);
+       struct vb2_queue *src_vq;
+       struct coda_q_data *q_data_src;
+
+       /* If the source format is already fixed, only list matching formats */
+       src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+       if (vb2_is_streaming(src_vq)) {
+               q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+
+               return enum_fmt(priv, f, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+                               q_data_src->fourcc);
+       }
+
+       return enum_fmt(priv, f, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0);
 }
 
 static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
                                   struct v4l2_fmtdesc *f)
 {
-       return enum_fmt(priv, f, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+       return enum_fmt(priv, f, V4L2_BUF_TYPE_VIDEO_OUTPUT, 0);
 }
 
 static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
@@ -492,15 +559,45 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
                                  struct v4l2_format *f)
 {
        struct coda_ctx *ctx = fh_to_ctx(priv);
-       struct coda_codec *codec = NULL;
+       struct coda_codec *codec;
+       struct vb2_queue *src_vq;
+       int ret;
 
-       /* Determine codec by the encoded format */
-       codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_YUV420,
-                               f->fmt.pix.pixelformat);
+       /*
+        * If the source format is already fixed, try to find a codec that
+        * converts to the given destination format
+        */
+       src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+       if (vb2_is_streaming(src_vq)) {
+               struct coda_q_data *q_data_src;
+
+               q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+               codec = coda_find_codec(ctx->dev, q_data_src->fourcc,
+                                       f->fmt.pix.pixelformat);
+               if (!codec)
+                       return -EINVAL;
+       } else {
+               /* Otherwise determine codec by encoded format, if possible */
+               codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_YUV420,
+                                       f->fmt.pix.pixelformat);
+       }
 
        f->fmt.pix.colorspace = ctx->colorspace;
 
-       return vidioc_try_fmt(codec, f);
+       ret = vidioc_try_fmt(codec, f);
+       if (ret < 0)
+               return ret;
+
+       /* The h.264 decoder only returns complete 16x16 macroblocks */
+       if (codec && codec->src_fourcc == V4L2_PIX_FMT_H264) {
+               f->fmt.pix.width = round_up(f->fmt.pix.width, 16);
+               f->fmt.pix.height = round_up(f->fmt.pix.height, 16);
+               f->fmt.pix.bytesperline = f->fmt.pix.width;
+               f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
+                                      f->fmt.pix.height * 3 / 2;
+       }
+
+       return 0;
 }
 
 static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
@@ -610,11 +707,35 @@ static int vidioc_expbuf(struct file *file, void *priv,
        return v4l2_m2m_expbuf(file, ctx->m2m_ctx, eb);
 }
 
+static bool coda_buf_is_end_of_stream(struct coda_ctx *ctx,
+                                     struct v4l2_buffer *buf)
+{
+       struct vb2_queue *src_vq;
+
+       src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+
+       return ((ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) &&
+               (buf->sequence == (ctx->qsequence - 1)));
+}
+
 static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
 {
        struct coda_ctx *ctx = fh_to_ctx(priv);
+       int ret;
+
+       ret = v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+
+       /* If this is the last capture buffer, emit an end-of-stream event */
+       if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+           coda_buf_is_end_of_stream(ctx, buf)) {
+               const struct v4l2_event eos_event = {
+                       .type = V4L2_EVENT_EOS
+               };
+
+               v4l2_event_queue_fh(&ctx->fh, &eos_event);
+       }
 
-       return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+       return ret;
 }
 
 static int vidioc_create_bufs(struct file *file, void *priv,
@@ -637,8 +758,53 @@ static int vidioc_streamoff(struct file *file, void *priv,
                            enum v4l2_buf_type type)
 {
        struct coda_ctx *ctx = fh_to_ctx(priv);
+       int ret;
+
+       /*
+        * This indirectly calls __vb2_queue_cancel, which dequeues all buffers.
+        * We therefore have to lock it against running hardware in this context,
+        * which still needs the buffers.
+        */
+       mutex_lock(&ctx->buffer_mutex);
+       ret = v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
+       mutex_unlock(&ctx->buffer_mutex);
+
+       return ret;
+}
+
+static int vidioc_decoder_cmd(struct file *file, void *fh,
+                             struct v4l2_decoder_cmd *dc)
+{
+       struct coda_ctx *ctx = fh_to_ctx(fh);
+
+       if (dc->cmd != V4L2_DEC_CMD_STOP)
+               return -EINVAL;
+
+       if ((dc->flags & V4L2_DEC_CMD_STOP_TO_BLACK) ||
+           (dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY))
+               return -EINVAL;
+
+       if (dc->stop.pts != 0)
+               return -EINVAL;
+
+       if (ctx->inst_type != CODA_INST_DECODER)
+               return -EINVAL;
+
+       /* Set the strem-end flag on this context */
+       ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
+
+       return 0;
+}
 
-       return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
+static int vidioc_subscribe_event(struct v4l2_fh *fh,
+                                 const struct v4l2_event_subscription *sub)
+{
+       switch (sub->type) {
+       case V4L2_EVENT_EOS:
+               return v4l2_event_subscribe(fh, sub, 0, NULL);
+       default:
+               return v4l2_ctrl_subscribe_event(fh, sub);
+       }
 }
 
 static const struct v4l2_ioctl_ops coda_ioctl_ops = {
@@ -664,14 +830,206 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = {
 
        .vidioc_streamon        = vidioc_streamon,
        .vidioc_streamoff       = vidioc_streamoff,
+
+       .vidioc_decoder_cmd     = vidioc_decoder_cmd,
+
+       .vidioc_subscribe_event = vidioc_subscribe_event,
+       .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 };
 
+static int coda_start_decoding(struct coda_ctx *ctx);
+
+static void coda_skip_run(struct work_struct *work)
+{
+       struct coda_ctx *ctx = container_of(work, struct coda_ctx, skip_run);
+
+       v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->m2m_ctx);
+}
+
+static inline int coda_get_bitstream_payload(struct coda_ctx *ctx)
+{
+       return kfifo_len(&ctx->bitstream_fifo);
+}
+
+static void coda_kfifo_sync_from_device(struct coda_ctx *ctx)
+{
+       struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo;
+       struct coda_dev *dev = ctx->dev;
+       u32 rd_ptr;
+
+       rd_ptr = coda_read(dev, CODA_REG_BIT_RD_PTR(ctx->reg_idx));
+       kfifo->out = (kfifo->in & ~kfifo->mask) |
+                     (rd_ptr - ctx->bitstream.paddr);
+       if (kfifo->out > kfifo->in)
+               kfifo->out -= kfifo->mask + 1;
+}
+
+static void coda_kfifo_sync_to_device_full(struct coda_ctx *ctx)
+{
+       struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo;
+       struct coda_dev *dev = ctx->dev;
+       u32 rd_ptr, wr_ptr;
+
+       rd_ptr = ctx->bitstream.paddr + (kfifo->out & kfifo->mask);
+       coda_write(dev, rd_ptr, CODA_REG_BIT_RD_PTR(ctx->reg_idx));
+       wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask);
+       coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
+}
+
+static void coda_kfifo_sync_to_device_write(struct coda_ctx *ctx)
+{
+       struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo;
+       struct coda_dev *dev = ctx->dev;
+       u32 wr_ptr;
+
+       wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask);
+       coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
+}
+
+static int coda_bitstream_queue(struct coda_ctx *ctx, struct vb2_buffer *src_buf)
+{
+       u32 src_size = vb2_get_plane_payload(src_buf, 0);
+       u32 n;
+
+       n = kfifo_in(&ctx->bitstream_fifo, vb2_plane_vaddr(src_buf, 0), src_size);
+       if (n < src_size)
+               return -ENOSPC;
+
+       dma_sync_single_for_device(&ctx->dev->plat_dev->dev, ctx->bitstream.paddr,
+                                  ctx->bitstream.size, DMA_TO_DEVICE);
+
+       ctx->qsequence++;
+
+       return 0;
+}
+
+static bool coda_bitstream_try_queue(struct coda_ctx *ctx,
+                                    struct vb2_buffer *src_buf)
+{
+       int ret;
+
+       if (coda_get_bitstream_payload(ctx) +
+           vb2_get_plane_payload(src_buf, 0) + 512 >= ctx->bitstream.size)
+               return false;
+
+       if (vb2_plane_vaddr(src_buf, 0) == NULL) {
+               v4l2_err(&ctx->dev->v4l2_dev, "trying to queue empty buffer\n");
+               return true;
+       }
+
+       ret = coda_bitstream_queue(ctx, src_buf);
+       if (ret < 0) {
+               v4l2_err(&ctx->dev->v4l2_dev, "bitstream buffer overflow\n");
+               return false;
+       }
+       /* Sync read pointer to device */
+       if (ctx == v4l2_m2m_get_curr_priv(ctx->dev->m2m_dev))
+               coda_kfifo_sync_to_device_write(ctx);
+
+       ctx->prescan_failed = false;
+
+       return true;
+}
+
+static void coda_fill_bitstream(struct coda_ctx *ctx)
+{
+       struct vb2_buffer *src_buf;
+
+       while (v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) > 0) {
+               src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+
+               if (coda_bitstream_try_queue(ctx, src_buf)) {
+                       src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+                       v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
+               } else {
+                       break;
+               }
+       }
+}
+
 /*
  * Mem-to-mem operations.
  */
-static void coda_device_run(void *m2m_priv)
+static int coda_prepare_decode(struct coda_ctx *ctx)
+{
+       struct vb2_buffer *dst_buf;
+       struct coda_dev *dev = ctx->dev;
+       struct coda_q_data *q_data_dst;
+       u32 stridey, height;
+       u32 picture_y, picture_cb, picture_cr;
+
+       dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+       q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+
+       if (ctx->params.rot_mode & CODA_ROT_90) {
+               stridey = q_data_dst->height;
+               height = q_data_dst->width;
+       } else {
+               stridey = q_data_dst->width;
+               height = q_data_dst->height;
+       }
+
+       /* Try to copy source buffer contents into the bitstream ringbuffer */
+       mutex_lock(&ctx->bitstream_mutex);
+       coda_fill_bitstream(ctx);
+       mutex_unlock(&ctx->bitstream_mutex);
+
+       if (coda_get_bitstream_payload(ctx) < 512 &&
+           (!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) {
+               v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+                        "bitstream payload: %d, skipping\n",
+                        coda_get_bitstream_payload(ctx));
+               schedule_work(&ctx->skip_run);
+               return -EAGAIN;
+       }
+
+       /* Run coda_start_decoding (again) if not yet initialized */
+       if (!ctx->initialized) {
+               int ret = coda_start_decoding(ctx);
+               if (ret < 0) {
+                       v4l2_err(&dev->v4l2_dev, "failed to start decoding\n");
+                       schedule_work(&ctx->skip_run);
+                       return -EAGAIN;
+               } else {
+                       ctx->initialized = 1;
+               }
+       }
+
+       /* Set rotator output */
+       picture_y = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
+       if (q_data_dst->fourcc == V4L2_PIX_FMT_YVU420) {
+               /* Switch Cr and Cb for YVU420 format */
+               picture_cr = picture_y + stridey * height;
+               picture_cb = picture_cr + stridey / 2 * height / 2;
+       } else {
+               picture_cb = picture_y + stridey * height;
+               picture_cr = picture_cb + stridey / 2 * height / 2;
+       }
+       coda_write(dev, picture_y, CODA_CMD_DEC_PIC_ROT_ADDR_Y);
+       coda_write(dev, picture_cb, CODA_CMD_DEC_PIC_ROT_ADDR_CB);
+       coda_write(dev, picture_cr, CODA_CMD_DEC_PIC_ROT_ADDR_CR);
+       coda_write(dev, stridey, CODA_CMD_DEC_PIC_ROT_STRIDE);
+       coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode,
+                       CODA_CMD_DEC_PIC_ROT_MODE);
+
+       switch (dev->devtype->product) {
+       case CODA_DX6:
+               /* TBD */
+       case CODA_7541:
+               coda_write(dev, CODA_PRE_SCAN_EN, CODA_CMD_DEC_PIC_OPTION);
+               break;
+       }
+
+       coda_write(dev, 0, CODA_CMD_DEC_PIC_SKIP_NUM);
+
+       coda_write(dev, 0, CODA_CMD_DEC_PIC_BB_START);
+       coda_write(dev, 0, CODA_CMD_DEC_PIC_START_BYTE);
+
+       return 0;
+}
+
+static void coda_prepare_encode(struct coda_ctx *ctx)
 {
-       struct coda_ctx *ctx = m2m_priv;
        struct coda_q_data *q_data_src, *q_data_dst;
        struct vb2_buffer *src_buf, *dst_buf;
        struct coda_dev *dev = ctx->dev;
@@ -681,17 +1039,15 @@ static void coda_device_run(void *m2m_priv)
        u32 pic_stream_buffer_addr, pic_stream_buffer_size;
        u32 dst_fourcc;
 
-       mutex_lock(&dev->coda_mutex);
-
        src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
        dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
        q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
        q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
        dst_fourcc = q_data_dst->fourcc;
 
-       src_buf->v4l2_buf.sequence = ctx->isequence;
-       dst_buf->v4l2_buf.sequence = ctx->isequence;
-       ctx->isequence++;
+       src_buf->v4l2_buf.sequence = ctx->osequence;
+       dst_buf->v4l2_buf.sequence = ctx->osequence;
+       ctx->osequence++;
 
        /*
         * Workaround coda firmware BUG that only marks the first
@@ -793,16 +1149,53 @@ static void coda_device_run(void *m2m_priv)
        coda_write(dev, pic_stream_buffer_addr, CODA_CMD_ENC_PIC_BB_START);
        coda_write(dev, pic_stream_buffer_size / 1024,
                   CODA_CMD_ENC_PIC_BB_SIZE);
+}
 
-       if (dev->devtype->product == CODA_7541) {
-               coda_write(dev, CODA7_USE_BIT_ENABLE | CODA7_USE_HOST_BIT_ENABLE |
-                               CODA7_USE_ME_ENABLE | CODA7_USE_HOST_ME_ENABLE,
-                               CODA7_REG_BIT_AXI_SRAM_USE);
+static void coda_device_run(void *m2m_priv)
+{
+       struct coda_ctx *ctx = m2m_priv;
+       struct coda_dev *dev = ctx->dev;
+       int ret;
+
+       mutex_lock(&ctx->buffer_mutex);
+
+       /*
+        * If streamoff dequeued all buffers before we could get the lock,
+        * just bail out immediately.
+        */
+       if ((!v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) &&
+           ctx->inst_type != CODA_INST_DECODER) ||
+               !v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx)) {
+               v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+                       "%d: device_run without buffers\n", ctx->idx);
+               mutex_unlock(&ctx->buffer_mutex);
+               schedule_work(&ctx->skip_run);
+               return;
+       }
+
+       mutex_lock(&dev->coda_mutex);
+
+       if (ctx->inst_type == CODA_INST_DECODER) {
+               ret = coda_prepare_decode(ctx);
+               if (ret < 0) {
+                       mutex_unlock(&dev->coda_mutex);
+                       mutex_unlock(&ctx->buffer_mutex);
+                       /* job_finish scheduled by prepare_decode */
+                       return;
+               }
+       } else {
+               coda_prepare_encode(ctx);
        }
 
+       if (dev->devtype->product != CODA_DX6)
+               coda_write(dev, ctx->iram_info.axi_sram_use,
+                               CODA7_REG_BIT_AXI_SRAM_USE);
+
        /* 1 second timeout in case CODA locks up */
        schedule_delayed_work(&dev->timeout, HZ);
 
+       if (ctx->inst_type == CODA_INST_DECODER)
+               coda_kfifo_sync_to_device_full(ctx);
        coda_command_async(ctx, CODA_COMMAND_PIC_RUN);
 }
 
@@ -812,15 +1205,32 @@ static int coda_job_ready(void *m2m_priv)
 
        /*
         * For both 'P' and 'key' frame cases 1 picture
-        * and 1 frame are needed.
+        * and 1 frame are needed. In the decoder case,
+        * the compressed frame can be in the bitstream.
         */
-       if (!v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) ||
-               !v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx)) {
+       if (!v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) &&
+           ctx->inst_type != CODA_INST_DECODER) {
                v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
                         "not ready: not enough video buffers.\n");
                return 0;
        }
 
+       if (!v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx)) {
+               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                        "not ready: not enough video capture buffers.\n");
+               return 0;
+       }
+
+       if (ctx->prescan_failed ||
+           ((ctx->inst_type == CODA_INST_DECODER) &&
+            (coda_get_bitstream_payload(ctx) < 512) &&
+            !(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) {
+               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                        "%d: not ready: not enough bitstream data.\n",
+                        ctx->idx);
+               return 0;
+       }
+
        if (ctx->aborting) {
                v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
                         "not ready: aborting\n");
@@ -936,7 +1346,29 @@ static int coda_buf_prepare(struct vb2_buffer *vb)
 static void coda_buf_queue(struct vb2_buffer *vb)
 {
        struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
-       v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+       struct coda_q_data *q_data;
+
+       q_data = get_q_data(ctx, vb->vb2_queue->type);
+
+       /*
+        * In the decoder case, immediately try to copy the buffer into the
+        * bitstream ringbuffer and mark it as ready to be dequeued.
+        */
+       if (q_data->fourcc == V4L2_PIX_FMT_H264 &&
+           vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+               /*
+                * For backwards compatiblity, queuing an empty buffer marks
+                * the stream end
+                */
+               if (vb2_get_plane_payload(vb, 0) == 0)
+                       ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
+               mutex_lock(&ctx->bitstream_mutex);
+               v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+               coda_fill_bitstream(ctx);
+               mutex_unlock(&ctx->bitstream_mutex);
+       } else {
+               v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+       }
 }
 
 static void coda_wait_prepare(struct vb2_queue *q)
@@ -951,88 +1383,488 @@ static void coda_wait_finish(struct vb2_queue *q)
        coda_lock(ctx);
 }
 
+static void coda_parabuf_write(struct coda_ctx *ctx, int index, u32 value)
+{
+       struct coda_dev *dev = ctx->dev;
+       u32 *p = ctx->parabuf.vaddr;
+
+       if (dev->devtype->product == CODA_DX6)
+               p[index] = value;
+       else
+               p[index ^ 1] = value;
+}
+
+static int coda_alloc_aux_buf(struct coda_dev *dev,
+                             struct coda_aux_buf *buf, size_t size)
+{
+       buf->vaddr = dma_alloc_coherent(&dev->plat_dev->dev, size, &buf->paddr,
+                                       GFP_KERNEL);
+       if (!buf->vaddr)
+               return -ENOMEM;
+
+       buf->size = size;
+
+       return 0;
+}
+
+static inline int coda_alloc_context_buf(struct coda_ctx *ctx,
+                                        struct coda_aux_buf *buf, size_t size)
+{
+       return coda_alloc_aux_buf(ctx->dev, buf, size);
+}
+
+static void coda_free_aux_buf(struct coda_dev *dev,
+                             struct coda_aux_buf *buf)
+{
+       if (buf->vaddr) {
+               dma_free_coherent(&dev->plat_dev->dev, buf->size,
+                                 buf->vaddr, buf->paddr);
+               buf->vaddr = NULL;
+               buf->size = 0;
+       }
+}
+
 static void coda_free_framebuffers(struct coda_ctx *ctx)
 {
        int i;
 
-       for (i = 0; i < CODA_MAX_FRAMEBUFFERS; i++) {
-               if (ctx->internal_frames[i].vaddr) {
-                       dma_free_coherent(&ctx->dev->plat_dev->dev,
-                               ctx->internal_frames[i].size,
-                               ctx->internal_frames[i].vaddr,
-                               ctx->internal_frames[i].paddr);
-                       ctx->internal_frames[i].vaddr = NULL;
+       for (i = 0; i < CODA_MAX_FRAMEBUFFERS; i++)
+               coda_free_aux_buf(ctx->dev, &ctx->internal_frames[i]);
+}
+
+static int coda_alloc_framebuffers(struct coda_ctx *ctx, struct coda_q_data *q_data, u32 fourcc)
+{
+       struct coda_dev *dev = ctx->dev;
+       int height = q_data->height;
+       dma_addr_t paddr;
+       int ysize;
+       int ret;
+       int i;
+
+       if (ctx->codec && ctx->codec->src_fourcc == V4L2_PIX_FMT_H264)
+               height = round_up(height, 16);
+       ysize = round_up(q_data->width, 8) * height;
+
+       /* Allocate frame buffers */
+       for (i = 0; i < ctx->num_internal_frames; i++) {
+               size_t size;
+
+               size = q_data->sizeimage;
+               if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 &&
+                   dev->devtype->product != CODA_DX6)
+                       ctx->internal_frames[i].size += ysize/4;
+               ret = coda_alloc_context_buf(ctx, &ctx->internal_frames[i], size);
+               if (ret < 0) {
+                       coda_free_framebuffers(ctx);
+                       return ret;
                }
        }
+
+       /* Register frame buffers in the parameter buffer */
+       for (i = 0; i < ctx->num_internal_frames; i++) {
+               paddr = ctx->internal_frames[i].paddr;
+               coda_parabuf_write(ctx, i * 3 + 0, paddr); /* Y */
+               coda_parabuf_write(ctx, i * 3 + 1, paddr + ysize); /* Cb */
+               coda_parabuf_write(ctx, i * 3 + 2, paddr + ysize + ysize/4); /* Cr */
+
+               /* mvcol buffer for h.264 */
+               if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 &&
+                   dev->devtype->product != CODA_DX6)
+                       coda_parabuf_write(ctx, 96 + i,
+                                          ctx->internal_frames[i].paddr +
+                                          ysize + ysize/4 + ysize/4);
+       }
+
+       /* mvcol buffer for mpeg4 */
+       if ((dev->devtype->product != CODA_DX6) &&
+           (ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4))
+               coda_parabuf_write(ctx, 97, ctx->internal_frames[i].paddr +
+                                           ysize + ysize/4 + ysize/4);
+
+       return 0;
 }
 
-static void coda_parabuf_write(struct coda_ctx *ctx, int index, u32 value)
+static int coda_h264_padding(int size, char *p)
+{
+       int nal_size;
+       int diff;
+
+       diff = size - (size & ~0x7);
+       if (diff == 0)
+               return 0;
+
+       nal_size = coda_filler_size[diff];
+       memcpy(p, coda_filler_nal, nal_size);
+
+       /* Add rbsp stop bit and trailing at the end */
+       *(p + nal_size - 1) = 0x80;
+
+       return nal_size;
+}
+
+static void coda_setup_iram(struct coda_ctx *ctx)
 {
+       struct coda_iram_info *iram_info = &ctx->iram_info;
        struct coda_dev *dev = ctx->dev;
-       u32 *p = ctx->parabuf.vaddr;
+       int ipacdc_size;
+       int bitram_size;
+       int dbk_size;
+       int ovl_size;
+       int mb_width;
+       int me_size;
+       int size;
+
+       memset(iram_info, 0, sizeof(*iram_info));
+       size = dev->iram_size;
 
        if (dev->devtype->product == CODA_DX6)
-               p[index] = value;
-       else
-               p[index ^ 1] = value;
+               return;
+
+       if (ctx->inst_type == CODA_INST_ENCODER) {
+               struct coda_q_data *q_data_src;
+
+               q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+               mb_width = DIV_ROUND_UP(q_data_src->width, 16);
+
+               /* Prioritize in case IRAM is too small for everything */
+               me_size = round_up(round_up(q_data_src->width, 16) * 36 + 2048,
+                                  1024);
+               iram_info->search_ram_size = me_size;
+               if (size >= iram_info->search_ram_size) {
+                       if (dev->devtype->product == CODA_7541)
+                               iram_info->axi_sram_use |= CODA7_USE_HOST_ME_ENABLE;
+                       iram_info->search_ram_paddr = dev->iram_paddr;
+                       size -= iram_info->search_ram_size;
+               } else {
+                       pr_err("IRAM is smaller than the search ram size\n");
+                       goto out;
+               }
+
+               /* Only H.264BP and H.263P3 are considered */
+               dbk_size = round_up(128 * mb_width, 1024);
+               if (size >= dbk_size) {
+                       iram_info->axi_sram_use |= CODA7_USE_HOST_DBK_ENABLE;
+                       iram_info->buf_dbk_y_use = dev->iram_paddr +
+                                                  iram_info->search_ram_size;
+                       iram_info->buf_dbk_c_use = iram_info->buf_dbk_y_use +
+                                                  dbk_size / 2;
+                       size -= dbk_size;
+               } else {
+                       goto out;
+               }
+
+               bitram_size = round_up(128 * mb_width, 1024);
+               if (size >= bitram_size) {
+                       iram_info->axi_sram_use |= CODA7_USE_HOST_BIT_ENABLE;
+                       iram_info->buf_bit_use = iram_info->buf_dbk_c_use +
+                                                dbk_size / 2;
+                       size -= bitram_size;
+               } else {
+                       goto out;
+               }
+
+               ipacdc_size = round_up(128 * mb_width, 1024);
+               if (size >= ipacdc_size) {
+                       iram_info->axi_sram_use |= CODA7_USE_HOST_IP_ENABLE;
+                       iram_info->buf_ip_ac_dc_use = iram_info->buf_bit_use +
+                                                     bitram_size;
+                       size -= ipacdc_size;
+               }
+
+               /* OVL and BTP disabled for encoder */
+       } else if (ctx->inst_type == CODA_INST_DECODER) {
+               struct coda_q_data *q_data_dst;
+               int mb_height;
+
+               q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+               mb_width = DIV_ROUND_UP(q_data_dst->width, 16);
+               mb_height = DIV_ROUND_UP(q_data_dst->height, 16);
+
+               dbk_size = round_up(256 * mb_width, 1024);
+               if (size >= dbk_size) {
+                       iram_info->axi_sram_use |= CODA7_USE_HOST_DBK_ENABLE;
+                       iram_info->buf_dbk_y_use = dev->iram_paddr;
+                       iram_info->buf_dbk_c_use = dev->iram_paddr +
+                                                  dbk_size / 2;
+                       size -= dbk_size;
+               } else {
+                       goto out;
+               }
+
+               bitram_size = round_up(128 * mb_width, 1024);
+               if (size >= bitram_size) {
+                       iram_info->axi_sram_use |= CODA7_USE_HOST_BIT_ENABLE;
+                       iram_info->buf_bit_use = iram_info->buf_dbk_c_use +
+                                                dbk_size / 2;
+                       size -= bitram_size;
+               } else {
+                       goto out;
+               }
+
+               ipacdc_size = round_up(128 * mb_width, 1024);
+               if (size >= ipacdc_size) {
+                       iram_info->axi_sram_use |= CODA7_USE_HOST_IP_ENABLE;
+                       iram_info->buf_ip_ac_dc_use = iram_info->buf_bit_use +
+                                                     bitram_size;
+                       size -= ipacdc_size;
+               } else {
+                       goto out;
+               }
+
+               ovl_size = round_up(80 * mb_width, 1024);
+       }
+
+out:
+       switch (dev->devtype->product) {
+       case CODA_DX6:
+               break;
+       case CODA_7541:
+               /* i.MX53 uses secondary AXI for IRAM access */
+               if (iram_info->axi_sram_use & CODA7_USE_HOST_BIT_ENABLE)
+                       iram_info->axi_sram_use |= CODA7_USE_BIT_ENABLE;
+               if (iram_info->axi_sram_use & CODA7_USE_HOST_IP_ENABLE)
+                       iram_info->axi_sram_use |= CODA7_USE_IP_ENABLE;
+               if (iram_info->axi_sram_use & CODA7_USE_HOST_DBK_ENABLE)
+                       iram_info->axi_sram_use |= CODA7_USE_DBK_ENABLE;
+               if (iram_info->axi_sram_use & CODA7_USE_HOST_OVL_ENABLE)
+                       iram_info->axi_sram_use |= CODA7_USE_OVL_ENABLE;
+               if (iram_info->axi_sram_use & CODA7_USE_HOST_ME_ENABLE)
+                       iram_info->axi_sram_use |= CODA7_USE_ME_ENABLE;
+       }
+
+       if (!(iram_info->axi_sram_use & CODA7_USE_HOST_IP_ENABLE))
+               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                        "IRAM smaller than needed\n");
+
+       if (dev->devtype->product == CODA_7541) {
+               /* TODO - Enabling these causes picture errors on CODA7541 */
+               if (ctx->inst_type == CODA_INST_DECODER) {
+                       /* fw 1.4.50 */
+                       iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE |
+                                                    CODA7_USE_IP_ENABLE);
+               } else {
+                       /* fw 13.4.29 */
+                       iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE |
+                                                    CODA7_USE_HOST_DBK_ENABLE |
+                                                    CODA7_USE_IP_ENABLE |
+                                                    CODA7_USE_DBK_ENABLE);
+               }
+       }
 }
 
-static int coda_alloc_framebuffers(struct coda_ctx *ctx, struct coda_q_data *q_data, u32 fourcc)
+static void coda_free_context_buffers(struct coda_ctx *ctx)
 {
        struct coda_dev *dev = ctx->dev;
 
-       int height = q_data->height;
-       dma_addr_t paddr;
-       int ysize;
-       int i;
+       coda_free_aux_buf(dev, &ctx->slicebuf);
+       coda_free_aux_buf(dev, &ctx->psbuf);
+       if (dev->devtype->product != CODA_DX6)
+               coda_free_aux_buf(dev, &ctx->workbuf);
+}
+
+static int coda_alloc_context_buffers(struct coda_ctx *ctx,
+                                     struct coda_q_data *q_data)
+{
+       struct coda_dev *dev = ctx->dev;
+       size_t size;
+       int ret;
+
+       switch (dev->devtype->product) {
+       case CODA_7541:
+               size = CODA7_WORK_BUF_SIZE;
+               break;
+       default:
+               return 0;
+       }
+
+       if (ctx->psbuf.vaddr) {
+               v4l2_err(&dev->v4l2_dev, "psmembuf still allocated\n");
+               return -EBUSY;
+       }
+       if (ctx->slicebuf.vaddr) {
+               v4l2_err(&dev->v4l2_dev, "slicebuf still allocated\n");
+               return -EBUSY;
+       }
+       if (ctx->workbuf.vaddr) {
+               v4l2_err(&dev->v4l2_dev, "context buffer still allocated\n");
+               ret = -EBUSY;
+               return -ENOMEM;
+       }
+
+       if (q_data->fourcc == V4L2_PIX_FMT_H264) {
+               /* worst case slice size */
+               size = (DIV_ROUND_UP(q_data->width, 16) *
+                       DIV_ROUND_UP(q_data->height, 16)) * 3200 / 8 + 512;
+               ret = coda_alloc_context_buf(ctx, &ctx->slicebuf, size);
+               if (ret < 0) {
+                       v4l2_err(&dev->v4l2_dev, "failed to allocate %d byte slice buffer",
+                                ctx->slicebuf.size);
+                       return ret;
+               }
+       }
+
+       if (dev->devtype->product == CODA_7541) {
+               ret = coda_alloc_context_buf(ctx, &ctx->psbuf, CODA7_PS_BUF_SIZE);
+               if (ret < 0) {
+                       v4l2_err(&dev->v4l2_dev, "failed to allocate psmem buffer");
+                       goto err;
+               }
+       }
+
+       ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size);
+       if (ret < 0) {
+               v4l2_err(&dev->v4l2_dev, "failed to allocate %d byte context buffer",
+                        ctx->workbuf.size);
+               goto err;
+       }
+
+       return 0;
+
+err:
+       coda_free_context_buffers(ctx);
+       return ret;
+}
+
+static int coda_start_decoding(struct coda_ctx *ctx)
+{
+       struct coda_q_data *q_data_src, *q_data_dst;
+       u32 bitstream_buf, bitstream_size;
+       struct coda_dev *dev = ctx->dev;
+       int width, height;
+       u32 src_fourcc;
+       u32 val;
+       int ret;
+
+       /* Start decoding */
+       q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+       q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+       bitstream_buf = ctx->bitstream.paddr;
+       bitstream_size = ctx->bitstream.size;
+       src_fourcc = q_data_src->fourcc;
+
+       coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR);
+
+       /* Update coda bitstream read and write pointers from kfifo */
+       coda_kfifo_sync_to_device_full(ctx);
+
+       ctx->display_idx = -1;
+       ctx->frm_dis_flg = 0;
+       coda_write(dev, 0, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
+
+       coda_write(dev, CODA_BIT_DEC_SEQ_INIT_ESCAPE,
+                       CODA_REG_BIT_BIT_STREAM_PARAM);
+
+       coda_write(dev, bitstream_buf, CODA_CMD_DEC_SEQ_BB_START);
+       coda_write(dev, bitstream_size / 1024, CODA_CMD_DEC_SEQ_BB_SIZE);
+       val = 0;
+       if (dev->devtype->product == CODA_7541)
+               val |= CODA_REORDER_ENABLE;
+       coda_write(dev, val, CODA_CMD_DEC_SEQ_OPTION);
+
+       ctx->params.codec_mode = ctx->codec->mode;
+       ctx->params.codec_mode_aux = 0;
+       if (src_fourcc == V4L2_PIX_FMT_H264) {
+               if (dev->devtype->product == CODA_7541) {
+                       coda_write(dev, ctx->psbuf.paddr,
+                                       CODA_CMD_DEC_SEQ_PS_BB_START);
+                       coda_write(dev, (CODA7_PS_BUF_SIZE / 1024),
+                                       CODA_CMD_DEC_SEQ_PS_BB_SIZE);
+               }
+       }
+
+       if (coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT)) {
+               v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n");
+               coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM);
+               return -ETIMEDOUT;
+       }
+
+       /* Update kfifo out pointer from coda bitstream read pointer */
+       coda_kfifo_sync_from_device(ctx);
 
-       ysize = round_up(q_data->width, 8) * height;
+       coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM);
 
-       /* Allocate frame buffers */
-       ctx->num_internal_frames = CODA_MAX_FRAMEBUFFERS;
-       for (i = 0; i < ctx->num_internal_frames; i++) {
-               ctx->internal_frames[i].size = q_data->sizeimage;
-               if (fourcc == V4L2_PIX_FMT_H264 && dev->devtype->product != CODA_DX6)
-                       ctx->internal_frames[i].size += ysize/4;
-               ctx->internal_frames[i].vaddr = dma_alloc_coherent(
-                               &dev->plat_dev->dev, ctx->internal_frames[i].size,
-                               &ctx->internal_frames[i].paddr, GFP_KERNEL);
-               if (!ctx->internal_frames[i].vaddr) {
-                       coda_free_framebuffers(ctx);
-                       return -ENOMEM;
-               }
+       if (coda_read(dev, CODA_RET_DEC_SEQ_SUCCESS) == 0) {
+               v4l2_err(&dev->v4l2_dev,
+                       "CODA_COMMAND_SEQ_INIT failed, error code = %d\n",
+                       coda_read(dev, CODA_RET_DEC_SEQ_ERR_REASON));
+               return -EAGAIN;
        }
 
-       /* Register frame buffers in the parameter buffer */
-       for (i = 0; i < ctx->num_internal_frames; i++) {
-               paddr = ctx->internal_frames[i].paddr;
-               coda_parabuf_write(ctx, i * 3 + 0, paddr); /* Y */
-               coda_parabuf_write(ctx, i * 3 + 1, paddr + ysize); /* Cb */
-               coda_parabuf_write(ctx, i * 3 + 2, paddr + ysize + ysize/4); /* Cr */
+       val = coda_read(dev, CODA_RET_DEC_SEQ_SRC_SIZE);
+       if (dev->devtype->product == CODA_DX6) {
+               width = (val >> CODADX6_PICWIDTH_OFFSET) & CODADX6_PICWIDTH_MASK;
+               height = val & CODADX6_PICHEIGHT_MASK;
+       } else {
+               width = (val >> CODA7_PICWIDTH_OFFSET) & CODA7_PICWIDTH_MASK;
+               height = val & CODA7_PICHEIGHT_MASK;
+       }
 
-               if (dev->devtype->product != CODA_DX6 && fourcc == V4L2_PIX_FMT_H264)
-                       coda_parabuf_write(ctx, 96 + i, ctx->internal_frames[i].paddr + ysize + ysize/4 + ysize/4);
+       if (width > q_data_dst->width || height > q_data_dst->height) {
+               v4l2_err(&dev->v4l2_dev, "stream is %dx%d, not %dx%d\n",
+                        width, height, q_data_dst->width, q_data_dst->height);
+               return -EINVAL;
        }
 
-       return 0;
-}
+       width = round_up(width, 16);
+       height = round_up(height, 16);
 
-static int coda_h264_padding(int size, char *p)
-{
-       int nal_size;
-       int diff;
+       v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "%s instance %d now: %dx%d\n",
+                __func__, ctx->idx, width, height);
 
-       diff = size - (size & ~0x7);
-       if (diff == 0)
-               return 0;
+       ctx->num_internal_frames = coda_read(dev, CODA_RET_DEC_SEQ_FRAME_NEED) + 1;
+       if (ctx->num_internal_frames > CODA_MAX_FRAMEBUFFERS) {
+               v4l2_err(&dev->v4l2_dev,
+                        "not enough framebuffers to decode (%d < %d)\n",
+                        CODA_MAX_FRAMEBUFFERS, ctx->num_internal_frames);
+               return -EINVAL;
+       }
 
-       nal_size = coda_filler_size[diff];
-       memcpy(p, coda_filler_nal, nal_size);
+       ret = coda_alloc_framebuffers(ctx, q_data_dst, src_fourcc);
+       if (ret < 0)
+               return ret;
 
-       /* Add rbsp stop bit and trailing at the end */
-       *(p + nal_size - 1) = 0x80;
+       /* Tell the decoder how many frame buffers we allocated. */
+       coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM);
+       coda_write(dev, width, CODA_CMD_SET_FRAME_BUF_STRIDE);
 
-       return nal_size;
+       if (dev->devtype->product != CODA_DX6) {
+               /* Set secondary AXI IRAM */
+               coda_setup_iram(ctx);
+
+               coda_write(dev, ctx->iram_info.buf_bit_use,
+                               CODA7_CMD_SET_FRAME_AXI_BIT_ADDR);
+               coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use,
+                               CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR);
+               coda_write(dev, ctx->iram_info.buf_dbk_y_use,
+                               CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR);
+               coda_write(dev, ctx->iram_info.buf_dbk_c_use,
+                               CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR);
+               coda_write(dev, ctx->iram_info.buf_ovl_use,
+                               CODA7_CMD_SET_FRAME_AXI_OVL_ADDR);
+       }
+
+       if (src_fourcc == V4L2_PIX_FMT_H264) {
+               coda_write(dev, ctx->slicebuf.paddr,
+                               CODA_CMD_SET_FRAME_SLICE_BB_START);
+               coda_write(dev, ctx->slicebuf.size / 1024,
+                               CODA_CMD_SET_FRAME_SLICE_BB_SIZE);
+       }
+
+       if (dev->devtype->product == CODA_7541) {
+               int max_mb_x = 1920 / 16;
+               int max_mb_y = 1088 / 16;
+               int max_mb_num = max_mb_x * max_mb_y;
+               coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y,
+                               CODA7_CMD_SET_FRAME_MAX_DEC_SIZE);
+       }
+
+       if (coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF)) {
+               v4l2_err(&ctx->dev->v4l2_dev,
+                        "CODA_COMMAND_SET_FRAME_BUF timeout\n");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
 }
 
 static int coda_encode_header(struct coda_ctx *ctx, struct vb2_buffer *buf,
@@ -1050,7 +1882,7 @@ static int coda_encode_header(struct coda_ctx *ctx, struct vb2_buffer *buf,
                v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n");
                return ret;
        }
-       *size = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)) -
+       *size = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)) -
                coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
        memcpy(header, vb2_plane_vaddr(buf, 0), *size);
 
@@ -1069,26 +1901,36 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
        u32 value;
        int ret = 0;
 
-       if (count < 1)
-               return -EINVAL;
+       q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+       if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+               if (q_data_src->fourcc == V4L2_PIX_FMT_H264) {
+                       if (coda_get_bitstream_payload(ctx) < 512)
+                               return -EINVAL;
+               } else {
+                       if (count < 1)
+                               return -EINVAL;
+               }
 
-       if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
                ctx->streamon_out = 1;
-       else
-               ctx->streamon_cap = 1;
 
-       q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-       if (ctx->streamon_out) {
                if (coda_format_is_yuv(q_data_src->fourcc))
                        ctx->inst_type = CODA_INST_ENCODER;
                else
                        ctx->inst_type = CODA_INST_DECODER;
+       } else {
+               if (count < 1)
+                       return -EINVAL;
+
+               ctx->streamon_cap = 1;
        }
 
        /* Don't start the coda unless both queues are on */
        if (!(ctx->streamon_out & ctx->streamon_cap))
                return 0;
 
+       /* Allow device_run with no buffers queued and after streamoff */
+       v4l2_m2m_set_src_buffered(ctx->m2m_ctx, true);
+
        ctx->gopcounter = ctx->params.gop_size - 1;
        buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
        bitstream_buf = vb2_dma_contig_plane_dma_addr(buf, 0);
@@ -1103,6 +1945,25 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
                return -EINVAL;
        }
 
+       /* Allocate per-instance buffers */
+       ret = coda_alloc_context_buffers(ctx, q_data_src);
+       if (ret < 0)
+               return ret;
+
+       if (ctx->inst_type == CODA_INST_DECODER) {
+               mutex_lock(&dev->coda_mutex);
+               ret = coda_start_decoding(ctx);
+               mutex_unlock(&dev->coda_mutex);
+               if (ret == -EAGAIN) {
+                       return 0;
+               } else if (ret < 0) {
+                       return ret;
+               } else {
+                       ctx->initialized = 1;
+                       return 0;
+               }
+       }
+
        if (!coda_is_initialized(dev)) {
                v4l2_err(v4l2_dev, "coda is not initialized.\n");
                return -EFAULT;
@@ -1111,8 +1972,8 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
        mutex_lock(&dev->coda_mutex);
 
        coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR);
-       coda_write(dev, bitstream_buf, CODA_REG_BIT_RD_PTR(ctx->idx));
-       coda_write(dev, bitstream_buf, CODA_REG_BIT_WR_PTR(ctx->idx));
+       coda_write(dev, bitstream_buf, CODA_REG_BIT_RD_PTR(ctx->reg_idx));
+       coda_write(dev, bitstream_buf, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
        switch (dev->devtype->product) {
        case CODA_DX6:
                coda_write(dev, CODADX6_STREAM_BUF_DYNALLOC_EN |
@@ -1207,6 +2068,8 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
        }
        coda_write(dev, value, CODA_CMD_ENC_SEQ_OPTION);
 
+       coda_setup_iram(ctx);
+
        if (dst_fourcc == V4L2_PIX_FMT_H264) {
                value  = (FMO_SLICE_SAVE_BUF_SIZE << 7);
                value |= (0 & CODA_FMOPARAM_TYPE_MASK) << CODA_FMOPARAM_TYPE_OFFSET;
@@ -1214,8 +2077,10 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
                if (dev->devtype->product == CODA_DX6) {
                        coda_write(dev, value, CODADX6_CMD_ENC_SEQ_FMO);
                } else {
-                       coda_write(dev, dev->iram_paddr, CODA7_CMD_ENC_SEQ_SEARCH_BASE);
-                       coda_write(dev, 48 * 1024, CODA7_CMD_ENC_SEQ_SEARCH_SIZE);
+                       coda_write(dev, ctx->iram_info.search_ram_paddr,
+                                       CODA7_CMD_ENC_SEQ_SEARCH_BASE);
+                       coda_write(dev, ctx->iram_info.search_ram_size,
+                                       CODA7_CMD_ENC_SEQ_SEARCH_SIZE);
                }
        }
 
@@ -1231,6 +2096,7 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
                goto out;
        }
 
+       ctx->num_internal_frames = 2;
        ret = coda_alloc_framebuffers(ctx, q_data_src, dst_fourcc);
        if (ret < 0) {
                v4l2_err(v4l2_dev, "failed to allocate framebuffers\n");
@@ -1239,13 +2105,20 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
 
        coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM);
        coda_write(dev, round_up(q_data_src->width, 8), CODA_CMD_SET_FRAME_BUF_STRIDE);
+       if (dev->devtype->product == CODA_7541)
+               coda_write(dev, round_up(q_data_src->width, 8),
+                               CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE);
        if (dev->devtype->product != CODA_DX6) {
-               coda_write(dev, round_up(q_data_src->width, 8), CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE);
-               coda_write(dev, dev->iram_paddr + 48 * 1024, CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR);
-               coda_write(dev, dev->iram_paddr + 53 * 1024, CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR);
-               coda_write(dev, dev->iram_paddr + 58 * 1024, CODA7_CMD_SET_FRAME_AXI_BIT_ADDR);
-               coda_write(dev, dev->iram_paddr + 68 * 1024, CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR);
-               coda_write(dev, 0x0, CODA7_CMD_SET_FRAME_AXI_OVL_ADDR);
+               coda_write(dev, ctx->iram_info.buf_bit_use,
+                               CODA7_CMD_SET_FRAME_AXI_BIT_ADDR);
+               coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use,
+                               CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR);
+               coda_write(dev, ctx->iram_info.buf_dbk_y_use,
+                               CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR);
+               coda_write(dev, ctx->iram_info.buf_dbk_c_use,
+                               CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR);
+               coda_write(dev, ctx->iram_info.buf_ovl_use,
+                               CODA7_CMD_SET_FRAME_AXI_OVL_ADDR);
        }
        ret = coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF);
        if (ret < 0) {
@@ -1326,32 +2199,26 @@ static int coda_stop_streaming(struct vb2_queue *q)
        struct coda_dev *dev = ctx->dev;
 
        if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
-               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+               v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
                         "%s: output\n", __func__);
                ctx->streamon_out = 0;
+
+               ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
+
+               ctx->isequence = 0;
        } else {
-               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+               v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
                         "%s: capture\n", __func__);
                ctx->streamon_cap = 0;
-       }
-
-       /* Don't stop the coda unless both queues are off */
-       if (ctx->streamon_out || ctx->streamon_cap)
-               return 0;
 
-       cancel_delayed_work(&dev->timeout);
-
-       mutex_lock(&dev->coda_mutex);
-       v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-                "%s: sent command 'SEQ_END' to coda\n", __func__);
-       if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) {
-               v4l2_err(&dev->v4l2_dev,
-                        "CODA_COMMAND_SEQ_END failed\n");
-               return -ETIMEDOUT;
+               ctx->osequence = 0;
        }
-       mutex_unlock(&dev->coda_mutex);
 
-       coda_free_framebuffers(ctx);
+       if (!ctx->streamon_out && !ctx->streamon_cap) {
+               kfifo_init(&ctx->bitstream_fifo,
+                       ctx->bitstream.vaddr, ctx->bitstream.size);
+               ctx->runcounter = 0;
+       }
 
        return 0;
 }
@@ -1511,7 +2378,7 @@ static int coda_open(struct file *file)
 {
        struct coda_dev *dev = video_drvdata(file);
        struct coda_ctx *ctx = NULL;
-       int ret = 0;
+       int ret;
        int idx;
 
        idx = coda_next_free_instance(dev);
@@ -1523,12 +2390,19 @@ static int coda_open(struct file *file)
        if (!ctx)
                return -ENOMEM;
 
+       INIT_WORK(&ctx->skip_run, coda_skip_run);
        v4l2_fh_init(&ctx->fh, video_devdata(file));
        file->private_data = &ctx->fh;
        v4l2_fh_add(&ctx->fh);
        ctx->dev = dev;
        ctx->idx = idx;
-
+       switch (dev->devtype->product) {
+       case CODA_7541:
+               ctx->reg_idx = 0;
+               break;
+       default:
+               ctx->reg_idx = idx;
+       }
        set_default_params(ctx);
        ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
                                         &coda_queue_init);
@@ -1547,13 +2421,24 @@ static int coda_open(struct file *file)
 
        ctx->fh.ctrl_handler = &ctx->ctrls;
 
-       ctx->parabuf.vaddr = dma_alloc_coherent(&dev->plat_dev->dev,
-                       CODA_PARA_BUF_SIZE, &ctx->parabuf.paddr, GFP_KERNEL);
-       if (!ctx->parabuf.vaddr) {
+       ret = coda_alloc_context_buf(ctx, &ctx->parabuf, CODA_PARA_BUF_SIZE);
+       if (ret < 0) {
                v4l2_err(&dev->v4l2_dev, "failed to allocate parabuf");
+               goto err;
+       }
+
+       ctx->bitstream.size = CODA_MAX_FRAME_SIZE;
+       ctx->bitstream.vaddr = dma_alloc_writecombine(&dev->plat_dev->dev,
+                       ctx->bitstream.size, &ctx->bitstream.paddr, GFP_KERNEL);
+       if (!ctx->bitstream.vaddr) {
+               v4l2_err(&dev->v4l2_dev, "failed to allocate bitstream ringbuffer");
                ret = -ENOMEM;
                goto err;
        }
+       kfifo_init(&ctx->bitstream_fifo,
+               ctx->bitstream.vaddr, ctx->bitstream.size);
+       mutex_init(&ctx->bitstream_mutex);
+       mutex_init(&ctx->buffer_mutex);
 
        coda_lock(ctx);
        list_add(&ctx->list, &dev->instances);
@@ -1582,13 +2467,34 @@ static int coda_release(struct file *file)
        v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Releasing instance %p\n",
                 ctx);
 
+       /* If this instance is running, call .job_abort and wait for it to end */
+       v4l2_m2m_ctx_release(ctx->m2m_ctx);
+
+       /* In case the instance was not running, we still need to call SEQ_END */
+       mutex_lock(&dev->coda_mutex);
+       v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+                "%s: sent command 'SEQ_END' to coda\n", __func__);
+       if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) {
+               v4l2_err(&dev->v4l2_dev,
+                        "CODA_COMMAND_SEQ_END failed\n");
+               mutex_unlock(&dev->coda_mutex);
+               return -ETIMEDOUT;
+       }
+       mutex_unlock(&dev->coda_mutex);
+
+       coda_free_framebuffers(ctx);
+
        coda_lock(ctx);
        list_del(&ctx->list);
        coda_unlock(ctx);
 
-       dma_free_coherent(&dev->plat_dev->dev, CODA_PARA_BUF_SIZE,
-               ctx->parabuf.vaddr, ctx->parabuf.paddr);
-       v4l2_m2m_ctx_release(ctx->m2m_ctx);
+       dma_free_writecombine(&dev->plat_dev->dev, ctx->bitstream.size,
+               ctx->bitstream.vaddr, ctx->bitstream.paddr);
+       coda_free_context_buffers(ctx);
+       if (ctx->dev->devtype->product == CODA_DX6)
+               coda_free_aux_buf(dev, &ctx->workbuf);
+
+       coda_free_aux_buf(dev, &ctx->parabuf);
        v4l2_ctrl_handler_free(&ctx->ctrls);
        clk_disable_unprepare(dev->clk_per);
        clk_disable_unprepare(dev->clk_ahb);
@@ -1628,55 +2534,180 @@ static const struct v4l2_file_operations coda_fops = {
        .mmap           = coda_mmap,
 };
 
-static irqreturn_t coda_irq_handler(int irq, void *data)
+static void coda_finish_decode(struct coda_ctx *ctx)
 {
-       struct vb2_buffer *src_buf, *dst_buf;
-       struct coda_dev *dev = data;
-       u32 wr_ptr, start_ptr;
-       struct coda_ctx *ctx;
+       struct coda_dev *dev = ctx->dev;
+       struct coda_q_data *q_data_src;
+       struct coda_q_data *q_data_dst;
+       struct vb2_buffer *dst_buf;
+       int width, height;
+       int decoded_idx;
+       int display_idx;
+       u32 src_fourcc;
+       int success;
+       u32 val;
 
-       cancel_delayed_work(&dev->timeout);
+       dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
 
-       /* read status register to attend the IRQ */
-       coda_read(dev, CODA_REG_BIT_INT_STATUS);
-       coda_write(dev, CODA_REG_BIT_INT_CLEAR_SET,
-                     CODA_REG_BIT_INT_CLEAR);
+       /* Update kfifo out pointer from coda bitstream read pointer */
+       coda_kfifo_sync_from_device(ctx);
 
-       ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
-       if (ctx == NULL) {
-               v4l2_err(&dev->v4l2_dev, "Instance released before the end of transaction\n");
-               mutex_unlock(&dev->coda_mutex);
-               return IRQ_HANDLED;
+       /*
+        * in stream-end mode, the read pointer can overshoot the write pointer
+        * by up to 512 bytes
+        */
+       if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) {
+               if (coda_get_bitstream_payload(ctx) >= 0x100000 - 512)
+                       kfifo_init(&ctx->bitstream_fifo,
+                               ctx->bitstream.vaddr, ctx->bitstream.size);
        }
 
-       if (ctx->aborting) {
-               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                        "task has been aborted\n");
-               mutex_unlock(&dev->coda_mutex);
-               return IRQ_HANDLED;
+       q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+       src_fourcc = q_data_src->fourcc;
+
+       val = coda_read(dev, CODA_RET_DEC_PIC_SUCCESS);
+       if (val != 1)
+               pr_err("DEC_PIC_SUCCESS = %d\n", val);
+
+       success = val & 0x1;
+       if (!success)
+               v4l2_err(&dev->v4l2_dev, "decode failed\n");
+
+       if (src_fourcc == V4L2_PIX_FMT_H264) {
+               if (val & (1 << 3))
+                       v4l2_err(&dev->v4l2_dev,
+                                "insufficient PS buffer space (%d bytes)\n",
+                                ctx->psbuf.size);
+               if (val & (1 << 2))
+                       v4l2_err(&dev->v4l2_dev,
+                                "insufficient slice buffer space (%d bytes)\n",
+                                ctx->slicebuf.size);
        }
 
-       if (coda_isbusy(ctx->dev)) {
-               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-                        "coda is still busy!!!!\n");
-               return IRQ_NONE;
+       val = coda_read(dev, CODA_RET_DEC_PIC_SIZE);
+       width = (val >> 16) & 0xffff;
+       height = val & 0xffff;
+
+       q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+
+       val = coda_read(dev, CODA_RET_DEC_PIC_TYPE);
+       if ((val & 0x7) == 0) {
+               dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
+               dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME;
+       } else {
+               dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
+               dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME;
+       }
+
+       val = coda_read(dev, CODA_RET_DEC_PIC_ERR_MB);
+       if (val > 0)
+               v4l2_err(&dev->v4l2_dev,
+                        "errors in %d macroblocks\n", val);
+
+       if (dev->devtype->product == CODA_7541) {
+               val = coda_read(dev, CODA_RET_DEC_PIC_OPTION);
+               if (val == 0) {
+                       /* not enough bitstream data */
+                       v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+                                "prescan failed: %d\n", val);
+                       ctx->prescan_failed = true;
+                       return;
+               }
+       }
+
+       ctx->frm_dis_flg = coda_read(dev, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
+
+       /*
+        * The previous display frame was copied out by the rotator,
+        * now it can be overwritten again
+        */
+       if (ctx->display_idx >= 0 &&
+           ctx->display_idx < ctx->num_internal_frames) {
+               ctx->frm_dis_flg &= ~(1 << ctx->display_idx);
+               coda_write(dev, ctx->frm_dis_flg,
+                               CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
+       }
+
+       /*
+        * The index of the last decoded frame, not necessarily in
+        * display order, and the index of the next display frame.
+        * The latter could have been decoded in a previous run.
+        */
+       decoded_idx = coda_read(dev, CODA_RET_DEC_PIC_CUR_IDX);
+       display_idx = coda_read(dev, CODA_RET_DEC_PIC_FRAME_IDX);
+
+       if (decoded_idx == -1) {
+               /* no frame was decoded, but we might have a display frame */
+               if (display_idx < 0 && ctx->display_idx < 0)
+                       ctx->prescan_failed = true;
+       } else if (decoded_idx == -2) {
+               /* no frame was decoded, we still return the remaining buffers */
+       } else if (decoded_idx < 0 || decoded_idx >= ctx->num_internal_frames) {
+               v4l2_err(&dev->v4l2_dev,
+                        "decoded frame index out of range: %d\n", decoded_idx);
+       }
+
+       if (display_idx == -1) {
+               /*
+                * no more frames to be decoded, but there could still
+                * be rotator output to dequeue
+                */
+               ctx->prescan_failed = true;
+       } else if (display_idx == -3) {
+               /* possibly prescan failure */
+       } else if (display_idx < 0 || display_idx >= ctx->num_internal_frames) {
+               v4l2_err(&dev->v4l2_dev,
+                        "presentation frame index out of range: %d\n",
+                        display_idx);
+       }
+
+       /* If a frame was copied out, return it */
+       if (ctx->display_idx >= 0 &&
+           ctx->display_idx < ctx->num_internal_frames) {
+               dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+               dst_buf->v4l2_buf.sequence = ctx->osequence++;
+
+               vb2_set_plane_payload(dst_buf, 0, width * height * 3 / 2);
+
+               v4l2_m2m_buf_done(dst_buf, success ? VB2_BUF_STATE_DONE :
+                                                    VB2_BUF_STATE_ERROR);
+
+               v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+                       "job finished: decoding frame (%d) (%s)\n",
+                       dst_buf->v4l2_buf.sequence,
+                       (dst_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) ?
+                       "KEYFRAME" : "PFRAME");
+       } else {
+               v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+                       "job finished: no frame decoded\n");
        }
 
+       /* The rotator will copy the current display frame next time */
+       ctx->display_idx = display_idx;
+}
+
+static void coda_finish_encode(struct coda_ctx *ctx)
+{
+       struct vb2_buffer *src_buf, *dst_buf;
+       struct coda_dev *dev = ctx->dev;
+       u32 wr_ptr, start_ptr;
+
        src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
        dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
 
        /* Get results from the coda */
        coda_read(dev, CODA_RET_ENC_PIC_TYPE);
        start_ptr = coda_read(dev, CODA_CMD_ENC_PIC_BB_START);
-       wr_ptr = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx));
+       wr_ptr = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
+
        /* Calculate bytesused field */
        if (dst_buf->v4l2_buf.sequence == 0) {
-               dst_buf->v4l2_planes[0].bytesused = (wr_ptr - start_ptr) +
-                                               ctx->vpu_header_size[0] +
-                                               ctx->vpu_header_size[1] +
-                                               ctx->vpu_header_size[2];
+               vb2_set_plane_payload(dst_buf, 0, wr_ptr - start_ptr +
+                                       ctx->vpu_header_size[0] +
+                                       ctx->vpu_header_size[1] +
+                                       ctx->vpu_header_size[2]);
        } else {
-               dst_buf->v4l2_planes[0].bytesused = (wr_ptr - start_ptr);
+               vb2_set_plane_payload(dst_buf, 0, wr_ptr - start_ptr);
        }
 
        v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "frame size = %u\n",
@@ -1708,8 +2739,62 @@ static irqreturn_t coda_irq_handler(int irq, void *data)
                dst_buf->v4l2_buf.sequence,
                (dst_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) ?
                "KEYFRAME" : "PFRAME");
+}
+
+static irqreturn_t coda_irq_handler(int irq, void *data)
+{
+       struct coda_dev *dev = data;
+       struct coda_ctx *ctx;
+
+       cancel_delayed_work(&dev->timeout);
+
+       /* read status register to attend the IRQ */
+       coda_read(dev, CODA_REG_BIT_INT_STATUS);
+       coda_write(dev, CODA_REG_BIT_INT_CLEAR_SET,
+                     CODA_REG_BIT_INT_CLEAR);
+
+       ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
+       if (ctx == NULL) {
+               v4l2_err(&dev->v4l2_dev, "Instance released before the end of transaction\n");
+               mutex_unlock(&dev->coda_mutex);
+               return IRQ_HANDLED;
+       }
+
+       if (ctx->aborting) {
+               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                        "task has been aborted\n");
+               goto out;
+       }
+
+       if (coda_isbusy(ctx->dev)) {
+               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                        "coda is still busy!!!!\n");
+               return IRQ_NONE;
+       }
+
+       if (ctx->inst_type == CODA_INST_DECODER)
+               coda_finish_decode(ctx);
+       else
+               coda_finish_encode(ctx);
+
+out:
+       if (ctx->aborting || (!ctx->streamon_cap && !ctx->streamon_out)) {
+               v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+                        "%s: sent command 'SEQ_END' to coda\n", __func__);
+               if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) {
+                       v4l2_err(&dev->v4l2_dev,
+                                "CODA_COMMAND_SEQ_END failed\n");
+               }
+
+               kfifo_init(&ctx->bitstream_fifo,
+                       ctx->bitstream.vaddr, ctx->bitstream.size);
+
+               coda_free_framebuffers(ctx);
+               coda_free_context_buffers(ctx);
+       }
 
        mutex_unlock(&dev->coda_mutex);
+       mutex_unlock(&ctx->buffer_mutex);
 
        v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->m2m_ctx);
 
@@ -1726,6 +2811,8 @@ static void coda_timeout(struct work_struct *work)
 
        mutex_lock(&dev->dev_mutex);
        list_for_each_entry(ctx, &dev->instances, list) {
+               if (mutex_is_locked(&ctx->buffer_mutex))
+                       mutex_unlock(&ctx->buffer_mutex);
                v4l2_m2m_streamoff(NULL, ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
                v4l2_m2m_streamoff(NULL, ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
        }
@@ -1738,7 +2825,7 @@ static void coda_timeout(struct work_struct *work)
 
 static u32 coda_supported_firmwares[] = {
        CODA_FIRMWARE_VERNUM(CODA_DX6, 2, 2, 5),
-       CODA_FIRMWARE_VERNUM(CODA_7541, 13, 4, 29),
+       CODA_FIRMWARE_VERNUM(CODA_7541, 1, 4, 50),
 };
 
 static bool coda_firmware_supported(u32 vernum)
@@ -1803,8 +2890,14 @@ static int coda_hw_init(struct coda_dev *dev)
                coda_write(dev, 0, CODA_REG_BIT_CODE_BUF_ADDR + i * 4);
 
        /* Tell the BIT where to find everything it needs */
-       coda_write(dev, dev->workbuf.paddr,
-                     CODA_REG_BIT_WORK_BUF_ADDR);
+       if (dev->devtype->product == CODA_7541) {
+               coda_write(dev, dev->tempbuf.paddr,
+                               CODA_REG_BIT_TEMP_BUF_ADDR);
+               coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM);
+       } else {
+               coda_write(dev, dev->workbuf.paddr,
+                             CODA_REG_BIT_WORK_BUF_ADDR);
+       }
        coda_write(dev, dev->codebuf.paddr,
                      CODA_REG_BIT_CODE_BUF_ADDR);
        coda_write(dev, 0, CODA_REG_BIT_CODE_RUN);
@@ -1891,11 +2984,8 @@ static void coda_fw_callback(const struct firmware *fw, void *context)
        }
 
        /* allocate auxiliary per-device code buffer for the BIT processor */
-       dev->codebuf.size = fw->size;
-       dev->codebuf.vaddr = dma_alloc_coherent(&pdev->dev, fw->size,
-                                                   &dev->codebuf.paddr,
-                                                   GFP_KERNEL);
-       if (!dev->codebuf.vaddr) {
+       ret = coda_alloc_aux_buf(dev, &dev->codebuf, fw->size);
+       if (ret < 0) {
                dev_err(&pdev->dev, "failed to allocate code buffer\n");
                return;
        }
@@ -1987,7 +3077,7 @@ MODULE_DEVICE_TABLE(platform, coda_platform_ids);
 
 #ifdef CONFIG_OF
 static const struct of_device_id coda_dt_ids[] = {
-       { .compatible = "fsl,imx27-vpu", .data = &coda_platform_ids[CODA_IMX27] },
+       { .compatible = "fsl,imx27-vpu", .data = &coda_devdata[CODA_IMX27] },
        { .compatible = "fsl,imx53-vpu", .data = &coda_devdata[CODA_IMX53] },
        { /* sentinel */ }
 };
@@ -2048,8 +3138,8 @@ static int coda_probe(struct platform_device *pdev)
                return -ENOENT;
        }
 
-       if (devm_request_irq(&pdev->dev, irq, coda_irq_handler,
-               0, CODA_NAME, dev) < 0) {
+       if (devm_request_threaded_irq(&pdev->dev, irq, NULL, coda_irq_handler,
+               IRQF_ONESHOT, CODA_NAME, dev) < 0) {
                dev_err(&pdev->dev, "failed to request irq\n");
                return -ENOENT;
        }
@@ -2085,24 +3175,36 @@ static int coda_probe(struct platform_device *pdev)
        /* allocate auxiliary per-device buffers for the BIT processor */
        switch (dev->devtype->product) {
        case CODA_DX6:
-               dev->workbuf.size = CODADX6_WORK_BUF_SIZE;
+               ret = coda_alloc_aux_buf(dev, &dev->workbuf,
+                                        CODADX6_WORK_BUF_SIZE);
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "failed to allocate work buffer\n");
+                       v4l2_device_unregister(&dev->v4l2_dev);
+                       return ret;
+               }
+               break;
+       case CODA_7541:
+               dev->tempbuf.size = CODA7_TEMP_BUF_SIZE;
                break;
-       default:
-               dev->workbuf.size = CODA7_WORK_BUF_SIZE;
        }
-       dev->workbuf.vaddr = dma_alloc_coherent(&pdev->dev, dev->workbuf.size,
-                                                   &dev->workbuf.paddr,
-                                                   GFP_KERNEL);
-       if (!dev->workbuf.vaddr) {
-               dev_err(&pdev->dev, "failed to allocate work buffer\n");
-               v4l2_device_unregister(&dev->v4l2_dev);
-               return -ENOMEM;
+       if (dev->tempbuf.size) {
+               ret = coda_alloc_aux_buf(dev, &dev->tempbuf,
+                                        dev->tempbuf.size);
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "failed to allocate temp buffer\n");
+                       v4l2_device_unregister(&dev->v4l2_dev);
+                       return ret;
+               }
        }
 
-       if (dev->devtype->product == CODA_DX6)
+       switch (dev->devtype->product) {
+       case CODA_DX6:
                dev->iram_size = CODADX6_IRAM_SIZE;
-       else
+               break;
+       case CODA_7541:
                dev->iram_size = CODA7_IRAM_SIZE;
+               break;
+       }
        dev->iram_vaddr = gen_pool_alloc(dev->iram_pool, dev->iram_size);
        if (!dev->iram_vaddr) {
                dev_err(&pdev->dev, "unable to alloc iram\n");
@@ -2128,12 +3230,9 @@ static int coda_remove(struct platform_device *pdev)
        v4l2_device_unregister(&dev->v4l2_dev);
        if (dev->iram_vaddr)
                gen_pool_free(dev->iram_pool, dev->iram_vaddr, dev->iram_size);
-       if (dev->codebuf.vaddr)
-               dma_free_coherent(&pdev->dev, dev->codebuf.size,
-                                 &dev->codebuf.vaddr, dev->codebuf.paddr);
-       if (dev->workbuf.vaddr)
-               dma_free_coherent(&pdev->dev, dev->workbuf.size, &dev->workbuf.vaddr,
-                         dev->workbuf.paddr);
+       coda_free_aux_buf(dev, &dev->codebuf);
+       coda_free_aux_buf(dev, &dev->tempbuf);
+       coda_free_aux_buf(dev, &dev->workbuf);
        return 0;
 }
 
index ace0bf0a3b9cb245a5399a55ae7acd2594eb1a1d..4e32e2edea62005d8ae6c8d20da8bf071d417183 100644 (file)
 #define                CODA_STREAM_ENDIAN_SELECT       (1 << 0)
 #define CODA_REG_BIT_FRAME_MEM_CTRL            0x110
 #define                CODA_IMAGE_ENDIAN_SELECT        (1 << 0)
+#define CODA_REG_BIT_BIT_STREAM_PARAM          0x114
+#define                CODA_BIT_STREAM_END_FLAG        (1 << 2)
+#define                CODA_BIT_DEC_SEQ_INIT_ESCAPE    (1 << 0)
+#define CODA_REG_BIT_TEMP_BUF_ADDR             0x118
 #define CODA_REG_BIT_RD_PTR(x)                 (0x120 + 8 * (x))
 #define CODA_REG_BIT_WR_PTR(x)                 (0x124 + 8 * (x))
+#define CODA_REG_BIT_FRM_DIS_FLG(x)            (0x150 + 4 * (x))
 #define CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR   0x140
 #define CODA7_REG_BIT_AXI_SRAM_USE             0x140
-#define                CODA7_USE_BIT_ENABLE            (1 << 0)
+#define                CODA7_USE_HOST_ME_ENABLE        (1 << 11)
+#define                CODA7_USE_HOST_OVL_ENABLE       (1 << 10)
+#define                CODA7_USE_HOST_DBK_ENABLE       (1 << 9)
+#define                CODA7_USE_HOST_IP_ENABLE        (1 << 8)
 #define                CODA7_USE_HOST_BIT_ENABLE       (1 << 7)
 #define                CODA7_USE_ME_ENABLE             (1 << 4)
-#define                CODA7_USE_HOST_ME_ENABLE        (1 << 11)
+#define                CODA7_USE_OVL_ENABLE            (1 << 3)
+#define                CODA7_USE_DBK_ENABLE            (1 << 2)
+#define                CODA7_USE_IP_ENABLE             (1 << 1)
+#define                CODA7_USE_BIT_ENABLE            (1 << 0)
+
 #define CODA_REG_BIT_BUSY                      0x160
 #define                CODA_REG_BIT_BUSY_FLAG          1
 #define CODA_REG_BIT_RUN_COMMAND               0x164
 #define        CODA_MODE_INVALID               0xffff
 #define CODA_REG_BIT_INT_ENABLE                0x170
 #define                CODA_INT_INTERRUPT_ENABLE       (1 << 3)
+#define CODA_REG_BIT_INT_REASON                        0x174
+#define CODA7_REG_BIT_RUN_AUX_STD              0x178
+#define                CODA_MP4_AUX_MPEG4              0
+#define                CODA_MP4_AUX_DIVX3              1
+#define                CODA_VPX_AUX_THO                0
+#define                CODA_VPX_AUX_VP6                1
+#define                CODA_VPX_AUX_VP8                2
+#define                CODA_H264_AUX_AVC               0
+#define                CODA_H264_AUX_MVC               1
 
 /*
  * Commands' mailbox:
  * issued.
  */
 
+/* Decoder Sequence Initialization */
+#define CODA_CMD_DEC_SEQ_BB_START              0x180
+#define CODA_CMD_DEC_SEQ_BB_SIZE               0x184
+#define CODA_CMD_DEC_SEQ_OPTION                        0x188
+#define                CODA_REORDER_ENABLE                     (1 << 1)
+#define                CODADX6_QP_REPORT                       (1 << 0)
+#define                CODA7_MP4_DEBLK_ENABLE                  (1 << 0)
+#define CODA_CMD_DEC_SEQ_SRC_SIZE              0x18c
+#define CODA_CMD_DEC_SEQ_START_BYTE            0x190
+#define CODA_CMD_DEC_SEQ_PS_BB_START           0x194
+#define CODA_CMD_DEC_SEQ_PS_BB_SIZE            0x198
+#define CODA_CMD_DEC_SEQ_MP4_ASP_CLASS         0x19c
+#define CODA_CMD_DEC_SEQ_X264_MV_EN            0x19c
+#define CODA_CMD_DEC_SEQ_SPP_CHUNK_SIZE                0x1a0
+
+#define CODA7_RET_DEC_SEQ_ASPECT               0x1b0
+#define CODA_RET_DEC_SEQ_SUCCESS               0x1c0
+#define CODA_RET_DEC_SEQ_SRC_FMT               0x1c4 /* SRC_SIZE on CODA7 */
+#define CODA_RET_DEC_SEQ_SRC_SIZE              0x1c4
+#define CODA_RET_DEC_SEQ_SRC_F_RATE            0x1c8
+#define CODA9_RET_DEC_SEQ_ASPECT               0x1c8
+#define CODA_RET_DEC_SEQ_FRAME_NEED            0x1cc
+#define CODA_RET_DEC_SEQ_FRAME_DELAY           0x1d0
+#define CODA_RET_DEC_SEQ_INFO                  0x1d4
+#define CODA_RET_DEC_SEQ_CROP_LEFT_RIGHT       0x1d8
+#define CODA_RET_DEC_SEQ_CROP_TOP_BOTTOM       0x1dc
+#define CODA_RET_DEC_SEQ_NEXT_FRAME_NUM                0x1e0
+#define CODA_RET_DEC_SEQ_ERR_REASON            0x1e0
+#define CODA_RET_DEC_SEQ_FRATE_NR              0x1e4
+#define CODA_RET_DEC_SEQ_FRATE_DR              0x1e8
+#define CODA_RET_DEC_SEQ_JPG_PARA              0x1e4
+#define CODA_RET_DEC_SEQ_JPG_THUMB_IND         0x1e8
+
+/* Decoder Picture Run */
+#define CODA_CMD_DEC_PIC_ROT_MODE              0x180
+#define CODA_CMD_DEC_PIC_ROT_ADDR_Y            0x184
+#define CODA_CMD_DEC_PIC_ROT_ADDR_CB           0x188
+#define CODA_CMD_DEC_PIC_ROT_ADDR_CR           0x18c
+#define CODA_CMD_DEC_PIC_ROT_STRIDE            0x190
+
+#define CODA_CMD_DEC_PIC_OPTION                        0x194
+#define                CODA_PRE_SCAN_EN                        (1 << 0)
+#define                CODA_PRE_SCAN_MODE_DECODE               (0 << 1)
+#define                CODA_PRE_SCAN_MODE_RETURN               (1 << 1)
+#define                CODA_IFRAME_SEARCH_EN                   (1 << 2)
+#define                CODA_SKIP_FRAME_MODE                    (0x3 << 3)
+#define CODA_CMD_DEC_PIC_SKIP_NUM              0x198
+#define CODA_CMD_DEC_PIC_CHUNK_SIZE            0x19c
+#define CODA_CMD_DEC_PIC_BB_START              0x1a0
+#define CODA_CMD_DEC_PIC_START_BYTE            0x1a4
+#define CODA_RET_DEC_PIC_SIZE                  0x1bc
+#define CODA_RET_DEC_PIC_FRAME_NUM             0x1c0
+#define CODA_RET_DEC_PIC_FRAME_IDX             0x1c4
+#define CODA_RET_DEC_PIC_ERR_MB                        0x1c8
+#define CODA_RET_DEC_PIC_TYPE                  0x1cc
+#define                CODA_PIC_TYPE_MASK                      0x7
+#define                CODA_PIC_TYPE_MASK_VC1                  0x3f
+#define                CODA9_PIC_TYPE_FIRST_MASK               (0x7 << 3)
+#define                CODA9_PIC_TYPE_IDR_MASK                 (0x3 << 6)
+#define                CODA7_PIC_TYPE_H264_NPF_MASK            (0x3 << 16)
+#define                CODA7_PIC_TYPE_INTERLACED               (1 << 18)
+#define CODA_RET_DEC_PIC_POST                  0x1d0
+#define CODA_RET_DEC_PIC_MVC_REPORT            0x1d0
+#define CODA_RET_DEC_PIC_OPTION                        0x1d4
+#define CODA_RET_DEC_PIC_SUCCESS               0x1d8
+#define CODA_RET_DEC_PIC_CUR_IDX               0x1dc
+#define CODA_RET_DEC_PIC_CROP_LEFT_RIGHT       0x1e0
+#define CODA_RET_DEC_PIC_CROP_TOP_BOTTOM       0x1e4
+#define CODA_RET_DEC_PIC_FRAME_NEED            0x1ec
+
 /* Encoder Sequence Initialization */
 #define CODA_CMD_ENC_SEQ_BB_START                              0x180
 #define CODA_CMD_ENC_SEQ_BB_SIZE                               0x184
 #define CODA_CMD_ENC_SEQ_OPTION                                0x188
+#define                CODA7_OPTION_AVCINTRA16X16ONLY_OFFSET           9
 #define                CODA7_OPTION_GAMMA_OFFSET                       8
+#define                CODA7_OPTION_RCQPMAX_OFFSET                     7
 #define                CODADX6_OPTION_GAMMA_OFFSET                     7
+#define                CODA7_OPTION_RCQPMIN_OFFSET                     6
 #define                CODA_OPTION_LIMITQP_OFFSET                      6
 #define                CODA_OPTION_RCINTRAQP_OFFSET                    5
 #define                CODA_OPTION_FMO_OFFSET                          4
+#define                CODA_OPTION_AVC_AUD_OFFSET                      2
 #define                CODA_OPTION_SLICEREPORT_OFFSET                  1
 #define CODA_CMD_ENC_SEQ_COD_STD                               0x18c
 #define                CODA_STD_MPEG4                                  0
 #define                CODA_FMOPARAM_TYPE_MASK                         1
 #define                CODA_FMOPARAM_SLICENUM_OFFSET                   0
 #define                CODA_FMOPARAM_SLICENUM_MASK                     0x0f
+#define CODADX6_CMD_ENC_SEQ_INTRA_QP                           0x1bc
 #define CODA7_CMD_ENC_SEQ_SEARCH_BASE                          0x1b8
 #define CODA7_CMD_ENC_SEQ_SEARCH_SIZE                          0x1bc
+#define CODA7_CMD_ENC_SEQ_INTRA_QP                             0x1c4
 #define CODA_CMD_ENC_SEQ_RC_QP_MAX                             0x1c8
 #define                CODA_QPMAX_OFFSET                               0
 #define                CODA_QPMAX_MASK                                 0x3f
 #define CODA_CMD_ENC_PIC_OPTION        0x194
 #define CODA_CMD_ENC_PIC_BB_START      0x198
 #define CODA_CMD_ENC_PIC_BB_SIZE       0x19c
+#define CODA_RET_ENC_FRAME_NUM         0x1c0
 #define CODA_RET_ENC_PIC_TYPE          0x1c4
+#define CODA_RET_ENC_PIC_FRAME_IDX     0x1c8
 #define CODA_RET_ENC_PIC_SLICE_NUM     0x1cc
 #define CODA_RET_ENC_PIC_FLAG          0x1d0
+#define CODA_RET_ENC_PIC_SUCCESS       0x1d8
 
 /* Set Frame Buffer */
 #define CODA_CMD_SET_FRAME_BUF_NUM             0x180
 #define CODA_CMD_SET_FRAME_BUF_STRIDE          0x184
+#define CODA_CMD_SET_FRAME_SLICE_BB_START      0x188
+#define CODA_CMD_SET_FRAME_SLICE_BB_SIZE       0x18c
 #define CODA7_CMD_SET_FRAME_AXI_BIT_ADDR       0x190
 #define CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR    0x194
 #define CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR      0x198
 #define CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR      0x19c
 #define CODA7_CMD_SET_FRAME_AXI_OVL_ADDR       0x1a0
+#define CODA7_CMD_SET_FRAME_MAX_DEC_SIZE       0x1a4
 #define CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE  0x1a8
 
 /* Encoder Header */
index e180ff7282d9eb7f5aa556ba66822482b91adca8..04609cc6eba70a3a5ad40c04a01a4308bccb8403 100644 (file)
@@ -1743,11 +1743,10 @@ static int vpbe_display_probe(struct platform_device *pdev)
 
        printk(KERN_DEBUG "vpbe_display_probe\n");
        /* Allocate memory for vpbe_display */
-       disp_dev = kzalloc(sizeof(struct vpbe_display), GFP_KERNEL);
-       if (!disp_dev) {
-               printk(KERN_ERR "ran out of memory\n");
+       disp_dev = devm_kzalloc(&pdev->dev, sizeof(struct vpbe_display),
+                               GFP_KERNEL);
+       if (!disp_dev)
                return -ENOMEM;
-       }
 
        spin_lock_init(&disp_dev->dma_queue_lock);
        /*
@@ -1786,26 +1785,24 @@ static int vpbe_display_probe(struct platform_device *pdev)
        }
 
        irq = res->start;
-       if (request_irq(irq, venc_isr,  IRQF_DISABLED, VPBE_DISPLAY_DRIVER,
-               disp_dev)) {
+       err = devm_request_irq(&pdev->dev, irq, venc_isr, IRQF_DISABLED,
+                              VPBE_DISPLAY_DRIVER, disp_dev);
+       if (err) {
                v4l2_err(&disp_dev->vpbe_dev->v4l2_dev,
                                "Unable to request interrupt\n");
-               err = -ENODEV;
                goto probe_out;
        }
 
        for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) {
                if (register_device(disp_dev->dev[i], disp_dev, pdev)) {
                        err = -ENODEV;
-                       goto probe_out_irq;
+                       goto probe_out;
                }
        }
 
        printk(KERN_DEBUG "Successfully completed the probing of vpbe v4l2 device\n");
        return 0;
 
-probe_out_irq:
-       free_irq(res->start, disp_dev);
 probe_out:
        for (k = 0; k < VPBE_DISPLAY_MAX_DEVICES; k++) {
                /* Get the pointer to the layer object */
@@ -1817,7 +1814,6 @@ probe_out:
                                kfree(disp_dev->dev[k]);
                }
        }
-       kfree(disp_dev);
        return err;
 }
 
@@ -1830,15 +1826,10 @@ static int vpbe_display_remove(struct platform_device *pdev)
        struct vpbe_layer *vpbe_display_layer;
        struct vpbe_display *disp_dev = platform_get_drvdata(pdev);
        struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
-       struct resource *res;
        int i;
 
        v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_remove\n");
 
-       /* unregister irq */
-       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       free_irq(res->start, disp_dev);
-
        /* deinitialize the vpbe display controller */
        if (NULL != vpbe_dev->ops.deinitialize)
                vpbe_dev->ops.deinitialize(&pdev->dev, vpbe_dev);
index 6ed82e8b297bf7861847f7bb9ca085b728c36810..d053c2669c1fff0e0e140d0e5e92247ac56b0d25 100644 (file)
@@ -1547,61 +1547,36 @@ static int osd_probe(struct platform_device *pdev)
        const struct platform_device_id *pdev_id;
        struct osd_state *osd;
        struct resource *res;
-       int ret = 0;
 
-       osd = kzalloc(sizeof(struct osd_state), GFP_KERNEL);
+       pdev_id = platform_get_device_id(pdev);
+       if (!pdev_id)
+               return -EINVAL;
+
+       osd = devm_kzalloc(&pdev->dev, sizeof(struct osd_state), GFP_KERNEL);
        if (osd == NULL)
                return -ENOMEM;
 
-       pdev_id = platform_get_device_id(pdev);
-       if (!pdev_id) {
-               ret = -EINVAL;
-               goto free_mem;
-       }
 
        osd->dev = &pdev->dev;
        osd->vpbe_type = pdev_id->driver_data;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(osd->dev, "Unable to get OSD register address map\n");
-               ret = -ENODEV;
-               goto free_mem;
-       }
+       osd->osd_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(osd->osd_base))
+               return PTR_ERR(osd->osd_base);
+
        osd->osd_base_phys = res->start;
        osd->osd_size = resource_size(res);
-       if (!request_mem_region(osd->osd_base_phys, osd->osd_size,
-                               MODULE_NAME)) {
-               dev_err(osd->dev, "Unable to reserve OSD MMIO region\n");
-               ret = -ENODEV;
-               goto free_mem;
-       }
-       osd->osd_base = ioremap_nocache(res->start, osd->osd_size);
-       if (!osd->osd_base) {
-               dev_err(osd->dev, "Unable to map the OSD region\n");
-               ret = -ENODEV;
-               goto release_mem_region;
-       }
        spin_lock_init(&osd->lock);
        osd->ops = osd_ops;
        platform_set_drvdata(pdev, osd);
        dev_notice(osd->dev, "OSD sub device probe success\n");
-       return ret;
 
-release_mem_region:
-       release_mem_region(osd->osd_base_phys, osd->osd_size);
-free_mem:
-       kfree(osd);
-       return ret;
+       return 0;
 }
 
 static int osd_remove(struct platform_device *pdev)
 {
-       struct osd_state *osd = platform_get_drvdata(pdev);
-
-       iounmap((void *)osd->osd_base);
-       release_mem_region(osd->osd_base_phys, osd->osd_size);
-       kfree(osd);
        return 0;
 }
 
index 87eef9be08ede65d5e7ad2683b2cc154f596603a..14a023a75d2d3c026a9e59bac16f0e7b6bf38bfc 100644 (file)
@@ -639,105 +639,46 @@ static int venc_probe(struct platform_device *pdev)
        const struct platform_device_id *pdev_id;
        struct venc_state *venc;
        struct resource *res;
-       int ret;
 
-       venc = kzalloc(sizeof(struct venc_state), GFP_KERNEL);
+       if (!pdev->dev.platform_data) {
+               dev_err(&pdev->dev, "No platform data for VENC sub device");
+               return -EINVAL;
+       }
+
+       pdev_id = platform_get_device_id(pdev);
+       if (!pdev_id)
+               return -EINVAL;
+
+       venc = devm_kzalloc(&pdev->dev, sizeof(struct venc_state), GFP_KERNEL);
        if (venc == NULL)
                return -ENOMEM;
 
-       pdev_id = platform_get_device_id(pdev);
-       if (!pdev_id) {
-               ret = -EINVAL;
-               goto free_mem;
-       }
        venc->venc_type = pdev_id->driver_data;
        venc->pdev = &pdev->dev;
        venc->pdata = pdev->dev.platform_data;
-       if (NULL == venc->pdata) {
-               dev_err(venc->pdev, "Unable to get platform data for"
-                       " VENC sub device");
-               ret = -ENOENT;
-               goto free_mem;
-       }
+
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(venc->pdev,
-                       "Unable to get VENC register address map\n");
-               ret = -ENODEV;
-               goto free_mem;
-       }
 
-       if (!request_mem_region(res->start, resource_size(res), "venc")) {
-               dev_err(venc->pdev, "Unable to reserve VENC MMIO region\n");
-               ret = -ENODEV;
-               goto free_mem;
-       }
-
-       venc->venc_base = ioremap_nocache(res->start, resource_size(res));
-       if (!venc->venc_base) {
-               dev_err(venc->pdev, "Unable to map VENC IO space\n");
-               ret = -ENODEV;
-               goto release_venc_mem_region;
-       }
+       venc->venc_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(venc->venc_base))
+               return PTR_ERR(venc->venc_base);
 
        if (venc->venc_type != VPBE_VERSION_1) {
                res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-               if (!res) {
-                       dev_err(venc->pdev,
-                               "Unable to get VDAC_CONFIG address map\n");
-                       ret = -ENODEV;
-                       goto unmap_venc_io;
-               }
-
-               if (!request_mem_region(res->start,
-                                       resource_size(res), "venc")) {
-                       dev_err(venc->pdev,
-                               "Unable to reserve VDAC_CONFIG  MMIO region\n");
-                       ret = -ENODEV;
-                       goto unmap_venc_io;
-               }
-
-               venc->vdaccfg_reg = ioremap_nocache(res->start,
-                                                   resource_size(res));
-               if (!venc->vdaccfg_reg) {
-                       dev_err(venc->pdev,
-                               "Unable to map VDAC_CONFIG IO space\n");
-                       ret = -ENODEV;
-                       goto release_vdaccfg_mem_region;
-               }
+
+               venc->vdaccfg_reg = devm_ioremap_resource(&pdev->dev, res);
+               if (IS_ERR(venc->vdaccfg_reg))
+                       return PTR_ERR(venc->vdaccfg_reg);
        }
        spin_lock_init(&venc->lock);
        platform_set_drvdata(pdev, venc);
        dev_notice(venc->pdev, "VENC sub device probe success\n");
-       return 0;
 
-release_vdaccfg_mem_region:
-       release_mem_region(res->start, resource_size(res));
-unmap_venc_io:
-       iounmap(venc->venc_base);
-release_venc_mem_region:
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(res->start, resource_size(res));
-free_mem:
-       kfree(venc);
-       return ret;
+       return 0;
 }
 
 static int venc_remove(struct platform_device *pdev)
 {
-       struct venc_state *venc = platform_get_drvdata(pdev);
-       struct resource *res;
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       iounmap((void *)venc->venc_base);
-       release_mem_region(res->start, resource_size(res));
-       if (venc->venc_type != VPBE_VERSION_1) {
-               res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-               iounmap((void *)venc->vdaccfg_reg);
-               release_mem_region(res->start, resource_size(res));
-       }
-       kfree(venc);
-
        return 0;
 }
 
index 5514175bbd072ec92b9e4a1a472b5d00e3f51088..7fbde6d790b5fb1e2173cbebd385ff060e74e553 100644 (file)
@@ -1979,6 +1979,76 @@ vpif_init_free_channel_objects:
        return err;
 }
 
+static int vpif_async_bound(struct v4l2_async_notifier *notifier,
+                           struct v4l2_subdev *subdev,
+                           struct v4l2_async_subdev *asd)
+{
+       int i;
+
+       for (i = 0; i < vpif_obj.config->subdev_count; i++)
+               if (!strcmp(vpif_obj.config->subdev_info[i].name,
+                           subdev->name)) {
+                       vpif_obj.sd[i] = subdev;
+                       return 0;
+               }
+
+       return -EINVAL;
+}
+
+static int vpif_probe_complete(void)
+{
+       struct common_obj *common;
+       struct channel_obj *ch;
+       int i, j, err, k;
+
+       for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) {
+               ch = vpif_obj.dev[j];
+               ch->channel_id = j;
+               common = &(ch->common[VPIF_VIDEO_INDEX]);
+               spin_lock_init(&common->irqlock);
+               mutex_init(&common->lock);
+               ch->video_dev->lock = &common->lock;
+               /* Initialize prio member of channel object */
+               v4l2_prio_init(&ch->prio);
+               video_set_drvdata(ch->video_dev, ch);
+
+               /* select input 0 */
+               err = vpif_set_input(vpif_obj.config, ch, 0);
+               if (err)
+                       goto probe_out;
+
+               err = video_register_device(ch->video_dev,
+                                           VFL_TYPE_GRABBER, (j ? 1 : 0));
+               if (err)
+                       goto probe_out;
+       }
+
+       v4l2_info(&vpif_obj.v4l2_dev, "VPIF capture driver initialized\n");
+       return 0;
+
+probe_out:
+       for (k = 0; k < j; k++) {
+               /* Get the pointer to the channel object */
+               ch = vpif_obj.dev[k];
+               /* Unregister video device */
+               video_unregister_device(ch->video_dev);
+       }
+       kfree(vpif_obj.sd);
+       for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) {
+               ch = vpif_obj.dev[i];
+               /* Note: does nothing if ch->video_dev == NULL */
+               video_device_release(ch->video_dev);
+       }
+       v4l2_device_unregister(&vpif_obj.v4l2_dev);
+
+       return err;
+}
+
+static int vpif_async_complete(struct v4l2_async_notifier *notifier)
+{
+       return vpif_probe_complete();
+}
+
 /**
  * vpif_probe : This function probes the vpif capture driver
  * @pdev: platform device pointer
@@ -1989,12 +2059,10 @@ vpif_init_free_channel_objects:
 static __init int vpif_probe(struct platform_device *pdev)
 {
        struct vpif_subdev_info *subdevdata;
-       struct vpif_capture_config *config;
-       int i, j, k, err;
+       int i, j, err;
        int res_idx = 0;
        struct i2c_adapter *i2c_adap;
        struct channel_obj *ch;
-       struct common_obj *common;
        struct video_device *vfd;
        struct resource *res;
        int subdev_count;
@@ -2068,10 +2136,9 @@ static __init int vpif_probe(struct platform_device *pdev)
                }
        }
 
-       i2c_adap = i2c_get_adapter(1);
-       config = pdev->dev.platform_data;
+       vpif_obj.config = pdev->dev.platform_data;
 
-       subdev_count = config->subdev_count;
+       subdev_count = vpif_obj.config->subdev_count;
        vpif_obj.sd = kzalloc(sizeof(struct v4l2_subdev *) * subdev_count,
                                GFP_KERNEL);
        if (vpif_obj.sd == NULL) {
@@ -2080,54 +2147,42 @@ static __init int vpif_probe(struct platform_device *pdev)
                goto vpif_sd_error;
        }
 
-       for (i = 0; i < subdev_count; i++) {
-               subdevdata = &config->subdev_info[i];
-               vpif_obj.sd[i] =
-                       v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev,
-                                                 i2c_adap,
-                                                 &subdevdata->board_info,
-                                                 NULL);
-
-               if (!vpif_obj.sd[i]) {
-                       vpif_err("Error registering v4l2 subdevice\n");
-                       err = -ENODEV;
+       if (!vpif_obj.config->asd_sizes) {
+               i2c_adap = i2c_get_adapter(1);
+               for (i = 0; i < subdev_count; i++) {
+                       subdevdata = &vpif_obj.config->subdev_info[i];
+                       vpif_obj.sd[i] =
+                               v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev,
+                                                         i2c_adap,
+                                                         &subdevdata->
+                                                         board_info,
+                                                         NULL);
+
+                       if (!vpif_obj.sd[i]) {
+                               vpif_err("Error registering v4l2 subdevice\n");
+                               goto probe_subdev_out;
+                       }
+                       v4l2_info(&vpif_obj.v4l2_dev,
+                                 "registered sub device %s\n",
+                                  subdevdata->name);
+               }
+               vpif_probe_complete();
+       } else {
+               vpif_obj.notifier.subdevs = vpif_obj.config->asd;
+               vpif_obj.notifier.num_subdevs = vpif_obj.config->asd_sizes[0];
+               vpif_obj.notifier.bound = vpif_async_bound;
+               vpif_obj.notifier.complete = vpif_async_complete;
+               err = v4l2_async_notifier_register(&vpif_obj.v4l2_dev,
+                                                  &vpif_obj.notifier);
+               if (err) {
+                       vpif_err("Error registering async notifier\n");
+                       err = -EINVAL;
                        goto probe_subdev_out;
                }
-               v4l2_info(&vpif_obj.v4l2_dev, "registered sub device %s\n",
-                         subdevdata->name);
        }
 
-       for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) {
-               ch = vpif_obj.dev[j];
-               ch->channel_id = j;
-               common = &(ch->common[VPIF_VIDEO_INDEX]);
-               spin_lock_init(&common->irqlock);
-               mutex_init(&common->lock);
-               ch->video_dev->lock = &common->lock;
-               /* Initialize prio member of channel object */
-               v4l2_prio_init(&ch->prio);
-               video_set_drvdata(ch->video_dev, ch);
-
-               /* select input 0 */
-               err = vpif_set_input(config, ch, 0);
-               if (err)
-                       goto probe_out;
-
-               err = video_register_device(ch->video_dev,
-                                           VFL_TYPE_GRABBER, (j ? 1 : 0));
-               if (err)
-                       goto probe_out;
-       }
-       v4l2_info(&vpif_obj.v4l2_dev, "VPIF capture driver initialized\n");
        return 0;
 
-probe_out:
-       for (k = 0; k < j; k++) {
-               /* Get the pointer to the channel object */
-               ch = vpif_obj.dev[k];
-               /* Unregister video device */
-               video_unregister_device(ch->video_dev);
-       }
 probe_subdev_out:
        /* free sub devices memory */
        kfree(vpif_obj.sd);
index 0ebb312603690f39ccc102eee04a8375c1ac4e36..5a29d9a0cae12c1a15fd74b7a7ab19f9f89731c5 100644 (file)
@@ -142,6 +142,8 @@ struct vpif_device {
        struct v4l2_device v4l2_dev;
        struct channel_obj *dev[VPIF_CAPTURE_NUM_CHANNELS];
        struct v4l2_subdev **sd;
+       struct v4l2_async_notifier notifier;
+       struct vpif_capture_config *config;
 };
 
 struct vpif_config_params {
index e6e57365025020f746e5958b357525e8b9a7dfce..6336dfc864822024e13800c81062f5c2b0af24ba 100644 (file)
@@ -1618,6 +1618,102 @@ vpif_init_free_channel_objects:
        return err;
 }
 
+static int vpif_async_bound(struct v4l2_async_notifier *notifier,
+                           struct v4l2_subdev *subdev,
+                           struct v4l2_async_subdev *asd)
+{
+       int i;
+
+       for (i = 0; i < vpif_obj.config->subdev_count; i++)
+               if (!strcmp(vpif_obj.config->subdevinfo[i].name,
+                           subdev->name)) {
+                       vpif_obj.sd[i] = subdev;
+                       vpif_obj.sd[i]->grp_id = 1 << i;
+                       return 0;
+               }
+
+       return -EINVAL;
+}
+
+static int vpif_probe_complete(void)
+{
+       struct common_obj *common;
+       struct channel_obj *ch;
+       int j, err, k;
+
+       for (j = 0; j < VPIF_DISPLAY_MAX_DEVICES; j++) {
+               ch = vpif_obj.dev[j];
+               /* Initialize field of the channel objects */
+               atomic_set(&ch->usrs, 0);
+               for (k = 0; k < VPIF_NUMOBJECTS; k++) {
+                       ch->common[k].numbuffers = 0;
+                       common = &ch->common[k];
+                       common->io_usrs = 0;
+                       common->started = 0;
+                       spin_lock_init(&common->irqlock);
+                       mutex_init(&common->lock);
+                       common->numbuffers = 0;
+                       common->set_addr = NULL;
+                       common->ytop_off = 0;
+                       common->ybtm_off = 0;
+                       common->ctop_off = 0;
+                       common->cbtm_off = 0;
+                       common->cur_frm = NULL;
+                       common->next_frm = NULL;
+                       memset(&common->fmt, 0, sizeof(common->fmt));
+                       common->numbuffers = config_params.numbuffers[k];
+               }
+               ch->initialized = 0;
+               if (vpif_obj.config->subdev_count)
+                       ch->sd = vpif_obj.sd[0];
+               ch->channel_id = j;
+               if (j < 2)
+                       ch->common[VPIF_VIDEO_INDEX].numbuffers =
+                           config_params.numbuffers[ch->channel_id];
+               else
+                       ch->common[VPIF_VIDEO_INDEX].numbuffers = 0;
+
+               memset(&ch->vpifparams, 0, sizeof(ch->vpifparams));
+
+               /* Initialize prio member of channel object */
+               v4l2_prio_init(&ch->prio);
+               ch->common[VPIF_VIDEO_INDEX].fmt.type =
+                                               V4L2_BUF_TYPE_VIDEO_OUTPUT;
+               ch->video_dev->lock = &common->lock;
+               video_set_drvdata(ch->video_dev, ch);
+
+               /* select output 0 */
+               err = vpif_set_output(vpif_obj.config, ch, 0);
+               if (err)
+                       goto probe_out;
+
+               /* register video device */
+               vpif_dbg(1, debug, "channel=%x,channel->video_dev=%x\n",
+                        (int)ch, (int)&ch->video_dev);
+
+               err = video_register_device(ch->video_dev,
+                                         VFL_TYPE_GRABBER, (j ? 3 : 2));
+               if (err < 0)
+                       goto probe_out;
+       }
+
+       return 0;
+
+probe_out:
+       for (k = 0; k < j; k++) {
+               ch = vpif_obj.dev[k];
+               video_unregister_device(ch->video_dev);
+               video_device_release(ch->video_dev);
+               ch->video_dev = NULL;
+       }
+       return err;
+}
+
+static int vpif_async_complete(struct v4l2_async_notifier *notifier)
+{
+       return vpif_probe_complete();
+}
+
 /*
  * vpif_probe: This function creates device entries by register itself to the
  * V4L2 driver and initializes fields of each channel objects
@@ -1625,11 +1721,9 @@ vpif_init_free_channel_objects:
 static __init int vpif_probe(struct platform_device *pdev)
 {
        struct vpif_subdev_info *subdevdata;
-       struct vpif_display_config *config;
-       int i, j = 0, k, err = 0;
+       int i, j = 0, err = 0;
        int res_idx = 0;
        struct i2c_adapter *i2c_adap;
-       struct common_obj *common;
        struct channel_obj *ch;
        struct video_device *vfd;
        struct resource *res;
@@ -1708,11 +1802,9 @@ static __init int vpif_probe(struct platform_device *pdev)
                                                                        size/2;
                }
        }
-
-       i2c_adap = i2c_get_adapter(1);
-       config = pdev->dev.platform_data;
-       subdev_count = config->subdev_count;
-       subdevdata = config->subdevinfo;
+       vpif_obj.config = pdev->dev.platform_data;
+       subdev_count = vpif_obj.config->subdev_count;
+       subdevdata = vpif_obj.config->subdevinfo;
        vpif_obj.sd = kzalloc(sizeof(struct v4l2_subdev *) * subdev_count,
                                                                GFP_KERNEL);
        if (vpif_obj.sd == NULL) {
@@ -1721,86 +1813,40 @@ static __init int vpif_probe(struct platform_device *pdev)
                goto vpif_sd_error;
        }
 
-       for (i = 0; i < subdev_count; i++) {
-               vpif_obj.sd[i] = v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev,
-                                               i2c_adap,
-                                               &subdevdata[i].board_info,
-                                               NULL);
-               if (!vpif_obj.sd[i]) {
-                       vpif_err("Error registering v4l2 subdevice\n");
-                       err = -ENODEV;
-                       goto probe_subdev_out;
-               }
-
-               if (vpif_obj.sd[i])
-                       vpif_obj.sd[i]->grp_id = 1 << i;
-       }
-
-       for (j = 0; j < VPIF_DISPLAY_MAX_DEVICES; j++) {
-               ch = vpif_obj.dev[j];
-               /* Initialize field of the channel objects */
-               atomic_set(&ch->usrs, 0);
-               for (k = 0; k < VPIF_NUMOBJECTS; k++) {
-                       ch->common[k].numbuffers = 0;
-                       common = &ch->common[k];
-                       common->io_usrs = 0;
-                       common->started = 0;
-                       spin_lock_init(&common->irqlock);
-                       mutex_init(&common->lock);
-                       common->numbuffers = 0;
-                       common->set_addr = NULL;
-                       common->ytop_off = common->ybtm_off = 0;
-                       common->ctop_off = common->cbtm_off = 0;
-                       common->cur_frm = common->next_frm = NULL;
-                       memset(&common->fmt, 0, sizeof(common->fmt));
-                       common->numbuffers = config_params.numbuffers[k];
+       if (!vpif_obj.config->asd_sizes) {
+               i2c_adap = i2c_get_adapter(1);
+               for (i = 0; i < subdev_count; i++) {
+                       vpif_obj.sd[i] =
+                               v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev,
+                                                         i2c_adap,
+                                                         &subdevdata[i].
+                                                         board_info,
+                                                         NULL);
+                       if (!vpif_obj.sd[i]) {
+                               vpif_err("Error registering v4l2 subdevice\n");
+                               goto probe_subdev_out;
+                       }
 
+                       if (vpif_obj.sd[i])
+                               vpif_obj.sd[i]->grp_id = 1 << i;
+               }
+               vpif_probe_complete();
+       } else {
+               vpif_obj.notifier.subdevs = vpif_obj.config->asd;
+               vpif_obj.notifier.num_subdevs = vpif_obj.config->asd_sizes[0];
+               vpif_obj.notifier.bound = vpif_async_bound;
+               vpif_obj.notifier.complete = vpif_async_complete;
+               err = v4l2_async_notifier_register(&vpif_obj.v4l2_dev,
+                                                  &vpif_obj.notifier);
+               if (err) {
+                       vpif_err("Error registering async notifier\n");
+                       err = -EINVAL;
+                       goto probe_subdev_out;
                }
-               ch->initialized = 0;
-               if (subdev_count)
-                       ch->sd = vpif_obj.sd[0];
-               ch->channel_id = j;
-               if (j < 2)
-                       ch->common[VPIF_VIDEO_INDEX].numbuffers =
-                           config_params.numbuffers[ch->channel_id];
-               else
-                       ch->common[VPIF_VIDEO_INDEX].numbuffers = 0;
-
-               memset(&ch->vpifparams, 0, sizeof(ch->vpifparams));
-
-               /* Initialize prio member of channel object */
-               v4l2_prio_init(&ch->prio);
-               ch->common[VPIF_VIDEO_INDEX].fmt.type =
-                                               V4L2_BUF_TYPE_VIDEO_OUTPUT;
-               ch->video_dev->lock = &common->lock;
-               video_set_drvdata(ch->video_dev, ch);
-
-               /* select output 0 */
-               err = vpif_set_output(config, ch, 0);
-               if (err)
-                       goto probe_out;
-
-               /* register video device */
-               vpif_dbg(1, debug, "channel=%x,channel->video_dev=%x\n",
-                               (int)ch, (int)&ch->video_dev);
-
-               err = video_register_device(ch->video_dev,
-                                         VFL_TYPE_GRABBER, (j ? 3 : 2));
-               if (err < 0)
-                       goto probe_out;
        }
 
-       v4l2_info(&vpif_obj.v4l2_dev,
-                       " VPIF display driver initialized\n");
        return 0;
 
-probe_out:
-       for (k = 0; k < j; k++) {
-               ch = vpif_obj.dev[k];
-               video_unregister_device(ch->video_dev);
-               video_device_release(ch->video_dev);
-               ch->video_dev = NULL;
-       }
 probe_subdev_out:
        kfree(vpif_obj.sd);
 vpif_sd_error:
index 5d87fc86e580ad367e8264a092b907dd91d03fd9..4d0485b99a80678c9db6eb534bb9d0a30922c94b 100644 (file)
@@ -148,7 +148,8 @@ struct vpif_device {
        struct v4l2_device v4l2_dev;
        struct channel_obj *dev[VPIF_DISPLAY_NUM_CHANNELS];
        struct v4l2_subdev **sd;
-
+       struct v4l2_async_notifier notifier;
+       struct vpif_display_config *config;
 };
 
 struct vpif_config_params {
index 8a2f01e344eee43927a3fed123815ff33ba50b54..31120b4a4a33feb4323225b31c846e0bb3f06977 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/pm_runtime.h>
+#include <linux/err.h>
 
 #include <media/davinci/vpss.h>
 
@@ -404,9 +405,8 @@ EXPORT_SYMBOL(dm365_vpss_set_pg_frame_size);
 
 static int vpss_probe(struct platform_device *pdev)
 {
-       struct resource         *r1, *r2;
+       struct resource *res;
        char *platform_name;
-       int status;
 
        if (!pdev->dev.platform_data) {
                dev_err(&pdev->dev, "no platform data\n");
@@ -427,38 +427,19 @@ static int vpss_probe(struct platform_device *pdev)
        }
 
        dev_info(&pdev->dev, "%s vpss probed\n", platform_name);
-       r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!r1)
-               return -ENOENT;
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
-       r1 = request_mem_region(r1->start, resource_size(r1), r1->name);
-       if (!r1)
-               return -EBUSY;
-
-       oper_cfg.vpss_regs_base0 = ioremap(r1->start, resource_size(r1));
-       if (!oper_cfg.vpss_regs_base0) {
-               status = -EBUSY;
-               goto fail1;
-       }
+       oper_cfg.vpss_regs_base0 = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(oper_cfg.vpss_regs_base0))
+               return PTR_ERR(oper_cfg.vpss_regs_base0);
 
        if (oper_cfg.platform == DM355 || oper_cfg.platform == DM365) {
-               r2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-               if (!r2) {
-                       status = -ENOENT;
-                       goto fail2;
-               }
-               r2 = request_mem_region(r2->start, resource_size(r2), r2->name);
-               if (!r2) {
-                       status = -EBUSY;
-                       goto fail2;
-               }
-
-               oper_cfg.vpss_regs_base1 = ioremap(r2->start,
-                                                  resource_size(r2));
-               if (!oper_cfg.vpss_regs_base1) {
-                       status = -EBUSY;
-                       goto fail3;
-               }
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+
+               oper_cfg.vpss_regs_base1 = devm_ioremap_resource(&pdev->dev,
+                                                                res);
+               if (IS_ERR(oper_cfg.vpss_regs_base1))
+                       return PTR_ERR(oper_cfg.vpss_regs_base1);
        }
 
        if (oper_cfg.platform == DM355) {
@@ -493,30 +474,13 @@ static int vpss_probe(struct platform_device *pdev)
 
        spin_lock_init(&oper_cfg.vpss_lock);
        dev_info(&pdev->dev, "%s vpss probe success\n", platform_name);
-       return 0;
 
-fail3:
-       release_mem_region(r2->start, resource_size(r2));
-fail2:
-       iounmap(oper_cfg.vpss_regs_base0);
-fail1:
-       release_mem_region(r1->start, resource_size(r1));
-       return status;
+       return 0;
 }
 
 static int vpss_remove(struct platform_device *pdev)
 {
-       struct resource         *res;
-
        pm_runtime_disable(&pdev->dev);
-       iounmap(oper_cfg.vpss_regs_base0);
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(res->start, resource_size(res));
-       if (oper_cfg.platform == DM355 || oper_cfg.platform == DM365) {
-               iounmap(oper_cfg.vpss_regs_base1);
-               res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-               release_mem_region(res->start, resource_size(res));
-       }
        return 0;
 }
 
index 1f079ff33d4b94f7e0bcd92edc2f17504952fe6b..5628453612469a624300a3e934cf1620928dc074 100644 (file)
@@ -399,7 +399,7 @@ static void cafe_ctlr_init(struct mcam_camera *mcam)
 }
 
 
-static void cafe_ctlr_power_up(struct mcam_camera *mcam)
+static int cafe_ctlr_power_up(struct mcam_camera *mcam)
 {
        /*
         * Part one of the sensor dance: turn the global
@@ -414,6 +414,8 @@ static void cafe_ctlr_power_up(struct mcam_camera *mcam)
         */
        mcam_reg_write(mcam, REG_GPR, GPR_C1EN|GPR_C0EN); /* pwr up, reset */
        mcam_reg_write(mcam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0);
+
+       return 0;
 }
 
 static void cafe_ctlr_power_down(struct mcam_camera *mcam)
index 0821ed08c122855370d3dd338e8da2f84cbddfad..5184887b155c7098415b1a3470619be336023f87 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/delay.h>
 #include <linux/vmalloc.h>
 #include <linux/io.h>
+#include <linux/clk.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
@@ -93,6 +94,9 @@ MODULE_PARM_DESC(buffer_mode,
 #define CF_CONFIG_NEEDED 4     /* Must configure hardware */
 #define CF_SINGLE_BUFFER 5     /* Running with a single buffer */
 #define CF_SG_RESTART   6      /* SG restart needed */
+#define CF_FRAME_SOF0   7      /* Frame 0 started */
+#define CF_FRAME_SOF1   8
+#define CF_FRAME_SOF2   9
 
 #define sensor_call(cam, o, f, args...) \
        v4l2_subdev_call(cam->sensor, o, f, ##args)
@@ -101,6 +105,7 @@ static struct mcam_format_struct {
        __u8 *desc;
        __u32 pixelformat;
        int bpp;   /* Bytes per pixel */
+       bool planar;
        enum v4l2_mbus_pixelcode mbus_code;
 } mcam_formats[] = {
        {
@@ -108,24 +113,56 @@ static struct mcam_format_struct {
                .pixelformat    = V4L2_PIX_FMT_YUYV,
                .mbus_code      = V4L2_MBUS_FMT_YUYV8_2X8,
                .bpp            = 2,
+               .planar         = false,
+       },
+       {
+               .desc           = "UYVY 4:2:2",
+               .pixelformat    = V4L2_PIX_FMT_UYVY,
+               .mbus_code      = V4L2_MBUS_FMT_YUYV8_2X8,
+               .bpp            = 2,
+               .planar         = false,
+       },
+       {
+               .desc           = "YUV 4:2:2 PLANAR",
+               .pixelformat    = V4L2_PIX_FMT_YUV422P,
+               .mbus_code      = V4L2_MBUS_FMT_YUYV8_2X8,
+               .bpp            = 2,
+               .planar         = true,
+       },
+       {
+               .desc           = "YUV 4:2:0 PLANAR",
+               .pixelformat    = V4L2_PIX_FMT_YUV420,
+               .mbus_code      = V4L2_MBUS_FMT_YUYV8_2X8,
+               .bpp            = 2,
+               .planar         = true,
+       },
+       {
+               .desc           = "YVU 4:2:0 PLANAR",
+               .pixelformat    = V4L2_PIX_FMT_YVU420,
+               .mbus_code      = V4L2_MBUS_FMT_YUYV8_2X8,
+               .bpp            = 2,
+               .planar         = true,
        },
        {
                .desc           = "RGB 444",
                .pixelformat    = V4L2_PIX_FMT_RGB444,
                .mbus_code      = V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE,
                .bpp            = 2,
+               .planar         = false,
        },
        {
                .desc           = "RGB 565",
                .pixelformat    = V4L2_PIX_FMT_RGB565,
                .mbus_code      = V4L2_MBUS_FMT_RGB565_2X8_LE,
                .bpp            = 2,
+               .planar         = false,
        },
        {
                .desc           = "Raw RGB Bayer",
                .pixelformat    = V4L2_PIX_FMT_SBGGR8,
                .mbus_code      = V4L2_MBUS_FMT_SBGGR8_1X8,
-               .bpp            = 1
+               .bpp            = 1,
+               .planar         = false,
        },
 };
 #define N_MCAM_FMTS ARRAY_SIZE(mcam_formats)
@@ -168,6 +205,12 @@ struct mcam_dma_desc {
        u32 segment_len;
 };
 
+struct yuv_pointer_t {
+       dma_addr_t y;
+       dma_addr_t u;
+       dma_addr_t v;
+};
+
 /*
  * Our buffer type for working with videobuf2.  Note that the vb2
  * developers have decreed that struct vb2_buffer must be at the
@@ -179,6 +222,7 @@ struct mcam_vb_buffer {
        struct mcam_dma_desc *dma_desc; /* Descriptor virtual address */
        dma_addr_t dma_desc_pa;         /* Descriptor physical address */
        int dma_desc_nent;              /* Number of mapped descriptors */
+       struct yuv_pointer_t yuv_p;
 };
 
 static inline struct mcam_vb_buffer *vb_to_mvb(struct vb2_buffer *vb)
@@ -219,8 +263,10 @@ static void mcam_reset_buffers(struct mcam_camera *cam)
        int i;
 
        cam->next_buf = -1;
-       for (i = 0; i < cam->nbufs; i++)
+       for (i = 0; i < cam->nbufs; i++) {
                clear_bit(i, &cam->flags);
+               clear_bit(CF_FRAME_SOF0 + i, &cam->flags);
+       }
 }
 
 static inline int mcam_needs_config(struct mcam_camera *cam)
@@ -253,6 +299,45 @@ static void mcam_ctlr_stop(struct mcam_camera *cam)
        mcam_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE);
 }
 
+static void mcam_enable_mipi(struct mcam_camera *mcam)
+{
+       /* Using MIPI mode and enable MIPI */
+       cam_dbg(mcam, "camera: DPHY3=0x%x, DPHY5=0x%x, DPHY6=0x%x\n",
+                       mcam->dphy[0], mcam->dphy[1], mcam->dphy[2]);
+       mcam_reg_write(mcam, REG_CSI2_DPHY3, mcam->dphy[0]);
+       mcam_reg_write(mcam, REG_CSI2_DPHY5, mcam->dphy[1]);
+       mcam_reg_write(mcam, REG_CSI2_DPHY6, mcam->dphy[2]);
+
+       if (!mcam->mipi_enabled) {
+               if (mcam->lane > 4 || mcam->lane <= 0) {
+                       cam_warn(mcam, "lane number error\n");
+                       mcam->lane = 1; /* set the default value */
+               }
+               /*
+                * 0x41 actives 1 lane
+                * 0x43 actives 2 lanes
+                * 0x45 actives 3 lanes (never happen)
+                * 0x47 actives 4 lanes
+                */
+               mcam_reg_write(mcam, REG_CSI2_CTRL0,
+                       CSI2_C0_MIPI_EN | CSI2_C0_ACT_LANE(mcam->lane));
+               mcam_reg_write(mcam, REG_CLKCTRL,
+                       (mcam->mclk_src << 29) | mcam->mclk_div);
+
+               mcam->mipi_enabled = true;
+       }
+}
+
+static void mcam_disable_mipi(struct mcam_camera *mcam)
+{
+       /* Using Parallel mode or disable MIPI */
+       mcam_reg_write(mcam, REG_CSI2_CTRL0, 0x0);
+       mcam_reg_write(mcam, REG_CSI2_DPHY3, 0x0);
+       mcam_reg_write(mcam, REG_CSI2_DPHY5, 0x0);
+       mcam_reg_write(mcam, REG_CSI2_DPHY6, 0x0);
+       mcam->mipi_enabled = false;
+}
+
 /* ------------------------------------------------------------------- */
 
 #ifdef MCAM_MODE_VMALLOC
@@ -425,6 +510,15 @@ static inline int mcam_check_dma_buffers(struct mcam_camera *cam)
 /*
  * DMA-contiguous code.
  */
+
+static bool mcam_fmt_is_planar(__u32 pfmt)
+{
+       struct mcam_format_struct *f;
+
+       f = mcam_find_format(pfmt);
+       return f->planar;
+}
+
 /*
  * Set up a contiguous buffer for the given frame.  Here also is where
  * the underrun strategy is set: if there is no buffer available, reuse
@@ -436,27 +530,58 @@ static inline int mcam_check_dma_buffers(struct mcam_camera *cam)
 static void mcam_set_contig_buffer(struct mcam_camera *cam, int frame)
 {
        struct mcam_vb_buffer *buf;
+       struct v4l2_pix_format *fmt = &cam->pix_format;
+       dma_addr_t dma_handle;
+       u32 pixel_count = fmt->width * fmt->height;
+       struct vb2_buffer *vb;
+
        /*
         * If there are no available buffers, go into single mode
         */
        if (list_empty(&cam->buffers)) {
                buf = cam->vb_bufs[frame ^ 0x1];
-               cam->vb_bufs[frame] = buf;
-               mcam_reg_write(cam, frame == 0 ? REG_Y0BAR : REG_Y1BAR,
-                               vb2_dma_contig_plane_dma_addr(&buf->vb_buf, 0));
                set_bit(CF_SINGLE_BUFFER, &cam->flags);
                cam->frame_state.singles++;
-               return;
+       } else {
+               /*
+                * OK, we have a buffer we can use.
+                */
+               buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer,
+                                       queue);
+               list_del_init(&buf->queue);
+               clear_bit(CF_SINGLE_BUFFER, &cam->flags);
        }
-       /*
-        * OK, we have a buffer we can use.
-        */
-       buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer, queue);
-       list_del_init(&buf->queue);
-       mcam_reg_write(cam, frame == 0 ? REG_Y0BAR : REG_Y1BAR,
-                       vb2_dma_contig_plane_dma_addr(&buf->vb_buf, 0));
+
        cam->vb_bufs[frame] = buf;
-       clear_bit(CF_SINGLE_BUFFER, &cam->flags);
+       vb = &buf->vb_buf;
+
+       dma_handle = vb2_dma_contig_plane_dma_addr(vb, 0);
+       buf->yuv_p.y = dma_handle;
+
+       switch (cam->pix_format.pixelformat) {
+       case V4L2_PIX_FMT_YUV422P:
+               buf->yuv_p.u = buf->yuv_p.y + pixel_count;
+               buf->yuv_p.v = buf->yuv_p.u + pixel_count / 2;
+               break;
+       case V4L2_PIX_FMT_YUV420:
+               buf->yuv_p.u = buf->yuv_p.y + pixel_count;
+               buf->yuv_p.v = buf->yuv_p.u + pixel_count / 4;
+               break;
+       case V4L2_PIX_FMT_YVU420:
+               buf->yuv_p.v = buf->yuv_p.y + pixel_count;
+               buf->yuv_p.u = buf->yuv_p.v + pixel_count / 4;
+               break;
+       default:
+               break;
+       }
+
+       mcam_reg_write(cam, frame == 0 ? REG_Y0BAR : REG_Y1BAR, buf->yuv_p.y);
+       if (mcam_fmt_is_planar(fmt->pixelformat)) {
+               mcam_reg_write(cam, frame == 0 ?
+                                       REG_U0BAR : REG_U1BAR, buf->yuv_p.u);
+               mcam_reg_write(cam, frame == 0 ?
+                                       REG_V0BAR : REG_V1BAR, buf->yuv_p.v);
+       }
 }
 
 /*
@@ -614,48 +739,90 @@ static inline void mcam_sg_restart(struct mcam_camera *cam)
  */
 static void mcam_ctlr_image(struct mcam_camera *cam)
 {
-       int imgsz;
        struct v4l2_pix_format *fmt = &cam->pix_format;
+       u32 widthy = 0, widthuv = 0, imgsz_h, imgsz_w;
+
+       cam_dbg(cam, "camera: bytesperline = %d; height = %d\n",
+               fmt->bytesperline, fmt->sizeimage / fmt->bytesperline);
+       imgsz_h = (fmt->height << IMGSZ_V_SHIFT) & IMGSZ_V_MASK;
+       imgsz_w = (fmt->width * 2) & IMGSZ_H_MASK;
+
+       switch (fmt->pixelformat) {
+       case V4L2_PIX_FMT_YUYV:
+       case V4L2_PIX_FMT_UYVY:
+               widthy = fmt->width * 2;
+               widthuv = 0;
+               break;
+       case V4L2_PIX_FMT_JPEG:
+               imgsz_h = (fmt->sizeimage / fmt->bytesperline) << IMGSZ_V_SHIFT;
+               widthy = fmt->bytesperline;
+               widthuv = 0;
+               break;
+       case V4L2_PIX_FMT_YUV422P:
+       case V4L2_PIX_FMT_YUV420:
+       case V4L2_PIX_FMT_YVU420:
+               widthy = fmt->width;
+               widthuv = fmt->width / 2;
+               break;
+       default:
+               widthy = fmt->bytesperline;
+               widthuv = 0;
+       }
+
+       mcam_reg_write_mask(cam, REG_IMGPITCH, widthuv << 16 | widthy,
+                       IMGP_YP_MASK | IMGP_UVP_MASK);
+       mcam_reg_write(cam, REG_IMGSIZE, imgsz_h | imgsz_w);
+       mcam_reg_write(cam, REG_IMGOFFSET, 0x0);
 
-       imgsz = ((fmt->height << IMGSZ_V_SHIFT) & IMGSZ_V_MASK) |
-               (fmt->bytesperline & IMGSZ_H_MASK);
-       mcam_reg_write(cam, REG_IMGSIZE, imgsz);
-       mcam_reg_write(cam, REG_IMGOFFSET, 0);
-       /* YPITCH just drops the last two bits */
-       mcam_reg_write_mask(cam, REG_IMGPITCH, fmt->bytesperline,
-                       IMGP_YP_MASK);
        /*
         * Tell the controller about the image format we are using.
         */
-       switch (cam->pix_format.pixelformat) {
+       switch (fmt->pixelformat) {
+       case V4L2_PIX_FMT_YUV422P:
+               mcam_reg_write_mask(cam, REG_CTRL0,
+                       C0_DF_YUV | C0_YUV_PLANAR | C0_YUVE_YVYU, C0_DF_MASK);
+               break;
+       case V4L2_PIX_FMT_YUV420:
+       case V4L2_PIX_FMT_YVU420:
+               mcam_reg_write_mask(cam, REG_CTRL0,
+                       C0_DF_YUV | C0_YUV_420PL | C0_YUVE_YVYU, C0_DF_MASK);
+               break;
        case V4L2_PIX_FMT_YUYV:
-           mcam_reg_write_mask(cam, REG_CTRL0,
-                           C0_DF_YUV|C0_YUV_PACKED|C0_YUVE_YUYV,
-                           C0_DF_MASK);
-           break;
-
+               mcam_reg_write_mask(cam, REG_CTRL0,
+                       C0_DF_YUV | C0_YUV_PACKED | C0_YUVE_UYVY, C0_DF_MASK);
+               break;
+       case V4L2_PIX_FMT_UYVY:
+               mcam_reg_write_mask(cam, REG_CTRL0,
+                       C0_DF_YUV | C0_YUV_PACKED | C0_YUVE_YUYV, C0_DF_MASK);
+               break;
+       case V4L2_PIX_FMT_JPEG:
+               mcam_reg_write_mask(cam, REG_CTRL0,
+                       C0_DF_YUV | C0_YUV_PACKED | C0_YUVE_YUYV, C0_DF_MASK);
+               break;
        case V4L2_PIX_FMT_RGB444:
-           mcam_reg_write_mask(cam, REG_CTRL0,
-                           C0_DF_RGB|C0_RGBF_444|C0_RGB4_XRGB,
-                           C0_DF_MASK);
+               mcam_reg_write_mask(cam, REG_CTRL0,
+                       C0_DF_RGB | C0_RGBF_444 | C0_RGB4_XRGB, C0_DF_MASK);
                /* Alpha value? */
-           break;
-
+               break;
        case V4L2_PIX_FMT_RGB565:
-           mcam_reg_write_mask(cam, REG_CTRL0,
-                           C0_DF_RGB|C0_RGBF_565|C0_RGB5_BGGR,
-                           C0_DF_MASK);
-           break;
-
+               mcam_reg_write_mask(cam, REG_CTRL0,
+                       C0_DF_RGB | C0_RGBF_565 | C0_RGB5_BGGR, C0_DF_MASK);
+               break;
        default:
-           cam_err(cam, "Unknown format %x\n", cam->pix_format.pixelformat);
-           break;
+               cam_err(cam, "camera: unknown format: %#x\n", fmt->pixelformat);
+               break;
        }
+
        /*
         * Make sure it knows we want to use hsync/vsync.
         */
-       mcam_reg_write_mask(cam, REG_CTRL0, C0_SIF_HVSYNC,
-                       C0_SIFM_MASK);
+       mcam_reg_write_mask(cam, REG_CTRL0, C0_SIF_HVSYNC, C0_SIFM_MASK);
+       /*
+        * This field controls the generation of EOF(DVP only)
+        */
+       if (cam->bus_type != V4L2_MBUS_CSI2)
+               mcam_reg_set_bit(cam, REG_CTRL0,
+                               C0_EOF_VSYNC | C0_VEDGE_CTRL);
 }
 
 
@@ -753,15 +920,21 @@ static void mcam_ctlr_stop_dma(struct mcam_camera *cam)
 /*
  * Power up and down.
  */
-static void mcam_ctlr_power_up(struct mcam_camera *cam)
+static int mcam_ctlr_power_up(struct mcam_camera *cam)
 {
        unsigned long flags;
+       int ret;
 
        spin_lock_irqsave(&cam->dev_lock, flags);
-       cam->plat_power_up(cam);
+       ret = cam->plat_power_up(cam);
+       if (ret) {
+               spin_unlock_irqrestore(&cam->dev_lock, flags);
+               return ret;
+       }
        mcam_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN);
        spin_unlock_irqrestore(&cam->dev_lock, flags);
        msleep(5); /* Just to be sure */
+       return 0;
 }
 
 static void mcam_ctlr_power_down(struct mcam_camera *cam)
@@ -869,6 +1042,17 @@ static int mcam_read_setup(struct mcam_camera *cam)
        spin_lock_irqsave(&cam->dev_lock, flags);
        clear_bit(CF_DMA_ACTIVE, &cam->flags);
        mcam_reset_buffers(cam);
+       /*
+        * Update CSI2_DPHY value
+        */
+       if (cam->calc_dphy)
+               cam->calc_dphy(cam);
+       cam_dbg(cam, "camera: DPHY sets: dphy3=0x%x, dphy5=0x%x, dphy6=0x%x\n",
+                       cam->dphy[0], cam->dphy[1], cam->dphy[2]);
+       if (cam->bus_type == V4L2_MBUS_CSI2)
+               mcam_enable_mipi(cam);
+       else
+               mcam_disable_mipi(cam);
        mcam_ctlr_irq_enable(cam);
        cam->state = S_STREAMING;
        if (!test_bit(CF_SG_RESTART, &cam->flags))
@@ -943,6 +1127,7 @@ static void mcam_vb_wait_finish(struct vb2_queue *vq)
 static int mcam_vb_start_streaming(struct vb2_queue *vq, unsigned int count)
 {
        struct mcam_camera *cam = vb2_get_drv_priv(vq);
+       unsigned int frame;
 
        if (cam->state != S_IDLE) {
                INIT_LIST_HEAD(&cam->buffers);
@@ -960,6 +1145,14 @@ static int mcam_vb_start_streaming(struct vb2_queue *vq, unsigned int count)
                cam->state = S_BUFWAIT;
                return 0;
        }
+
+       /*
+        * Ensure clear the left over frame flags
+        * before every really start streaming
+        */
+       for (frame = 0; frame < cam->nbufs; frame++)
+               clear_bit(CF_FRAME_SOF0 + frame, &cam->flags);
+
        return mcam_read_setup(cam);
 }
 
@@ -976,6 +1169,12 @@ static int mcam_vb_stop_streaming(struct vb2_queue *vq)
        if (cam->state != S_STREAMING)
                return -EINVAL;
        mcam_ctlr_stop_dma(cam);
+       /*
+        * Reset the CCIC PHY after stopping streaming,
+        * otherwise, the CCIC may be unstable.
+        */
+       if (cam->ctlr_reset)
+               cam->ctlr_reset(cam);
        /*
         * VB2 reclaims the buffers, so we need to forget
         * about them.
@@ -1087,6 +1286,7 @@ static int mcam_setup_vb2(struct mcam_camera *cam)
 #ifdef MCAM_MODE_DMA_CONTIG
                vq->ops = &mcam_vb2_ops;
                vq->mem_ops = &vb2_dma_contig_memops;
+               vq->buf_struct_size = sizeof(struct mcam_vb_buffer);
                cam->vb_alloc_ctx = vb2_dma_contig_init_ctx(cam->dev);
                vq->io_modes = VB2_MMAP | VB2_USERPTR;
                cam->dma_setup = mcam_ctlr_dma_contig;
@@ -1097,6 +1297,7 @@ static int mcam_setup_vb2(struct mcam_camera *cam)
 #ifdef MCAM_MODE_DMA_SG
                vq->ops = &mcam_vb2_sg_ops;
                vq->mem_ops = &vb2_dma_sg_memops;
+               vq->buf_struct_size = sizeof(struct mcam_vb_buffer);
                vq->io_modes = VB2_MMAP | VB2_USERPTR;
                cam->dma_setup = mcam_ctlr_dma_sg;
                cam->frame_complete = mcam_dma_sg_done;
@@ -1247,7 +1448,15 @@ static int mcam_vidioc_try_fmt_vid_cap(struct file *filp, void *priv,
        ret = sensor_call(cam, video, try_mbus_fmt, &mbus_fmt);
        mutex_unlock(&cam->s_mutex);
        v4l2_fill_pix_format(pix, &mbus_fmt);
-       pix->bytesperline = pix->width * f->bpp;
+       switch (f->pixelformat) {
+       case V4L2_PIX_FMT_YUV420:
+       case V4L2_PIX_FMT_YVU420:
+               pix->bytesperline = pix->width * 3 / 2;
+               break;
+       default:
+               pix->bytesperline = pix->width * f->bpp;
+               break;
+       }
        pix->sizeimage = pix->height * pix->bytesperline;
        return ret;
 }
@@ -1475,7 +1684,9 @@ static int mcam_v4l_open(struct file *filp)
                ret = mcam_setup_vb2(cam);
                if (ret)
                        goto out;
-               mcam_ctlr_power_up(cam);
+               ret = mcam_ctlr_power_up(cam);
+               if (ret)
+                       goto out;
                __mcam_cam_reset(cam);
                mcam_set_config_needed(cam, 1);
        }
@@ -1498,10 +1709,12 @@ static int mcam_v4l_release(struct file *filp)
        if (cam->users == 0) {
                mcam_ctlr_stop_dma(cam);
                mcam_cleanup_vb2(cam);
+               mcam_disable_mipi(cam);
                mcam_ctlr_power_down(cam);
                if (cam->buffer_mode == B_vmalloc && alloc_bufs_at_read)
                        mcam_free_dma_bufs(cam);
        }
+
        mutex_unlock(&cam->s_mutex);
        return 0;
 }
@@ -1617,9 +1830,11 @@ int mccic_irq(struct mcam_camera *cam, unsigned int irqs)
         * each time.
         */
        for (frame = 0; frame < cam->nbufs; frame++)
-               if (irqs & (IRQ_EOF0 << frame)) {
+               if (irqs & (IRQ_EOF0 << frame) &&
+                       test_bit(CF_FRAME_SOF0 + frame, &cam->flags)) {
                        mcam_frame_complete(cam, frame);
                        handled = 1;
+                       clear_bit(CF_FRAME_SOF0 + frame, &cam->flags);
                        if (cam->buffer_mode == B_DMA_sg)
                                break;
                }
@@ -1628,9 +1843,15 @@ int mccic_irq(struct mcam_camera *cam, unsigned int irqs)
         * code assumes that we won't get multiple frame interrupts
         * at once; may want to rethink that.
         */
-       if (irqs & (IRQ_SOF0 | IRQ_SOF1 | IRQ_SOF2)) {
+       for (frame = 0; frame < cam->nbufs; frame++) {
+               if (irqs & (IRQ_SOF0 << frame)) {
+                       set_bit(CF_FRAME_SOF0 + frame, &cam->flags);
+                       handled = IRQ_HANDLED;
+               }
+       }
+
+       if (handled == IRQ_HANDLED) {
                set_bit(CF_DMA_ACTIVE, &cam->flags);
-               handled = 1;
                if (cam->buffer_mode == B_DMA_sg)
                        mcam_ctlr_stop(cam);
        }
@@ -1787,7 +2008,11 @@ int mccic_resume(struct mcam_camera *cam)
 
        mutex_lock(&cam->s_mutex);
        if (cam->users > 0) {
-               mcam_ctlr_power_up(cam);
+               ret = mcam_ctlr_power_up(cam);
+               if (ret) {
+                       mutex_unlock(&cam->s_mutex);
+                       return ret;
+               }
                __mcam_cam_reset(cam);
        } else {
                mcam_ctlr_power_down(cam);
index 520c8ded9443f5869e101f8ca92d3c3346e9894f..e0e628cb98f94c7a5d4b90588d2a85449ad44547 100644 (file)
@@ -88,6 +88,8 @@ struct mcam_frame_state {
        unsigned int delivered;
 };
 
+#define NR_MCAM_CLK 3
+
 /*
  * A description of one of our devices.
  * Locking: controlled by s_mutex.  Certain fields, however, require
@@ -108,11 +110,33 @@ struct mcam_camera {
        short int clock_speed;  /* Sensor clock speed, default 30 */
        short int use_smbus;    /* SMBUS or straight I2c? */
        enum mcam_buffer_mode buffer_mode;
+
+       int mclk_min;   /* The minimal value of mclk */
+       int mclk_src;   /* which clock source the mclk derives from */
+       int mclk_div;   /* Clock Divider Value for MCLK */
+
+       int ccic_id;
+       enum v4l2_mbus_type bus_type;
+       /* MIPI support */
+       /* The dphy config value, allocated in board file
+        * dphy[0]: DPHY3
+        * dphy[1]: DPHY5
+        * dphy[2]: DPHY6
+        */
+       int *dphy;
+       bool mipi_enabled;      /* flag whether mipi is enabled already */
+       int lane;                       /* lane number */
+
+       /* clock tree support */
+       struct clk *clk[NR_MCAM_CLK];
+
        /*
         * Callbacks from the core to the platform code.
         */
-       void (*plat_power_up) (struct mcam_camera *cam);
+       int (*plat_power_up) (struct mcam_camera *cam);
        void (*plat_power_down) (struct mcam_camera *cam);
+       void (*calc_dphy) (struct mcam_camera *cam);
+       void (*ctlr_reset) (struct mcam_camera *cam);
 
        /*
         * Everything below here is private to the mcam core and
@@ -225,6 +249,23 @@ int mccic_resume(struct mcam_camera *cam);
 #define REG_Y0BAR      0x00
 #define REG_Y1BAR      0x04
 #define REG_Y2BAR      0x08
+#define REG_U0BAR      0x0c
+#define REG_U1BAR      0x10
+#define REG_U2BAR      0x14
+#define REG_V0BAR      0x18
+#define REG_V1BAR      0x1C
+#define REG_V2BAR      0x20
+
+/*
+ * register definitions for MIPI support
+ */
+#define REG_CSI2_CTRL0 0x100
+#define   CSI2_C0_MIPI_EN (0x1 << 0)
+#define   CSI2_C0_ACT_LANE(n) ((n-1) << 1)
+#define REG_CSI2_DPHY3 0x12c
+#define REG_CSI2_DPHY5 0x134
+#define REG_CSI2_DPHY6 0x138
+
 /* ... */
 
 #define REG_IMGPITCH   0x24    /* Image pitch register */
@@ -293,13 +334,16 @@ int mccic_resume(struct mcam_camera *cam);
 #define          C0_YUVE_XUVY    0x00020000    /* 420: .UVY            */
 #define          C0_YUVE_XVUY    0x00030000    /* 420: .VUY            */
 /* Bayer bits 18,19 if needed */
+#define          C0_EOF_VSYNC    0x00400000    /* Generate EOF by VSYNC */
+#define          C0_VEDGE_CTRL   0x00800000    /* Detect falling edge of VSYNC */
 #define          C0_HPOL_LOW     0x01000000    /* HSYNC polarity active low */
 #define          C0_VPOL_LOW     0x02000000    /* VSYNC polarity active low */
 #define          C0_VCLK_LOW     0x04000000    /* VCLK on falling edge */
 #define          C0_DOWNSCALE    0x08000000    /* Enable downscaler */
-#define          C0_SIFM_MASK    0xc0000000    /* SIF mode bits */
+/* SIFMODE */
 #define          C0_SIF_HVSYNC   0x00000000    /* Use H/VSYNC */
-#define          CO_SOF_NOSYNC   0x40000000    /* Use inband active signaling */
+#define          C0_SOF_NOSYNC   0x40000000    /* Use inband active signaling */
+#define          C0_SIFM_MASK    0xc0000000    /* SIF mode bits */
 
 /* Bits below C1_444ALPHA are not present in Cafe */
 #define REG_CTRL1      0x40    /* Control 1 */
index a634888271cd7a38ff162bc56d4b97b88923e09f..f06daa4f2502000bfd6e2038d10f806640b67da7 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/delay.h>
 #include <linux/list.h>
 #include <linux/pm.h>
+#include <linux/clk.h>
 
 #include "mcam-core.h"
 
@@ -33,11 +34,14 @@ MODULE_ALIAS("platform:mmp-camera");
 MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
 MODULE_LICENSE("GPL");
 
+static char *mcam_clks[] = {"CCICAXICLK", "CCICFUNCLK", "CCICPHYCLK"};
+
 struct mmp_camera {
        void *power_regs;
        struct platform_device *pdev;
        struct mcam_camera mcam;
        struct list_head devlist;
+       struct clk *mipi_clk;
        int irq;
 };
 
@@ -101,6 +105,27 @@ static struct mmp_camera *mmpcam_find_device(struct platform_device *pdev)
 #define CPU_SUBSYS_PMU_BASE    0xd4282800
 #define REG_CCIC_DCGCR         0x28    /* CCIC dyn clock gate ctrl reg */
 #define REG_CCIC_CRCR          0x50    /* CCIC clk reset ctrl reg      */
+#define REG_CCIC2_CRCR         0xf4    /* CCIC2 clk reset ctrl reg     */
+
+static void mcam_clk_enable(struct mcam_camera *mcam)
+{
+       unsigned int i;
+
+       for (i = 0; i < NR_MCAM_CLK; i++) {
+               if (!IS_ERR(mcam->clk[i]))
+                       clk_prepare_enable(mcam->clk[i]);
+       }
+}
+
+static void mcam_clk_disable(struct mcam_camera *mcam)
+{
+       int i;
+
+       for (i = NR_MCAM_CLK - 1; i >= 0; i--) {
+               if (!IS_ERR(mcam->clk[i]))
+                       clk_disable_unprepare(mcam->clk[i]);
+       }
+}
 
 /*
  * Power control.
@@ -112,10 +137,17 @@ static void mmpcam_power_up_ctlr(struct mmp_camera *cam)
        mdelay(1);
 }
 
-static void mmpcam_power_up(struct mcam_camera *mcam)
+static int mmpcam_power_up(struct mcam_camera *mcam)
 {
        struct mmp_camera *cam = mcam_to_cam(mcam);
        struct mmp_camera_platform_data *pdata;
+
+       if (mcam->bus_type == V4L2_MBUS_CSI2) {
+               cam->mipi_clk = devm_clk_get(mcam->dev, "mipi");
+               if ((IS_ERR(cam->mipi_clk) && mcam->dphy[2] == 0))
+                       return PTR_ERR(cam->mipi_clk);
+       }
+
 /*
  * Turn on power and clocks to the controller.
  */
@@ -132,6 +164,10 @@ static void mmpcam_power_up(struct mcam_camera *mcam)
        mdelay(5);
        gpio_set_value(pdata->sensor_reset_gpio, 1); /* reset is active low */
        mdelay(5);
+
+       mcam_clk_enable(mcam);
+
+       return 0;
 }
 
 static void mmpcam_power_down(struct mcam_camera *mcam)
@@ -149,8 +185,133 @@ static void mmpcam_power_down(struct mcam_camera *mcam)
        pdata = cam->pdev->dev.platform_data;
        gpio_set_value(pdata->sensor_power_gpio, 0);
        gpio_set_value(pdata->sensor_reset_gpio, 0);
+
+       if (mcam->bus_type == V4L2_MBUS_CSI2 && !IS_ERR(cam->mipi_clk)) {
+               if (cam->mipi_clk)
+                       devm_clk_put(mcam->dev, cam->mipi_clk);
+               cam->mipi_clk = NULL;
+       }
+
+       mcam_clk_disable(mcam);
 }
 
+void mcam_ctlr_reset(struct mcam_camera *mcam)
+{
+       unsigned long val;
+       struct mmp_camera *cam = mcam_to_cam(mcam);
+
+       if (mcam->ccic_id) {
+               /*
+                * Using CCIC2
+                */
+               val = ioread32(cam->power_regs + REG_CCIC2_CRCR);
+               iowrite32(val & ~0x2, cam->power_regs + REG_CCIC2_CRCR);
+               iowrite32(val | 0x2, cam->power_regs + REG_CCIC2_CRCR);
+       } else {
+               /*
+                * Using CCIC1
+                */
+               val = ioread32(cam->power_regs + REG_CCIC_CRCR);
+               iowrite32(val & ~0x2, cam->power_regs + REG_CCIC_CRCR);
+               iowrite32(val | 0x2, cam->power_regs + REG_CCIC_CRCR);
+       }
+}
+
+/*
+ * calc the dphy register values
+ * There are three dphy registers being used.
+ * dphy[0] - CSI2_DPHY3
+ * dphy[1] - CSI2_DPHY5
+ * dphy[2] - CSI2_DPHY6
+ * CSI2_DPHY3 and CSI2_DPHY6 can be set with a default value
+ * or be calculated dynamically
+ */
+void mmpcam_calc_dphy(struct mcam_camera *mcam)
+{
+       struct mmp_camera *cam = mcam_to_cam(mcam);
+       struct mmp_camera_platform_data *pdata = cam->pdev->dev.platform_data;
+       struct device *dev = &cam->pdev->dev;
+       unsigned long tx_clk_esc;
+
+       /*
+        * If CSI2_DPHY3 is calculated dynamically,
+        * pdata->lane_clk should be already set
+        * either in the board driver statically
+        * or in the sensor driver dynamically.
+        */
+       /*
+        * dphy[0] - CSI2_DPHY3:
+        *  bit 0 ~ bit 7: HS Term Enable.
+        *   defines the time that the DPHY
+        *   wait before enabling the data
+        *   lane termination after detecting
+        *   that the sensor has driven the data
+        *   lanes to the LP00 bridge state.
+        *   The value is calculated by:
+        *   (Max T(D_TERM_EN)/Period(DDR)) - 1
+        *  bit 8 ~ bit 15: HS_SETTLE
+        *   Time interval during which the HS
+        *   receiver shall ignore any Data Lane
+        *   HS transistions.
+        *   The vaule has been calibrated on
+        *   different boards. It seems to work well.
+        *
+        *  More detail please refer
+        *  MIPI Alliance Spectification for D-PHY
+        *  document for explanation of HS-SETTLE
+        *  and D-TERM-EN.
+        */
+       switch (pdata->dphy3_algo) {
+       case DPHY3_ALGO_PXA910:
+               /*
+                * Calculate CSI2_DPHY3 algo for PXA910
+                */
+               pdata->dphy[0] =
+                       (((1 + (pdata->lane_clk * 80) / 1000) & 0xff) << 8)
+                       | (1 + pdata->lane_clk * 35 / 1000);
+               break;
+       case DPHY3_ALGO_PXA2128:
+               /*
+                * Calculate CSI2_DPHY3 algo for PXA2128
+                */
+               pdata->dphy[0] =
+                       (((2 + (pdata->lane_clk * 110) / 1000) & 0xff) << 8)
+                       | (1 + pdata->lane_clk * 35 / 1000);
+               break;
+       default:
+               /*
+                * Use default CSI2_DPHY3 value for PXA688/PXA988
+                */
+               dev_dbg(dev, "camera: use the default CSI2_DPHY3 value\n");
+       }
+
+       /*
+        * mipi_clk will never be changed, it is a fixed value on MMP
+        */
+       if (IS_ERR(cam->mipi_clk))
+               return;
+
+       /* get the escape clk, this is hard coded */
+       tx_clk_esc = (clk_get_rate(cam->mipi_clk) / 1000000) / 12;
+
+       /*
+        * dphy[2] - CSI2_DPHY6:
+        * bit 0 ~ bit 7: CK Term Enable
+        *  Time for the Clock Lane receiver to enable the HS line
+        *  termination. The value is calculated similarly with
+        *  HS Term Enable
+        * bit 8 ~ bit 15: CK Settle
+        *  Time interval during which the HS receiver shall ignore
+        *  any Clock Lane HS transitions.
+        *  The value is calibrated on the boards.
+        */
+       pdata->dphy[2] =
+               ((((534 * tx_clk_esc) / 2000 - 1) & 0xff) << 8)
+               | (((38 * tx_clk_esc) / 1000 - 1) & 0xff);
+
+       dev_dbg(dev, "camera: DPHY sets: dphy3=0x%x, dphy5=0x%x, dphy6=0x%x\n",
+               pdata->dphy[0], pdata->dphy[1], pdata->dphy[2]);
+}
 
 static irqreturn_t mmpcam_irq(int irq, void *data)
 {
@@ -164,6 +325,35 @@ static irqreturn_t mmpcam_irq(int irq, void *data)
        return IRQ_RETVAL(handled);
 }
 
+static void mcam_deinit_clk(struct mcam_camera *mcam)
+{
+       unsigned int i;
+
+       for (i = 0; i < NR_MCAM_CLK; i++) {
+               if (!IS_ERR(mcam->clk[i])) {
+                       if (mcam->clk[i])
+                               devm_clk_put(mcam->dev, mcam->clk[i]);
+               }
+               mcam->clk[i] = NULL;
+       }
+}
+
+static void mcam_init_clk(struct mcam_camera *mcam)
+{
+       unsigned int i;
+
+       for (i = 0; i < NR_MCAM_CLK; i++) {
+               if (mcam_clks[i] != NULL) {
+                       /* Some clks are not necessary on some boards
+                        * We still try to run even it fails getting clk
+                        */
+                       mcam->clk[i] = devm_clk_get(mcam->dev, mcam_clks[i]);
+                       if (IS_ERR(mcam->clk[i]))
+                               dev_warn(mcam->dev, "Could not get clk: %s\n",
+                                               mcam_clks[i]);
+               }
+       }
+}
 
 static int mmpcam_probe(struct platform_device *pdev)
 {
@@ -173,17 +363,32 @@ static int mmpcam_probe(struct platform_device *pdev)
        struct mmp_camera_platform_data *pdata;
        int ret;
 
-       cam = kzalloc(sizeof(*cam), GFP_KERNEL);
+       pdata = pdev->dev.platform_data;
+       if (!pdata)
+               return -ENODEV;
+
+       cam = devm_kzalloc(&pdev->dev, sizeof(*cam), GFP_KERNEL);
        if (cam == NULL)
                return -ENOMEM;
        cam->pdev = pdev;
+       cam->mipi_clk = NULL;
        INIT_LIST_HEAD(&cam->devlist);
 
        mcam = &cam->mcam;
        mcam->plat_power_up = mmpcam_power_up;
        mcam->plat_power_down = mmpcam_power_down;
+       mcam->ctlr_reset = mcam_ctlr_reset;
+       mcam->calc_dphy = mmpcam_calc_dphy;
        mcam->dev = &pdev->dev;
        mcam->use_smbus = 0;
+       mcam->ccic_id = pdev->id;
+       mcam->mclk_min = pdata->mclk_min;
+       mcam->mclk_src = pdata->mclk_src;
+       mcam->mclk_div = pdata->mclk_div;
+       mcam->bus_type = pdata->bus_type;
+       mcam->dphy = pdata->dphy;
+       mcam->mipi_enabled = false;
+       mcam->lane = pdata->lane;
        mcam->chip_id = MCAM_ARMADA610;
        mcam->buffer_mode = B_DMA_sg;
        spin_lock_init(&mcam->dev_lock);
@@ -193,15 +398,11 @@ static int mmpcam_probe(struct platform_device *pdev)
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (res == NULL) {
                dev_err(&pdev->dev, "no iomem resource!\n");
-               ret = -ENODEV;
-               goto out_free;
-       }
-       mcam->regs = ioremap(res->start, resource_size(res));
-       if (mcam->regs == NULL) {
-               dev_err(&pdev->dev, "MMIO ioremap fail\n");
-               ret = -ENODEV;
-               goto out_free;
+               return -ENODEV;
        }
+       mcam->regs = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(mcam->regs))
+               return PTR_ERR(mcam->regs);
        mcam->regs_size = resource_size(res);
        /*
         * Power/clock memory is elsewhere; get it too.  Perhaps this
@@ -210,50 +411,51 @@ static int mmpcam_probe(struct platform_device *pdev)
        res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
        if (res == NULL) {
                dev_err(&pdev->dev, "no power resource!\n");
-               ret = -ENODEV;
-               goto out_unmap1;
-       }
-       cam->power_regs = ioremap(res->start, resource_size(res));
-       if (cam->power_regs == NULL) {
-               dev_err(&pdev->dev, "power MMIO ioremap fail\n");
-               ret = -ENODEV;
-               goto out_unmap1;
+               return -ENODEV;
        }
+       cam->power_regs = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(cam->power_regs))
+               return PTR_ERR(cam->power_regs);
        /*
         * Find the i2c adapter.  This assumes, of course, that the
         * i2c bus is already up and functioning.
         */
-       pdata = pdev->dev.platform_data;
        mcam->i2c_adapter = platform_get_drvdata(pdata->i2c_device);
        if (mcam->i2c_adapter == NULL) {
-               ret = -ENODEV;
                dev_err(&pdev->dev, "No i2c adapter\n");
-               goto out_unmap2;
+               return -ENODEV;
        }
        /*
         * Sensor GPIO pins.
         */
-       ret = gpio_request(pdata->sensor_power_gpio, "cam-power");
+       ret = devm_gpio_request(&pdev->dev, pdata->sensor_power_gpio,
+                                                       "cam-power");
        if (ret) {
                dev_err(&pdev->dev, "Can't get sensor power gpio %d",
                                pdata->sensor_power_gpio);
-               goto out_unmap2;
+               return ret;
        }
        gpio_direction_output(pdata->sensor_power_gpio, 0);
-       ret = gpio_request(pdata->sensor_reset_gpio, "cam-reset");
+       ret = devm_gpio_request(&pdev->dev, pdata->sensor_reset_gpio,
+                                                       "cam-reset");
        if (ret) {
                dev_err(&pdev->dev, "Can't get sensor reset gpio %d",
                                pdata->sensor_reset_gpio);
-               goto out_gpio;
+               return ret;
        }
        gpio_direction_output(pdata->sensor_reset_gpio, 0);
+
+       mcam_init_clk(mcam);
+
        /*
         * Power the device up and hand it off to the core.
         */
-       mmpcam_power_up(mcam);
+       ret = mmpcam_power_up(mcam);
+       if (ret)
+               goto out_deinit_clk;
        ret = mccic_register(mcam);
        if (ret)
-               goto out_gpio2;
+               goto out_power_down;
        /*
         * Finally, set up our IRQ now that the core is ready to
         * deal with it.
@@ -264,8 +466,8 @@ static int mmpcam_probe(struct platform_device *pdev)
                goto out_unregister;
        }
        cam->irq = res->start;
-       ret = request_irq(cam->irq, mmpcam_irq, IRQF_SHARED,
-                       "mmp-camera", mcam);
+       ret = devm_request_irq(&pdev->dev, cam->irq, mmpcam_irq, IRQF_SHARED,
+                                       "mmp-camera", mcam);
        if (ret == 0) {
                mmpcam_add_device(cam);
                return 0;
@@ -273,17 +475,10 @@ static int mmpcam_probe(struct platform_device *pdev)
 
 out_unregister:
        mccic_shutdown(mcam);
-out_gpio2:
+out_power_down:
        mmpcam_power_down(mcam);
-       gpio_free(pdata->sensor_reset_gpio);
-out_gpio:
-       gpio_free(pdata->sensor_power_gpio);
-out_unmap2:
-       iounmap(cam->power_regs);
-out_unmap1:
-       iounmap(mcam->regs);
-out_free:
-       kfree(cam);
+out_deinit_clk:
+       mcam_deinit_clk(mcam);
        return ret;
 }
 
@@ -300,6 +495,7 @@ static int mmpcam_remove(struct mmp_camera *cam)
        pdata = cam->pdev->dev.platform_data;
        gpio_free(pdata->sensor_reset_gpio);
        gpio_free(pdata->sensor_power_gpio);
+       mcam_deinit_clk(mcam);
        iounmap(cam->power_regs);
        iounmap(mcam->regs);
        kfree(cam);
index 553d87e5ceab41b9d2d081c6fc55dbe4b17db1ed..fd6289d60cde2c8a25450f6cb6d24c18923f0e81 100644 (file)
@@ -784,6 +784,7 @@ static int g2d_probe(struct platform_device *pdev)
        }
        *vfd = g2d_videodev;
        vfd->lock = &dev->mutex;
+       vfd->v4l2_dev = &dev->v4l2_dev;
        ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
        if (ret) {
                v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
index 5296385153d5d17ce0a3c3d6f6bf0d8513bb10f4..4f6dd42c9adb06755eebbc520ba57124f77a5e35 100644 (file)
@@ -344,7 +344,7 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
                pix_mp->num_planes = 2;
                /* Set pixelformat to the format in which MFC
                   outputs the decoded frame */
-               pix_mp->pixelformat = V4L2_PIX_FMT_NV12MT;
+               pix_mp->pixelformat = ctx->dst_fmt->fourcc;
                pix_mp->plane_fmt[0].bytesperline = ctx->buf_width;
                pix_mp->plane_fmt[0].sizeimage = ctx->luma_size;
                pix_mp->plane_fmt[1].bytesperline = ctx->buf_width;
@@ -382,10 +382,16 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
                        mfc_err("Unsupported format for source.\n");
                        return -EINVAL;
                }
-               if (!IS_MFCV6(dev) && (fmt->fourcc == V4L2_PIX_FMT_VP8)) {
-                       mfc_err("Not supported format.\n");
+               if (fmt->codec_mode == S5P_FIMV_CODEC_NONE) {
+                       mfc_err("Unknown codec\n");
                        return -EINVAL;
                }
+               if (!IS_MFCV6(dev)) {
+                       if (fmt->fourcc == V4L2_PIX_FMT_VP8) {
+                               mfc_err("Not supported format.\n");
+                               return -EINVAL;
+                       }
+               }
        } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
                fmt = find_format(f, MFC_FMT_RAW);
                if (!fmt) {
@@ -411,7 +417,6 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
        struct s5p_mfc_dev *dev = video_drvdata(file);
        struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
        int ret = 0;
-       struct s5p_mfc_fmt *fmt;
        struct v4l2_pix_format_mplane *pix_mp;
 
        mfc_debug_enter();
@@ -425,54 +430,32 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
                goto out;
        }
        if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
-               fmt = find_format(f, MFC_FMT_RAW);
-               if (!fmt) {
-                       mfc_err("Unsupported format for source.\n");
-                       return -EINVAL;
-               }
-               if (!IS_MFCV6(dev) && (fmt->fourcc != V4L2_PIX_FMT_NV12MT)) {
-                       mfc_err("Not supported format.\n");
-                       return -EINVAL;
-               } else if (IS_MFCV6(dev) &&
-                               (fmt->fourcc == V4L2_PIX_FMT_NV12MT)) {
-                       mfc_err("Not supported format.\n");
-                       return -EINVAL;
-               }
-               ctx->dst_fmt = fmt;
-               mfc_debug_leave();
-               return ret;
-       } else if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-               mfc_err("Wrong type error for S_FMT : %d", f->type);
-               return -EINVAL;
-       }
-       fmt = find_format(f, MFC_FMT_DEC);
-       if (!fmt || fmt->codec_mode == S5P_MFC_CODEC_NONE) {
-               mfc_err("Unknown codec\n");
-               ret = -EINVAL;
+               /* dst_fmt is validated by call to vidioc_try_fmt */
+               ctx->dst_fmt = find_format(f, MFC_FMT_RAW);
+               ret = 0;
                goto out;
-       }
-       if (fmt->type != MFC_FMT_DEC) {
-               mfc_err("Wrong format selected, you should choose "
-                                       "format for decoding\n");
+       } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               /* src_fmt is validated by call to vidioc_try_fmt */
+               ctx->src_fmt = find_format(f, MFC_FMT_DEC);
+               ctx->codec_mode = ctx->src_fmt->codec_mode;
+               mfc_debug(2, "The codec number is: %d\n", ctx->codec_mode);
+               pix_mp->height = 0;
+               pix_mp->width = 0;
+               if (pix_mp->plane_fmt[0].sizeimage)
+                       ctx->dec_src_buf_size = pix_mp->plane_fmt[0].sizeimage;
+               else
+                       pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size =
+                                                               DEF_CPB_SIZE;
+               pix_mp->plane_fmt[0].bytesperline = 0;
+               ctx->state = MFCINST_INIT;
+               ret = 0;
+               goto out;
+       } else {
+               mfc_err("Wrong type error for S_FMT : %d", f->type);
                ret = -EINVAL;
                goto out;
        }
-       if (!IS_MFCV6(dev) && (fmt->fourcc == V4L2_PIX_FMT_VP8)) {
-               mfc_err("Not supported format.\n");
-               return -EINVAL;
-       }
-       ctx->src_fmt = fmt;
-       ctx->codec_mode = fmt->codec_mode;
-       mfc_debug(2, "The codec number is: %d\n", ctx->codec_mode);
-       pix_mp->height = 0;
-       pix_mp->width = 0;
-       if (pix_mp->plane_fmt[0].sizeimage)
-               ctx->dec_src_buf_size = pix_mp->plane_fmt[0].sizeimage;
-       else
-               pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size =
-                                                               DEF_CPB_SIZE;
-       pix_mp->plane_fmt[0].bytesperline = 0;
-       ctx->state = MFCINST_INIT;
+
 out:
        mfc_debug_leave();
        return ret;
index 2549967b2f8589bb46007b8282520250392287b7..59e56f4c8ce34ded878308537b5de1a57595acf1 100644 (file)
@@ -906,6 +906,7 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
 
 static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
 {
+       struct s5p_mfc_dev *dev = video_drvdata(file);
        struct s5p_mfc_fmt *fmt;
        struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
 
@@ -930,6 +931,18 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
                        return -EINVAL;
                }
 
+               if (!IS_MFCV6(dev)) {
+                       if (fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16) {
+                               mfc_err("Not supported format.\n");
+                               return -EINVAL;
+                       }
+               } else if (IS_MFCV6(dev)) {
+                       if (fmt->fourcc == V4L2_PIX_FMT_NV12MT) {
+                               mfc_err("Not supported format.\n");
+                               return -EINVAL;
+                       }
+               }
+
                if (fmt->num_planes != pix_fmt_mp->num_planes) {
                        mfc_err("failed to try output format\n");
                        return -EINVAL;
@@ -947,7 +960,6 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
 {
        struct s5p_mfc_dev *dev = video_drvdata(file);
        struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
-       struct s5p_mfc_fmt *fmt;
        struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
        int ret = 0;
 
@@ -960,13 +972,9 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
                goto out;
        }
        if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
-               fmt = find_format(f, MFC_FMT_ENC);
-               if (!fmt) {
-                       mfc_err("failed to set capture format\n");
-                       return -EINVAL;
-               }
+               /* dst_fmt is validated by call to vidioc_try_fmt */
+               ctx->dst_fmt = find_format(f, MFC_FMT_ENC);
                ctx->state = MFCINST_INIT;
-               ctx->dst_fmt = fmt;
                ctx->codec_mode = ctx->dst_fmt->codec_mode;
                ctx->enc_dst_buf_size = pix_fmt_mp->plane_fmt[0].sizeimage;
                pix_fmt_mp->plane_fmt[0].bytesperline = 0;
@@ -987,28 +995,8 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
                }
                mfc_debug(2, "Got instance number: %d\n", ctx->inst_no);
        } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-               fmt = find_format(f, MFC_FMT_RAW);
-               if (!fmt) {
-                       mfc_err("failed to set output format\n");
-                       return -EINVAL;
-               }
-
-               if (!IS_MFCV6(dev) &&
-                               (fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16)) {
-                       mfc_err("Not supported format.\n");
-                       return -EINVAL;
-               } else if (IS_MFCV6(dev) &&
-                               (fmt->fourcc == V4L2_PIX_FMT_NV12MT)) {
-                       mfc_err("Not supported format.\n");
-                       return -EINVAL;
-               }
-
-               if (fmt->num_planes != pix_fmt_mp->num_planes) {
-                       mfc_err("failed to set output format\n");
-                       ret = -EINVAL;
-                       goto out;
-               }
-               ctx->src_fmt = fmt;
+               /* src_fmt is validated by call to vidioc_try_fmt */
+               ctx->src_fmt = find_format(f, MFC_FMT_RAW);
                ctx->img_width = pix_fmt_mp->width;
                ctx->img_height = pix_fmt_mp->height;
                mfc_debug(2, "codec number: %d\n", ctx->src_fmt->codec_mode);
index f2de0066089ad0093b1e9619642769ce59076e0c..dae9716e34b1e932ff9263c9901857bc1db85d7d 100644 (file)
@@ -1837,9 +1837,9 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev)
                for (j = 0; pcdev->pdata->asd_sizes[j]; j++) {
                        for (i = 0; i < pcdev->pdata->asd_sizes[j]; i++, asd++) {
                                dev_dbg(&pdev->dev, "%s(): subdev #%d, type %u\n",
-                                       __func__, i, (*asd)->bus_type);
-                               if ((*asd)->bus_type == V4L2_ASYNC_BUS_PLATFORM &&
-                                   !strncmp(name, (*asd)->match.platform.name,
+                                       __func__, i, (*asd)->match_type);
+                               if ((*asd)->match_type == V4L2_ASYNC_MATCH_DEVNAME &&
+                                   !strncmp(name, (*asd)->match.device_name.name,
                                             sizeof(name) - 1)) {
                                        pcdev->csi2_asd = *asd;
                                        break;
index 2dd0e5272941079a80a2fa4cac0c366035ec4d20..4b42572253e0fad7be92239e9f6a1582e068b2fb 100644 (file)
@@ -1475,7 +1475,7 @@ static int scan_async_group(struct soc_camera_host *ici,
                        break;
        }
 
-       if (i == size || asd[i]->bus_type != V4L2_ASYNC_BUS_I2C) {
+       if (i == size || asd[i]->match_type != V4L2_ASYNC_MATCH_I2C) {
                /* All useless */
                dev_err(ici->v4l2_dev.dev, "No I2C data source found!\n");
                return -ENODEV;
@@ -1501,7 +1501,7 @@ static int scan_async_group(struct soc_camera_host *ici,
                return -ENOMEM;
        }
 
-       sasc->notifier.subdev = asd;
+       sasc->notifier.subdevs = asd;
        sasc->notifier.num_subdevs = size;
        sasc->notifier.bound = soc_camera_async_bound;
        sasc->notifier.unbind = soc_camera_async_unbind;
index 177bcbd7a7c1c1e72b3459e618d56fb69bba617e..705dd6f9162c019b55ee0ab987bbf04d7c0df59f 100644 (file)
@@ -26,6 +26,7 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-ctrls.h>
 #include "radio-isa.h"
+#include "lm7000.h"
 
 MODULE_AUTHOR("Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
 MODULE_DESCRIPTION("A driver for the Aztech radio card.");
@@ -54,18 +55,29 @@ struct aztech {
        int curvol;
 };
 
-static void send_0_byte(struct aztech *az)
-{
-       udelay(radio_wait_time);
-       outb_p(2 + az->curvol, az->isa.io);
-       outb_p(64 + 2 + az->curvol, az->isa.io);
-}
+/* bit definitions for register read */
+#define AZTECH_BIT_NOT_TUNED   (1 << 0)
+#define AZTECH_BIT_MONO                (1 << 1)
+/* bit definitions for register write */
+#define AZTECH_BIT_TUN_CE      (1 << 1)
+#define AZTECH_BIT_TUN_CLK     (1 << 6)
+#define AZTECH_BIT_TUN_DATA    (1 << 7)
+/* bits 0 and 2 are volume control, bits 3..5 are not connected */
 
-static void send_1_byte(struct aztech *az)
+static void aztech_set_pins(void *handle, u8 pins)
 {
-       udelay(radio_wait_time);
-       outb_p(128 + 2 + az->curvol, az->isa.io);
-       outb_p(128 + 64 + 2 + az->curvol, az->isa.io);
+       struct radio_isa_card *isa = handle;
+       struct aztech *az = container_of(isa, struct aztech, isa);
+       u8 bits = az->curvol;
+
+       if (pins & LM7000_DATA)
+               bits |= AZTECH_BIT_TUN_DATA;
+       if (pins & LM7000_CLK)
+               bits |= AZTECH_BIT_TUN_CLK;
+       if (pins & LM7000_CE)
+               bits |= AZTECH_BIT_TUN_CE;
+
+       outb_p(bits, az->isa.io);
 }
 
 static struct radio_isa_card *aztech_alloc(void)
@@ -77,58 +89,21 @@ static struct radio_isa_card *aztech_alloc(void)
 
 static int aztech_s_frequency(struct radio_isa_card *isa, u32 freq)
 {
-       struct aztech *az = container_of(isa, struct aztech, isa);
-       int  i;
-
-       freq += 171200;                 /* Add 10.7 MHz IF              */
-       freq /= 800;                    /* Convert to 50 kHz units      */
-
-       send_0_byte(az);                /*  0: LSB of frequency       */
-
-       for (i = 0; i < 13; i++)        /*   : frequency bits (1-13)  */
-               if (freq & (1 << i))
-                       send_1_byte(az);
-               else
-                       send_0_byte(az);
-
-       send_0_byte(az);                /* 14: test bit - always 0    */
-       send_0_byte(az);                /* 15: test bit - always 0    */
-       send_0_byte(az);                /* 16: band data 0 - always 0 */
-       if (isa->stereo)                /* 17: stereo (1 to enable)   */
-               send_1_byte(az);
-       else
-               send_0_byte(az);
-
-       send_1_byte(az);                /* 18: band data 1 - unknown  */
-       send_0_byte(az);                /* 19: time base - always 0   */
-       send_0_byte(az);                /* 20: spacing (0 = 25 kHz)   */
-       send_1_byte(az);                /* 21: spacing (1 = 25 kHz)   */
-       send_0_byte(az);                /* 22: spacing (0 = 25 kHz)   */
-       send_1_byte(az);                /* 23: AM/FM (FM = 1, always) */
-
-       /* latch frequency */
-
-       udelay(radio_wait_time);
-       outb_p(128 + 64 + az->curvol, az->isa.io);
+       lm7000_set_freq(freq, isa, aztech_set_pins);
 
        return 0;
 }
 
-/* thanks to Michael Dwyer for giving me a dose of clues in
- * the signal strength department..
- *
- * This card has a stereo bit - bit 0 set = mono, not set = stereo
- */
 static u32 aztech_g_rxsubchans(struct radio_isa_card *isa)
 {
-       if (inb(isa->io) & 1)
+       if (inb(isa->io) & AZTECH_BIT_MONO)
                return V4L2_TUNER_SUB_MONO;
        return V4L2_TUNER_SUB_STEREO;
 }
 
-static int aztech_s_stereo(struct radio_isa_card *isa, bool stereo)
+static u32 aztech_g_signal(struct radio_isa_card *isa)
 {
-       return aztech_s_frequency(isa, isa->freq);
+       return (inb(isa->io) & AZTECH_BIT_NOT_TUNED) ? 0 : 0xffff;
 }
 
 static int aztech_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol)
@@ -146,8 +121,8 @@ static const struct radio_isa_ops aztech_ops = {
        .alloc = aztech_alloc,
        .s_mute_volume = aztech_s_mute_volume,
        .s_frequency = aztech_s_frequency,
-       .s_stereo = aztech_s_stereo,
        .g_rxsubchans = aztech_g_rxsubchans,
+       .g_signal = aztech_g_signal,
 };
 
 static const int aztech_ioports[] = { 0x350, 0x358 };
@@ -165,7 +140,7 @@ static struct radio_isa_driver aztech_driver = {
        .radio_nr_params = radio_nr,
        .io_ports = aztech_ioports,
        .num_of_io_ports = ARRAY_SIZE(aztech_ioports),
-       .region_size = 2,
+       .region_size = 8,
        .card = "Aztech Radio",
        .ops = &aztech_ops,
        .has_stereo = true,
index bd4d3a7cdadd130511cc186679124fd6231a929c..1d1c9e1d386ea4d33c2b835075947fe9b0c9b200 100644 (file)
@@ -200,15 +200,4 @@ static struct pci_driver maxiradio_driver = {
        .remove         = maxiradio_remove,
 };
 
-static int __init maxiradio_init(void)
-{
-       return pci_register_driver(&maxiradio_driver);
-}
-
-static void __exit maxiradio_exit(void)
-{
-       pci_unregister_driver(&maxiradio_driver);
-}
-
-module_init(maxiradio_init);
-module_exit(maxiradio_exit);
+module_pci_driver(maxiradio_driver);
index ed184f68c17c5ed39c35e342018ad281eb5e23d6..c1444f84717d725a7dd3e93048b6ff7a7b7e5831 100644 (file)
@@ -476,7 +476,7 @@ select_timeout:
 }
 
 /* Enable the device for receive */
-static void ene_rx_enable(struct ene_device *dev)
+static void ene_rx_enable_hw(struct ene_device *dev)
 {
        u8 reg_value;
 
@@ -504,11 +504,17 @@ static void ene_rx_enable(struct ene_device *dev)
 
        /* enter idle mode */
        ir_raw_event_set_idle(dev->rdev, true);
+}
+
+/* Enable the device for receive - wrapper to track the state*/
+static void ene_rx_enable(struct ene_device *dev)
+{
+       ene_rx_enable_hw(dev);
        dev->rx_enabled = true;
 }
 
 /* Disable the device receiver */
-static void ene_rx_disable(struct ene_device *dev)
+static void ene_rx_disable_hw(struct ene_device *dev)
 {
        /* disable inputs */
        ene_rx_enable_cir_engine(dev, false);
@@ -516,8 +522,13 @@ static void ene_rx_disable(struct ene_device *dev)
 
        /* disable hardware IRQ and firmware flag */
        ene_clear_reg_mask(dev, ENE_FW1, ENE_FW1_ENABLE | ENE_FW1_IRQ);
-
        ir_raw_event_set_idle(dev->rdev, true);
+}
+
+/* Disable the device receiver - wrapper to track the state */
+static void ene_rx_disable(struct ene_device *dev)
+{
+       ene_rx_disable_hw(dev);
        dev->rx_enabled = false;
 }
 
@@ -1022,6 +1033,8 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
        spin_lock_init(&dev->hw_lock);
 
        dev->hw_io = pnp_port_start(pnp_dev, 0);
+       dev->irq = pnp_irq(pnp_dev, 0);
+
 
        pnp_set_drvdata(pnp_dev, dev);
        dev->pnp_dev = pnp_dev;
@@ -1085,7 +1098,6 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
                goto exit_unregister_device;
        }
 
-       dev->irq = pnp_irq(pnp_dev, 0);
        if (request_irq(dev->irq, ene_isr,
                        IRQF_SHARED, ENE_DRIVER_NAME, (void *)dev)) {
                goto exit_release_hw_io;
@@ -1123,9 +1135,8 @@ static void ene_remove(struct pnp_dev *pnp_dev)
 }
 
 /* enable wake on IR (wakes on specific button on original remote) */
-static void ene_enable_wake(struct ene_device *dev, int enable)
+static void ene_enable_wake(struct ene_device *dev, bool enable)
 {
-       enable = enable && device_may_wakeup(&dev->pnp_dev->dev);
        dbg("wake on IR %s", enable ? "enabled" : "disabled");
        ene_set_clear_reg_mask(dev, ENE_FW1, ENE_FW1_WAKE, enable);
 }
@@ -1134,9 +1145,12 @@ static void ene_enable_wake(struct ene_device *dev, int enable)
 static int ene_suspend(struct pnp_dev *pnp_dev, pm_message_t state)
 {
        struct ene_device *dev = pnp_get_drvdata(pnp_dev);
-       ene_enable_wake(dev, true);
+       bool wake = device_may_wakeup(&dev->pnp_dev->dev);
+
+       if (!wake && dev->rx_enabled)
+               ene_rx_disable_hw(dev);
 
-       /* TODO: add support for wake pattern */
+       ene_enable_wake(dev, wake);
        return 0;
 }
 
index 6f978e85db8c6ec2625f84075a81f787dfaff71e..a7911e3b9bc07d4e887dadf8a41a76cf6e1275c5 100644 (file)
 #define __dbg(level, format, ...)                              \
 do {                                                           \
        if (debug >= level)                                     \
-               pr_debug(format "\n", ## __VA_ARGS__);          \
+               pr_info(format "\n", ## __VA_ARGS__);           \
 } while (0)
 
 #define dbg(format, ...)               __dbg(1, format, ## __VA_ARGS__)
index a4ab2e6b3f82fcdba0364745e064be3970b3ba8b..19632b1c21908cb52e0c483f7a7339f647756e1e 100644 (file)
@@ -364,8 +364,8 @@ static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count)
                periods = DIV_ROUND_CLOSEST(txbuf[i] * ir->carrier, 1000000);
                bytes = DIV_ROUND_UP(periods, 127);
                if (size + bytes > ir->bufsize) {
-                       count = i;
-                       break;
+                       rc = -EINVAL;
+                       goto out;
                }
                while (periods > 127) {
                        ir->packet->payload[size++] = 127 | space;
index e4561264e12439a8f24f2a63e94ac2572b0d47a0..ed2c8a1ed8caf39ee9eae20c8ec5b5f534c33c0a 100644 (file)
@@ -140,11 +140,20 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
                goto out;
        }
 
+       for (i = 0; i < count; i++) {
+               if (txbuf[i] > IR_MAX_DURATION / 1000 - duration || !txbuf[i]) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               duration += txbuf[i];
+       }
+
        ret = dev->tx_ir(dev, txbuf, count);
        if (ret < 0)
                goto out;
 
-       for (i = 0; i < ret; i++)
+       for (duration = i = 0; i < ret; i++)
                duration += txbuf[i];
 
        ret *= sizeof(unsigned int);
@@ -375,6 +384,7 @@ static int ir_lirc_register(struct rc_dev *dev)
        drv->code_length = sizeof(struct ir_raw_event) * 8;
        drv->fops = &lirc_fops;
        drv->dev = &dev->dev;
+       drv->rdev = dev;
        drv->owner = THIS_MODULE;
 
        drv->minor = lirc_register_driver(drv);
index 8dc057b273f25b49f7f4960896828c9437e3b489..dc5cbffcd5a26a4702b578e97c995e527b644236 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/device.h>
 #include <linux/cdev.h>
 
+#include <media/rc-core.h>
 #include <media/lirc.h>
 #include <media/lirc_dev.h>
 
@@ -467,6 +468,12 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file)
                goto error;
        }
 
+       if (ir->d.rdev) {
+               retval = rc_open(ir->d.rdev);
+               if (retval)
+                       goto error;
+       }
+
        cdev = ir->cdev;
        if (try_module_get(cdev->owner)) {
                ir->open++;
@@ -511,6 +518,9 @@ int lirc_dev_fop_close(struct inode *inode, struct file *file)
 
        WARN_ON(mutex_lock_killable(&lirc_dev_lock));
 
+       if (ir->d.rdev)
+               rc_close(ir->d.rdev);
+
        ir->open--;
        if (ir->attached) {
                ir->d.set_use_dec(ir->d.data);
index 1cf382a0b27761683f6afa4d8c07aed3904ed789..1dedebda1cefb6fd9e11364ebad36cb60ab1fbb5 100644 (file)
@@ -699,19 +699,50 @@ void rc_keydown_notimeout(struct rc_dev *dev, int scancode, u8 toggle)
 }
 EXPORT_SYMBOL_GPL(rc_keydown_notimeout);
 
+int rc_open(struct rc_dev *rdev)
+{
+       int rval = 0;
+
+       if (!rdev)
+               return -EINVAL;
+
+       mutex_lock(&rdev->lock);
+       if (!rdev->users++)
+               rval = rdev->open(rdev);
+
+       if (rval)
+               rdev->users--;
+
+       mutex_unlock(&rdev->lock);
+
+       return rval;
+}
+EXPORT_SYMBOL_GPL(rc_open);
+
 static int ir_open(struct input_dev *idev)
 {
        struct rc_dev *rdev = input_get_drvdata(idev);
 
-       return rdev->open(rdev);
+       return rc_open(rdev);
+}
+
+void rc_close(struct rc_dev *rdev)
+{
+       if (rdev) {
+               mutex_lock(&rdev->lock);
+
+                if (!--rdev->users)
+                       rdev->close(rdev);
+
+               mutex_unlock(&rdev->lock);
+       }
 }
+EXPORT_SYMBOL_GPL(rc_close);
 
 static void ir_close(struct input_dev *idev)
 {
        struct rc_dev *rdev = input_get_drvdata(idev);
-
-        if (rdev)
-               rdev->close(rdev);
+       rc_close(rdev);
 }
 
 /* class for /sys/class/rc */
@@ -1076,7 +1107,14 @@ int rc_register_device(struct rc_dev *dev)
        memcpy(&dev->input_dev->id, &dev->input_id, sizeof(dev->input_id));
        dev->input_dev->phys = dev->input_phys;
        dev->input_dev->name = dev->input_name;
+
+       /* input_register_device can call ir_open, so unlock mutex here */
+       mutex_unlock(&dev->lock);
+
        rc = input_register_device(dev->input_dev);
+
+       mutex_lock(&dev->lock);
+
        if (rc)
                goto out_table;
 
index 12167a6b5472d02e242b7b686a068f90e68d3797..0042367b060cc5b5cf578f1691ce43248a2a4747 100644 (file)
@@ -206,8 +206,6 @@ struct redrat3_dev {
        struct timer_list rx_timeout;
        u32 hw_timeout;
 
-       /* is the detector enabled*/
-       bool det_enabled;
        /* Is the device currently transmitting?*/
        bool transmitting;
 
@@ -472,32 +470,11 @@ static int redrat3_enable_detector(struct redrat3_dev *rr3)
                return -EIO;
        }
 
-       rr3->det_enabled = true;
        redrat3_issue_async(rr3);
 
        return 0;
 }
 
-/* Disables the rr3 long range detector */
-static void redrat3_disable_detector(struct redrat3_dev *rr3)
-{
-       struct device *dev = rr3->dev;
-       u8 ret;
-
-       rr3_ftr(dev, "Entering %s\n", __func__);
-
-       ret = redrat3_send_cmd(RR3_RC_DET_DISABLE, rr3);
-       if (ret != 0)
-               dev_err(dev, "%s: failure!\n", __func__);
-
-       ret = redrat3_send_cmd(RR3_RC_DET_STATUS, rr3);
-       if (ret != 0)
-               dev_warn(dev, "%s: detector status: %d, should be 0\n",
-                        __func__, ret);
-
-       rr3->det_enabled = false;
-}
-
 static inline void redrat3_delete(struct redrat3_dev *rr3,
                                  struct usb_device *udev)
 {
@@ -785,10 +762,10 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf,
                return -EAGAIN;
        }
 
-       count = min_t(unsigned, count, RR3_MAX_SIG_SIZE - RR3_TX_TRAILER_LEN);
+       if (count > RR3_MAX_SIG_SIZE - RR3_TX_TRAILER_LEN)
+               return -EINVAL;
 
        /* rr3 will disable rc detector on transmit */
-       rr3->det_enabled = false;
        rr3->transmitting = true;
 
        sample_lens = kzalloc(sizeof(int) * RR3_DRIVER_MAXLENS, GFP_KERNEL);
@@ -825,8 +802,8 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf,
                                                &irdata->lens[curlencheck]);
                                curlencheck++;
                        } else {
-                               count = i - 1;
-                               break;
+                               ret = -EINVAL;
+                               goto out;
                        }
                }
                irdata->sigdata[i] = lencheck;
@@ -868,7 +845,6 @@ out:
 
        rr3->transmitting = false;
        /* rr3 re-enables rc detector because it was enabled before */
-       rr3->det_enabled = true;
 
        return ret;
 }
@@ -1048,8 +1024,6 @@ static void redrat3_dev_disconnect(struct usb_interface *intf)
        if (!rr3)
                return;
 
-       redrat3_disable_detector(rr3);
-
        usb_set_intfdata(intf, NULL);
        rc_unregister_device(rr3->rc);
        del_timer_sync(&rr3->rx_timeout);
index a3c8ecf22078b46118e38c1a102e6ce07b317b13..2059d0c86ad3ad4b91da3c84543bd8fdf74ec213 100644 (file)
@@ -1,6 +1,6 @@
 config DVB_USB_V2
        tristate "Support for various USB DVB devices v2"
-       depends on DVB_CORE && USB && I2C
+       depends on DVB_CORE && USB && I2C && (RC_CORE || RC_CORE=n)
        help
          By enabling this you will be able to choose the various supported
          USB1.1 and USB2.0 DVB devices.
index f08136052f9c483de1e72ad4edb86bd446d82d8d..829323e42ca095671372ec15de5cea81a4810fea 100644 (file)
@@ -3589,6 +3589,8 @@ struct usb_device_id dib0700_usb_id_table[] = {
        { USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_TFE7790P) },
        { USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_TFE8096P) },
 /* 80 */{ USB_DEVICE(USB_VID_ELGATO,   USB_PID_ELGATO_EYETV_DTT_2) },
+       { USB_DEVICE(USB_VID_PCTV,      USB_PID_PCTV_2002E) },
+       { USB_DEVICE(USB_VID_PCTV,      USB_PID_PCTV_2002E_SE) },
        { 0 }           /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -3993,12 +3995,20 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        }
                },
 
-               .num_device_descs = 1,
+               .num_device_descs = 3,
                .devices = {
                        {   "Hauppauge Nova-TD Stick (52009)",
                                { &dib0700_usb_id_table[35], NULL },
                                { NULL },
                        },
+                       {   "PCTV 2002e",
+                               { &dib0700_usb_id_table[81], NULL },
+                               { NULL },
+                       },
+                       {   "PCTV 2002e SE",
+                               { &dib0700_usb_id_table[82], NULL },
+                               { NULL },
+                       },
                },
 
                .rc.core = {
index c2b635d6a17a9df6ad17f838e1ad715601fbefdd..0306cb778df4b07683fb05bc42949616ee03a55d 100644 (file)
@@ -1212,7 +1212,7 @@ static struct dvb_usb_device_properties vp7049_properties = {
                .rc_interval    = 150,
                .rc_codes       = RC_MAP_TWINHAN_VP1027_DVBS,
                .rc_query       = m920x_rc_core_query,
-               .allowed_protos = RC_TYPE_UNKNOWN,
+               .allowed_protos = RC_BIT_UNKNOWN,
        },
 
        .size_of_priv     = sizeof(struct m920x_state),
index 4851cc2e4a4d3227b59df97c8020298b41796c77..c4ff9739a7ae8cb099b21637dc23723e5e170d1b 100644 (file)
@@ -726,7 +726,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus,
 
        *eedata = data;
        *eedata_len = len;
-       dev_config = (void *)eedata;
+       dev_config = (void *)*eedata;
 
        switch (le16_to_cpu(dev_config->chip_conf) >> 4 & 0x3) {
        case 0:
index 1a577ed8ea0ca0163e9203e9db0a143ccd65a743..9d103344f34ab5e4e3267ca8fa08f58db1f5a741 100644 (file)
@@ -1008,6 +1008,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
        else
                f->fmt.pix.field = dev->interlaced ?
                           V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;
+       f->fmt.pix.priv = 0;
 
        return 0;
 }
index cb694055ba7d103ad75bfd73b2f41a0b0cb1e315..6e5070774dc2ca480fe3970c75bb79c0a893e47b 100644 (file)
@@ -303,6 +303,11 @@ static int hdpvr_probe(struct usb_interface *interface,
 
        dev->workqueue = 0;
 
+       /* init video transfer queues first of all */
+       /* to prevent oops in hdpvr_delete() on error paths */
+       INIT_LIST_HEAD(&dev->free_buff_list);
+       INIT_LIST_HEAD(&dev->rec_buff_list);
+
        /* register v4l2_device early so it can be used for printks */
        if (v4l2_device_register(&interface->dev, &dev->v4l2_dev)) {
                dev_err(&interface->dev, "v4l2_device_register failed\n");
@@ -325,10 +330,6 @@ static int hdpvr_probe(struct usb_interface *interface,
        if (!dev->workqueue)
                goto error;
 
-       /* init video transfer queues */
-       INIT_LIST_HEAD(&dev->free_buff_list);
-       INIT_LIST_HEAD(&dev->rec_buff_list);
-
        dev->options = hdpvr_default_options;
 
        if (default_video_input < HDPVR_VIDEO_INPUTS)
@@ -405,7 +406,7 @@ static int hdpvr_probe(struct usb_interface *interface,
                                    video_nr[atomic_inc_return(&dev_nr)]);
        if (retval < 0) {
                v4l2_err(&dev->v4l2_dev, "registering videodev failed\n");
-               goto error;
+               goto reg_fail;
        }
 
        /* let the user know what node this device is now attached to */
index ab97e7d0b4f25e2cdd7adf239be95cecfa70e546..6bc9b8e19e20d889d225fdc1864f15b881b18184 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  s2255drv.c - a driver for the Sensoray 2255 USB video capture device
  *
- *   Copyright (C) 2007-2010 by Sensoray Company Inc.
+ *   Copyright (C) 2007-2013 by Sensoray Company Inc.
  *                              Dean Anderson
  *
  * Some video buffer code based on vivi driver:
@@ -52,7 +52,7 @@
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-event.h>
 
-#define S2255_VERSION          "1.22.1"
+#define S2255_VERSION          "1.23.1"
 #define FIRMWARE_FILE_NAME "f2255usb.bin"
 
 /* default JPEG quality */
@@ -1303,11 +1303,6 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id i)
        int ret = 0;
 
        mutex_lock(&q->vb_lock);
-       if (videobuf_queue_is_busy(q)) {
-               dprintk(1, "queue busy\n");
-               ret = -EBUSY;
-               goto out_s_std;
-       }
        if (res_locked(fh)) {
                dprintk(1, "can't change standard after started\n");
                ret = -EBUSY;
index 1c3a1ec00237c4b6b2e2f3d10a2e7205d6d853fc..95584c15dc5aa7813444a3d51408142b8032b357 100644 (file)
@@ -1,8 +1,6 @@
-config VIDEO_STK1160
+config VIDEO_STK1160_COMMON
        tristate "STK1160 USB video capture support"
        depends on VIDEO_DEV && I2C
-       select VIDEOBUF2_VMALLOC
-       select VIDEO_SAA711X
 
        ---help---
          This is a video4linux driver for STK1160 based video capture devices.
@@ -12,9 +10,15 @@ config VIDEO_STK1160
 
 config VIDEO_STK1160_AC97
        bool "STK1160 AC97 codec support"
-       depends on VIDEO_STK1160 && SND
-       select SND_AC97_CODEC
+       depends on VIDEO_STK1160_COMMON && SND
 
        ---help---
          Enables AC97 codec support for stk1160 driver.
-.
+
+config VIDEO_STK1160
+       tristate
+       depends on (!VIDEO_STK1160_AC97 || (SND='n') || SND) && VIDEO_STK1160_COMMON
+       default y
+       select VIDEOBUF2_VMALLOC
+       select VIDEO_SAA711X
+       select SND_AC97_CODEC if SND
index 876fc26565e3bc05dbfe4a192ffe916080495fb2..c45c9881bb5f4fdad89cf9ffe45c1c05cf8d946c 100644 (file)
@@ -379,6 +379,9 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
        struct stk1160 *dev = video_drvdata(file);
        struct vb2_queue *q = &dev->vb_vidq;
 
+       if (dev->norm == norm)
+               return 0;
+
        if (vb2_is_busy(q))
                return -EBUSY;
 
@@ -440,9 +443,6 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
 {
        struct stk1160 *dev = video_drvdata(file);
 
-       if (vb2_is_busy(&dev->vb_vidq))
-               return -EBUSY;
-
        if (i > STK1160_MAX_INPUT)
                return -EINVAL;
 
index e07e4c699cc215344b86f10433f659a088617d00..95f94e5aa66d2a14910bc0b81eec3bf595534f02 100644 (file)
@@ -375,7 +375,7 @@ static inline void set_map_flags(struct poseidon *pd, struct usb_device *udev)
 }
 #endif
 
-static int check_firmware(struct usb_device *udev, int *down_firmware)
+static int check_firmware(struct usb_device *udev)
 {
        void *buf;
        int ret;
@@ -395,10 +395,8 @@ static int check_firmware(struct usb_device *udev, int *down_firmware)
                         USB_CTRL_GET_TIMEOUT);
        kfree(buf);
 
-       if (ret < 0) {
-               *down_firmware = 1;
+       if (ret < 0)
                return firmware_download(udev);
-       }
        return 0;
 }
 
@@ -411,9 +409,9 @@ static int poseidon_probe(struct usb_interface *interface,
        int new_one = 0;
 
        /* download firmware */
-       check_firmware(udev, &ret);
+       ret = check_firmware(udev);
        if (ret)
-               return 0;
+               return ret;
 
        /* Do I recovery from the hibernate ? */
        pd = find_old_poseidon(udev);
@@ -436,12 +434,22 @@ static int poseidon_probe(struct usb_interface *interface,
 
                /* register v4l2 device */
                ret = v4l2_device_register(&interface->dev, &pd->v4l2_dev);
+               if (ret)
+                       goto err_v4l2;
 
                /* register devices in directory /dev */
                ret = pd_video_init(pd);
-               poseidon_audio_init(pd);
-               poseidon_fm_init(pd);
-               pd_dvb_usb_device_init(pd);
+               if (ret)
+                       goto err_video;
+               ret = poseidon_audio_init(pd);
+               if (ret)
+                       goto err_audio;
+               ret = poseidon_fm_init(pd);
+               if (ret)
+                       goto err_fm;
+               ret = pd_dvb_usb_device_init(pd);
+               if (ret)
+                       goto err_dvb;
 
                INIT_LIST_HEAD(&pd->device_list);
                list_add_tail(&pd->device_list, &pd_device_list);
@@ -459,6 +467,17 @@ static int poseidon_probe(struct usb_interface *interface,
        }
 #endif
        return 0;
+err_dvb:
+       poseidon_fm_exit(pd);
+err_fm:
+       poseidon_audio_free(pd);
+err_audio:
+       pd_video_exit(pd);
+err_video:
+       v4l2_device_unregister(&pd->v4l2_dev);
+err_v4l2:
+       kfree(pd);
+       return ret;
 }
 
 static void poseidon_disconnect(struct usb_interface *interface)
index 8864436464bf2d9e6aaf3199fb58a5d9e10294ab..7c5b86006ee627c43a52003fb816c7fceb10b6f4 100644 (file)
@@ -1,6 +1,6 @@
 config VIDEO_USBTV
         tristate "USBTV007 video capture support"
-        depends on VIDEO_DEV
+        depends on VIDEO_V4L2
         select VIDEOBUF2_VMALLOC
 
         ---help---
index bf43f874685e2e5ba6acf97e891b8a09a7676432..8a505a90d3189a59876a916507ae50b6e11a0ed9 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/usb.h>
-#include <linux/version.h>
 #include <linux/videodev2.h>
 
 #include <media/v4l2-device.h>
@@ -57,7 +56,7 @@
 #define USBTV_CHUNK_SIZE       256
 #define USBTV_CHUNK            240
 #define USBTV_CHUNKS           (USBTV_WIDTH * USBTV_HEIGHT \
-                                       / 2 / USBTV_CHUNK)
+                                       / 4 / USBTV_CHUNK)
 
 /* Chunk header. */
 #define USBTV_MAGIC_OK(chunk)  ((be32_to_cpu(chunk[0]) & 0xff000000) \
@@ -89,18 +88,80 @@ struct usbtv {
        /* Number of currently processed frame, useful find
         * out when a new one begins. */
        u32 frame_id;
+       int chunks_done;
 
+       enum {
+               USBTV_COMPOSITE_INPUT,
+               USBTV_SVIDEO_INPUT,
+       } input;
        int iso_size;
        unsigned int sequence;
        struct urb *isoc_urbs[USBTV_ISOC_TRANSFERS];
 };
 
-static int usbtv_setup_capture(struct usbtv *usbtv)
+static int usbtv_set_regs(struct usbtv *usbtv, const u16 regs[][2], int size)
 {
        int ret;
        int pipe = usb_rcvctrlpipe(usbtv->udev, 0);
        int i;
-       static const u16 protoregs[][2] = {
+
+       for (i = 0; i < size; i++) {
+               u16 index = regs[i][0];
+               u16 value = regs[i][1];
+
+               ret = usb_control_msg(usbtv->udev, pipe, USBTV_REQUEST_REG,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       value, index, NULL, 0, 0);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int usbtv_select_input(struct usbtv *usbtv, int input)
+{
+       int ret;
+
+       static const u16 composite[][2] = {
+               { USBTV_BASE + 0x0105, 0x0060 },
+               { USBTV_BASE + 0x011f, 0x00f2 },
+               { USBTV_BASE + 0x0127, 0x0060 },
+               { USBTV_BASE + 0x00ae, 0x0010 },
+               { USBTV_BASE + 0x0284, 0x00aa },
+               { USBTV_BASE + 0x0239, 0x0060 },
+       };
+
+       static const u16 svideo[][2] = {
+               { USBTV_BASE + 0x0105, 0x0010 },
+               { USBTV_BASE + 0x011f, 0x00ff },
+               { USBTV_BASE + 0x0127, 0x0060 },
+               { USBTV_BASE + 0x00ae, 0x0030 },
+               { USBTV_BASE + 0x0284, 0x0088 },
+               { USBTV_BASE + 0x0239, 0x0060 },
+       };
+
+       switch (input) {
+       case USBTV_COMPOSITE_INPUT:
+               ret = usbtv_set_regs(usbtv, composite, ARRAY_SIZE(composite));
+               break;
+       case USBTV_SVIDEO_INPUT:
+               ret = usbtv_set_regs(usbtv, svideo, ARRAY_SIZE(svideo));
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       if (!ret)
+               usbtv->input = input;
+
+       return ret;
+}
+
+static int usbtv_setup_capture(struct usbtv *usbtv)
+{
+       int ret;
+       static const u16 setup[][2] = {
                /* These seem to enable the device. */
                { USBTV_BASE + 0x0008, 0x0001 },
                { USBTV_BASE + 0x01d0, 0x00ff },
@@ -188,20 +249,37 @@ static int usbtv_setup_capture(struct usbtv *usbtv)
                { USBTV_BASE + 0x024f, 0x0002 },
        };
 
-       for (i = 0; i < ARRAY_SIZE(protoregs); i++) {
-               u16 index = protoregs[i][0];
-               u16 value = protoregs[i][1];
+       ret = usbtv_set_regs(usbtv, setup, ARRAY_SIZE(setup));
+       if (ret)
+               return ret;
 
-               ret = usb_control_msg(usbtv->udev, pipe, USBTV_REQUEST_REG,
-                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                       value, index, NULL, 0, 0);
-               if (ret < 0)
-                       return ret;
-       }
+       ret = usbtv_select_input(usbtv, usbtv->input);
+       if (ret)
+               return ret;
 
        return 0;
 }
 
+/* Copy data from chunk into a frame buffer, deinterlacing the data
+ * into every second line. Unfortunately, they don't align nicely into
+ * 720 pixel lines, as the chunk is 240 words long, which is 480 pixels.
+ * Therefore, we break down the chunk into two halves before copyting,
+ * so that we can interleave a line if needed. */
+static void usbtv_chunk_to_vbuf(u32 *frame, u32 *src, int chunk_no, int odd)
+{
+       int half;
+
+       for (half = 0; half < 2; half++) {
+               int part_no = chunk_no * 2 + half;
+               int line = part_no / 3;
+               int part_index = (line * 2 + !odd) * 3 + (part_no % 3);
+
+               u32 *dst = &frame[part_index * USBTV_CHUNK/2];
+               memcpy(dst, src, USBTV_CHUNK/2 * sizeof(*src));
+               src += USBTV_CHUNK/2;
+       }
+}
+
 /* Called for each 256-byte image chunk.
  * First word identifies the chunk, followed by 240 words of image
  * data and padding. */
@@ -218,17 +296,17 @@ static void usbtv_image_chunk(struct usbtv *usbtv, u32 *chunk)
        frame_id = USBTV_FRAME_ID(chunk);
        odd = USBTV_ODD(chunk);
        chunk_no = USBTV_CHUNK_NO(chunk);
-
-       /* Deinterlace. TODO: Use interlaced frame format. */
-       chunk_no = (chunk_no - chunk_no % 3) * 2 + chunk_no % 3;
-       chunk_no += !odd * 3;
-
        if (chunk_no >= USBTV_CHUNKS)
                return;
 
        /* Beginning of a frame. */
-       if (chunk_no == 0)
+       if (chunk_no == 0) {
                usbtv->frame_id = frame_id;
+               usbtv->chunks_done = 0;
+       }
+
+       if (usbtv->frame_id != frame_id)
+               return;
 
        spin_lock_irqsave(&usbtv->buflock, flags);
        if (list_empty(&usbtv->bufs)) {
@@ -241,19 +319,23 @@ static void usbtv_image_chunk(struct usbtv *usbtv, u32 *chunk)
        buf = list_first_entry(&usbtv->bufs, struct usbtv_buf, list);
        frame = vb2_plane_vaddr(&buf->vb, 0);
 
-       /* Copy the chunk. */
-       memcpy(&frame[chunk_no * USBTV_CHUNK], &chunk[1],
-                       USBTV_CHUNK * sizeof(chunk[1]));
+       /* Copy the chunk data. */
+       usbtv_chunk_to_vbuf(frame, &chunk[1], chunk_no, odd);
+       usbtv->chunks_done++;
 
        /* Last chunk in a frame, signalling an end */
-       if (usbtv->frame_id && chunk_no == USBTV_CHUNKS-1) {
+       if (odd && chunk_no == USBTV_CHUNKS-1) {
                int size = vb2_plane_size(&buf->vb, 0);
+               enum vb2_buffer_state state = usbtv->chunks_done ==
+                                               USBTV_CHUNKS ?
+                                               VB2_BUF_STATE_DONE :
+                                               VB2_BUF_STATE_ERROR;
 
                buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED;
                buf->vb.v4l2_buf.sequence = usbtv->sequence++;
                v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
                vb2_set_plane_payload(&buf->vb, 0, size);
-               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
+               vb2_buffer_done(&buf->vb, state);
                list_del(&buf->list);
        }
 
@@ -418,10 +500,17 @@ static int usbtv_querycap(struct file *file, void *priv,
 static int usbtv_enum_input(struct file *file, void *priv,
                                        struct v4l2_input *i)
 {
-       if (i->index > 0)
+       switch (i->index) {
+       case USBTV_COMPOSITE_INPUT:
+               strlcpy(i->name, "Composite", sizeof(i->name));
+               break;
+       case USBTV_SVIDEO_INPUT:
+               strlcpy(i->name, "S-Video", sizeof(i->name));
+               break;
+       default:
                return -EINVAL;
+       }
 
-       strlcpy(i->name, "Composite", sizeof(i->name));
        i->type = V4L2_INPUT_TYPE_CAMERA;
        i->std = V4L2_STD_525_60;
        return 0;
@@ -461,15 +550,15 @@ static int usbtv_g_std(struct file *file, void *priv, v4l2_std_id *norm)
 
 static int usbtv_g_input(struct file *file, void *priv, unsigned int *i)
 {
-       *i = 0;
+       struct usbtv *usbtv = video_drvdata(file);
+       *i = usbtv->input;
        return 0;
 }
 
 static int usbtv_s_input(struct file *file, void *priv, unsigned int i)
 {
-       if (i > 0)
-               return -EINVAL;
-       return 0;
+       struct usbtv *usbtv = video_drvdata(file);
+       return usbtv_select_input(usbtv, i);
 }
 
 static int usbtv_s_std(struct file *file, void *priv, v4l2_std_id norm)
@@ -518,7 +607,7 @@ static int usbtv_queue_setup(struct vb2_queue *vq,
        if (*nbuffers < 2)
                *nbuffers = 2;
        *nplanes = 1;
-       sizes[0] = USBTV_CHUNK * USBTV_CHUNKS * sizeof(u32);
+       sizes[0] = USBTV_WIDTH * USBTV_HEIGHT / 2 * sizeof(u32);
 
        return 0;
 }
index aae241730caad2cd16f116c6a54317128da7cbbb..b350ab99652ce58131b8d8b8505c61d5accce9c6 100644 (file)
@@ -27,7 +27,6 @@ static bool match_i2c(struct device *dev, struct v4l2_async_subdev *asd)
 #if IS_ENABLED(CONFIG_I2C)
        struct i2c_client *client = i2c_verify_client(dev);
        return client &&
-               asd->bus_type == V4L2_ASYNC_BUS_I2C &&
                asd->match.i2c.adapter_id == client->adapter->nr &&
                asd->match.i2c.address == client->addr;
 #else
@@ -35,10 +34,14 @@ static bool match_i2c(struct device *dev, struct v4l2_async_subdev *asd)
 #endif
 }
 
-static bool match_platform(struct device *dev, struct v4l2_async_subdev *asd)
+static bool match_devname(struct device *dev, struct v4l2_async_subdev *asd)
 {
-       return asd->bus_type == V4L2_ASYNC_BUS_PLATFORM &&
-               !strcmp(asd->match.platform.name, dev_name(dev));
+       return !strcmp(asd->match.device_name.name, dev_name(dev));
+}
+
+static bool match_of(struct device *dev, struct v4l2_async_subdev *asd)
+{
+       return dev->of_node == asd->match.of.node;
 }
 
 static LIST_HEAD(subdev_list);
@@ -46,28 +49,29 @@ static LIST_HEAD(notifier_list);
 static DEFINE_MUTEX(list_lock);
 
 static struct v4l2_async_subdev *v4l2_async_belongs(struct v4l2_async_notifier *notifier,
-                                                   struct v4l2_async_subdev_list *asdl)
+                                                   struct v4l2_subdev *sd)
 {
-       struct v4l2_subdev *sd = v4l2_async_to_subdev(asdl);
        struct v4l2_async_subdev *asd;
-       bool (*match)(struct device *,
-                     struct v4l2_async_subdev *);
+       bool (*match)(struct device *, struct v4l2_async_subdev *);
 
        list_for_each_entry(asd, &notifier->waiting, list) {
                /* bus_type has been verified valid before */
-               switch (asd->bus_type) {
-               case V4L2_ASYNC_BUS_CUSTOM:
+               switch (asd->match_type) {
+               case V4L2_ASYNC_MATCH_CUSTOM:
                        match = asd->match.custom.match;
                        if (!match)
                                /* Match always */
                                return asd;
                        break;
-               case V4L2_ASYNC_BUS_PLATFORM:
-                       match = match_platform;
+               case V4L2_ASYNC_MATCH_DEVNAME:
+                       match = match_devname;
                        break;
-               case V4L2_ASYNC_BUS_I2C:
+               case V4L2_ASYNC_MATCH_I2C:
                        match = match_i2c;
                        break;
+               case V4L2_ASYNC_MATCH_OF:
+                       match = match_of;
+                       break;
                default:
                        /* Cannot happen, unless someone breaks us */
                        WARN_ON(true);
@@ -83,16 +87,15 @@ static struct v4l2_async_subdev *v4l2_async_belongs(struct v4l2_async_notifier *
 }
 
 static int v4l2_async_test_notify(struct v4l2_async_notifier *notifier,
-                                 struct v4l2_async_subdev_list *asdl,
+                                 struct v4l2_subdev *sd,
                                  struct v4l2_async_subdev *asd)
 {
-       struct v4l2_subdev *sd = v4l2_async_to_subdev(asdl);
        int ret;
 
        /* Remove from the waiting list */
        list_del(&asd->list);
-       asdl->asd = asd;
-       asdl->notifier = notifier;
+       sd->asd = asd;
+       sd->notifier = notifier;
 
        if (notifier->bound) {
                ret = notifier->bound(notifier, sd, asd);
@@ -100,7 +103,7 @@ static int v4l2_async_test_notify(struct v4l2_async_notifier *notifier,
                        return ret;
        }
        /* Move from the global subdevice list to notifier's done */
-       list_move(&asdl->list, &notifier->done);
+       list_move(&sd->async_list, &notifier->done);
 
        ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd);
        if (ret < 0) {
@@ -115,21 +118,19 @@ static int v4l2_async_test_notify(struct v4l2_async_notifier *notifier,
        return 0;
 }
 
-static void v4l2_async_cleanup(struct v4l2_async_subdev_list *asdl)
+static void v4l2_async_cleanup(struct v4l2_subdev *sd)
 {
-       struct v4l2_subdev *sd = v4l2_async_to_subdev(asdl);
-
        v4l2_device_unregister_subdev(sd);
-       /* Subdevice driver will reprobe and put asdl back onto the list */
-       list_del_init(&asdl->list);
-       asdl->asd = NULL;
+       /* Subdevice driver will reprobe and put the subdev back onto the list */
+       list_del_init(&sd->async_list);
+       sd->asd = NULL;
        sd->dev = NULL;
 }
 
 int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
                                 struct v4l2_async_notifier *notifier)
 {
-       struct v4l2_async_subdev_list *asdl, *tmp;
+       struct v4l2_subdev *sd, *tmp;
        struct v4l2_async_subdev *asd;
        int i;
 
@@ -141,17 +142,18 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
        INIT_LIST_HEAD(&notifier->done);
 
        for (i = 0; i < notifier->num_subdevs; i++) {
-               asd = notifier->subdev[i];
+               asd = notifier->subdevs[i];
 
-               switch (asd->bus_type) {
-               case V4L2_ASYNC_BUS_CUSTOM:
-               case V4L2_ASYNC_BUS_PLATFORM:
-               case V4L2_ASYNC_BUS_I2C:
+               switch (asd->match_type) {
+               case V4L2_ASYNC_MATCH_CUSTOM:
+               case V4L2_ASYNC_MATCH_DEVNAME:
+               case V4L2_ASYNC_MATCH_I2C:
+               case V4L2_ASYNC_MATCH_OF:
                        break;
                default:
                        dev_err(notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL,
-                               "Invalid bus-type %u on %p\n",
-                               asd->bus_type, asd);
+                               "Invalid match type %u on %p\n",
+                               asd->match_type, asd);
                        return -EINVAL;
                }
                list_add_tail(&asd->list, &notifier->waiting);
@@ -162,14 +164,14 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
        /* Keep also completed notifiers on the list */
        list_add(&notifier->list, &notifier_list);
 
-       list_for_each_entry_safe(asdl, tmp, &subdev_list, list) {
+       list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) {
                int ret;
 
-               asd = v4l2_async_belongs(notifier, asdl);
+               asd = v4l2_async_belongs(notifier, sd);
                if (!asd)
                        continue;
 
-               ret = v4l2_async_test_notify(notifier, asdl, asd);
+               ret = v4l2_async_test_notify(notifier, sd, asd);
                if (ret < 0) {
                        mutex_unlock(&list_lock);
                        return ret;
@@ -184,7 +186,7 @@ EXPORT_SYMBOL(v4l2_async_notifier_register);
 
 void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
 {
-       struct v4l2_async_subdev_list *asdl, *tmp;
+       struct v4l2_subdev *sd, *tmp;
        unsigned int notif_n_subdev = notifier->num_subdevs;
        unsigned int n_subdev = min(notif_n_subdev, V4L2_MAX_SUBDEVS);
        struct device *dev[n_subdev];
@@ -194,18 +196,16 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
 
        list_del(&notifier->list);
 
-       list_for_each_entry_safe(asdl, tmp, &notifier->done, list) {
-               struct v4l2_subdev *sd = v4l2_async_to_subdev(asdl);
-
+       list_for_each_entry_safe(sd, tmp, &notifier->done, list) {
                dev[i] = get_device(sd->dev);
 
-               v4l2_async_cleanup(asdl);
+               v4l2_async_cleanup(sd);
 
                /* If we handled USB devices, we'd have to lock the parent too */
                device_release_driver(dev[i++]);
 
                if (notifier->unbind)
-                       notifier->unbind(notifier, sd, sd->asdl.asd);
+                       notifier->unbind(notifier, sd, sd->asd);
        }
 
        mutex_unlock(&list_lock);
@@ -234,24 +234,23 @@ EXPORT_SYMBOL(v4l2_async_notifier_unregister);
 
 int v4l2_async_register_subdev(struct v4l2_subdev *sd)
 {
-       struct v4l2_async_subdev_list *asdl = &sd->asdl;
        struct v4l2_async_notifier *notifier;
 
        mutex_lock(&list_lock);
 
-       INIT_LIST_HEAD(&asdl->list);
+       INIT_LIST_HEAD(&sd->async_list);
 
        list_for_each_entry(notifier, &notifier_list, list) {
-               struct v4l2_async_subdev *asd = v4l2_async_belongs(notifier, asdl);
+               struct v4l2_async_subdev *asd = v4l2_async_belongs(notifier, sd);
                if (asd) {
-                       int ret = v4l2_async_test_notify(notifier, asdl, asd);
+                       int ret = v4l2_async_test_notify(notifier, sd, asd);
                        mutex_unlock(&list_lock);
                        return ret;
                }
        }
 
        /* None matched, wait for hot-plugging */
-       list_add(&asdl->list, &subdev_list);
+       list_add(&sd->async_list, &subdev_list);
 
        mutex_unlock(&list_lock);
 
@@ -261,23 +260,22 @@ EXPORT_SYMBOL(v4l2_async_register_subdev);
 
 void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
 {
-       struct v4l2_async_subdev_list *asdl = &sd->asdl;
-       struct v4l2_async_notifier *notifier = asdl->notifier;
+       struct v4l2_async_notifier *notifier = sd->notifier;
 
-       if (!asdl->asd) {
-               if (!list_empty(&asdl->list))
-                       v4l2_async_cleanup(asdl);
+       if (!sd->asd) {
+               if (!list_empty(&sd->async_list))
+                       v4l2_async_cleanup(sd);
                return;
        }
 
        mutex_lock(&list_lock);
 
-       list_add(&asdl->asd->list, &notifier->waiting);
+       list_add(&sd->asd->list, &notifier->waiting);
 
-       v4l2_async_cleanup(asdl);
+       v4l2_async_cleanup(sd);
 
        if (notifier->unbind)
-               notifier->unbind(notifier, sd, sd->asdl.asd);
+               notifier->unbind(notifier, sd, sd->asd);
 
        mutex_unlock(&list_lock);
 }
index e96497f7c3ed1b598106da2b7aa51f9a46284c68..89b90672088c7473bd80bd09ce1c47df4fc7bc2c 100644 (file)
@@ -196,6 +196,10 @@ static void v4l2_m2m_try_run(struct v4l2_m2m_dev *m2m_dev)
  * 2) at least one destination buffer has to be queued,
  * 3) streaming has to be on.
  *
+ * If a queue is buffered (for example a decoder hardware ringbuffer that has
+ * to be drained before doing streamoff), allow scheduling without v4l2 buffers
+ * on that queue.
+ *
  * There may also be additional, custom requirements. In such case the driver
  * should supply a custom callback (job_ready in v4l2_m2m_ops) that should
  * return 1 if the instance is ready.
@@ -224,7 +228,8 @@ static void v4l2_m2m_try_schedule(struct v4l2_m2m_ctx *m2m_ctx)
        }
 
        spin_lock_irqsave(&m2m_ctx->out_q_ctx.rdy_spinlock, flags_out);
-       if (list_empty(&m2m_ctx->out_q_ctx.rdy_queue)) {
+       if (list_empty(&m2m_ctx->out_q_ctx.rdy_queue)
+           && !m2m_ctx->out_q_ctx.buffered) {
                spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock,
                                        flags_out);
                spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job);
@@ -232,7 +237,8 @@ static void v4l2_m2m_try_schedule(struct v4l2_m2m_ctx *m2m_ctx)
                return;
        }
        spin_lock_irqsave(&m2m_ctx->cap_q_ctx.rdy_spinlock, flags_cap);
-       if (list_empty(&m2m_ctx->cap_q_ctx.rdy_queue)) {
+       if (list_empty(&m2m_ctx->cap_q_ctx.rdy_queue)
+           && !m2m_ctx->cap_q_ctx.buffered) {
                spin_unlock_irqrestore(&m2m_ctx->cap_q_ctx.rdy_spinlock,
                                        flags_cap);
                spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock,
index 3c157faee645805f398cc2047d5f7b035555aacc..0d68eb1a5ec528924695959646a29a31d87ca1a8 100644 (file)
@@ -3093,6 +3093,10 @@ static struct mfd_cell db8500_prcmu_devs[] = {
                .platform_data = &db8500_cpufreq_table,
                .pdata_size = sizeof(db8500_cpufreq_table),
        },
+       {
+               .name = "cpuidle-dbx500",
+               .of_compatible = "stericsson,cpuidle-dbx500",
+       },
        {
                .name = "db8500-thermal",
                .num_resources = ARRAY_SIZE(db8500_thsens_resources),
index b72edb72f7d269ccbeb75ff3c9193974e3d11a3e..718843cfacfca1f6712410f73072d5abcd825c8f 100644 (file)
@@ -795,9 +795,13 @@ static void tmio_mmc_power_on(struct tmio_mmc_host *host, unsigned short vdd)
         * omap_hsmmc.c driver does.
         */
        if (!IS_ERR(mmc->supply.vqmmc) && !ret) {
-               regulator_enable(mmc->supply.vqmmc);
+               ret = regulator_enable(mmc->supply.vqmmc);
                udelay(200);
        }
+
+       if (ret < 0)
+               dev_dbg(&host->pdev->dev, "Regulators failed to power up: %d\n",
+                       ret);
 }
 
 static void tmio_mmc_power_off(struct tmio_mmc_host *host)
index 6eeb84c81bc2ceb16a451fae1bc4194505b2dc7f..5c813907661c3415c979b1176bf937f7c086f2c8 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright Â© 2006-2008  Florian Fainelli <florian@openwrt.org>
  *                       Mike Albon <malbon@openwrt.org>
  * Copyright Â© 2009-2010  Daniel Dickinson <openwrt@cshore.neomailbox.net>
- * Copyright Â© 2011-2012  Jonas Gorski <jonas.gorski@gmail.com>
+ * Copyright Â© 2011-2013  Jonas Gorski <jonas.gorski@gmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #include <linux/crc32.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/sizes.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 
+#include <asm/mach-bcm63xx/bcm63xx_nvram.h>
 #include <asm/mach-bcm63xx/bcm963xx_tag.h>
 #include <asm/mach-bcm63xx/board_bcm963xx.h>
 
 #define BCM63XX_EXTENDED_SIZE  0xBFC00000      /* Extended flash address */
 
-#define BCM63XX_CFE_BLOCK_SIZE 0x10000         /* always at least 64KiB */
+#define BCM63XX_CFE_BLOCK_SIZE SZ_64K          /* always at least 64KiB */
 
 #define BCM63XX_CFE_MAGIC_OFFSET 0x4e0
 
@@ -90,7 +92,8 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
                              BCM63XX_CFE_BLOCK_SIZE);
 
        cfelen = cfe_erasesize;
-       nvramlen = cfe_erasesize;
+       nvramlen = bcm63xx_nvram_get_psi_size() * SZ_1K;
+       nvramlen = roundup(nvramlen, cfe_erasesize);
 
        /* Allocate memory for buffer */
        buf = vmalloc(sizeof(struct bcm_tag));
index fff665d59a0dba759f63854bb95e25bbb998b64f..89b9d689153298f3b7a3965adf811a3d9963de7c 100644 (file)
@@ -1571,8 +1571,8 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
        xip_enable(map, chip, adr);
        /* FIXME - should have reset delay before continuing */
 
-       printk(KERN_WARNING "MTD %s(): software timeout\n",
-              __func__ );
+       printk(KERN_WARNING "MTD %s(): software timeout, address:0x%.8lx.\n",
+              __func__, adr);
 
        ret = -EIO;
  op_done:
index 18e7761137a33037a21aa61585e20d98f47b172e..2060856dbf977ad580923d06690f514c5db656c5 100644 (file)
@@ -1,6 +1,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/delay.h>
 #include <linux/mtd/mtd.h>
 #include <linux/platform_device.h>
 #include <linux/bcma/bcma.h>
@@ -12,6 +13,57 @@ MODULE_DESCRIPTION("Serial flash driver for BCMA bus");
 
 static const char * const probes[] = { "bcm47xxpart", NULL };
 
+/**************************************************
+ * Various helpers
+ **************************************************/
+
+static void bcm47xxsflash_cmd(struct bcm47xxsflash *b47s, u32 opcode)
+{
+       int i;
+
+       b47s->cc_write(b47s, BCMA_CC_FLASHCTL, BCMA_CC_FLASHCTL_START | opcode);
+       for (i = 0; i < 1000; i++) {
+               if (!(b47s->cc_read(b47s, BCMA_CC_FLASHCTL) &
+                     BCMA_CC_FLASHCTL_BUSY))
+                       return;
+               cpu_relax();
+       }
+       pr_err("Control command failed (timeout)!\n");
+}
+
+static int bcm47xxsflash_poll(struct bcm47xxsflash *b47s, int timeout)
+{
+       unsigned long deadline = jiffies + timeout;
+
+       do {
+               switch (b47s->type) {
+               case BCM47XXSFLASH_TYPE_ST:
+                       bcm47xxsflash_cmd(b47s, OPCODE_ST_RDSR);
+                       if (!(b47s->cc_read(b47s, BCMA_CC_FLASHDATA) &
+                             SR_ST_WIP))
+                               return 0;
+                       break;
+               case BCM47XXSFLASH_TYPE_ATMEL:
+                       bcm47xxsflash_cmd(b47s, OPCODE_AT_STATUS);
+                       if (b47s->cc_read(b47s, BCMA_CC_FLASHDATA) &
+                           SR_AT_READY)
+                               return 0;
+                       break;
+               }
+
+               cpu_relax();
+               udelay(1);
+       } while (!time_after_eq(jiffies, deadline));
+
+       pr_err("Timeout waiting for flash to be ready!\n");
+
+       return -EBUSY;
+}
+
+/**************************************************
+ * MTD ops
+ **************************************************/
+
 static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len,
                              size_t *retlen, u_char *buf)
 {
@@ -48,6 +100,17 @@ static void bcm47xxsflash_fill_mtd(struct bcm47xxsflash *b47s)
  * BCMA
  **************************************************/
 
+static int bcm47xxsflash_bcma_cc_read(struct bcm47xxsflash *b47s, u16 offset)
+{
+       return bcma_cc_read32(b47s->bcma_cc, offset);
+}
+
+static void bcm47xxsflash_bcma_cc_write(struct bcm47xxsflash *b47s, u16 offset,
+                                       u32 value)
+{
+       bcma_cc_write32(b47s->bcma_cc, offset, value);
+}
+
 static int bcm47xxsflash_bcma_probe(struct platform_device *pdev)
 {
        struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev);
@@ -62,6 +125,8 @@ static int bcm47xxsflash_bcma_probe(struct platform_device *pdev)
        sflash->priv = b47s;
 
        b47s->bcma_cc = container_of(sflash, struct bcma_drv_cc, sflash);
+       b47s->cc_read = bcm47xxsflash_bcma_cc_read;
+       b47s->cc_write = bcm47xxsflash_bcma_cc_write;
 
        switch (b47s->bcma_cc->capabilities & BCMA_CC_CAP_FLASHT) {
        case BCMA_CC_FLASHT_STSER:
@@ -84,6 +149,9 @@ static int bcm47xxsflash_bcma_probe(struct platform_device *pdev)
                goto err_dev_reg;
        }
 
+       if (bcm47xxsflash_poll(b47s, HZ / 10))
+               pr_warn("Serial flash busy\n");
+
        return 0;
 
 err_dev_reg:
index f22f8c46dfc059566ae8cd4fcf4c90f810a7fd2a..fe93daf4f4894a35f2d7b8a65363d1d163d09ffc 100644 (file)
@@ -60,6 +60,8 @@ enum bcm47xxsflash_type {
 
 struct bcm47xxsflash {
        struct bcma_drv_cc *bcma_cc;
+       int (*cc_read)(struct bcm47xxsflash *b47s, u16 offset);
+       void (*cc_write)(struct bcm47xxsflash *b47s, u16 offset, u32 value);
 
        enum bcm47xxsflash_type type;
 
index e081bfeaaf7da1941c9dc243856c3ab2ba9abde2..5cb4c04726b2e0eb58dd6452b293602f82fa1945 100644 (file)
@@ -6,6 +6,9 @@
  *
  * Licence: GPL
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/blkdev.h>
 #include <linux/mount.h>
 #include <linux/slab.h>
 
-#define ERROR(fmt, args...) printk(KERN_ERR "block2mtd: " fmt "\n" , ## args)
-#define INFO(fmt, args...) printk(KERN_INFO "block2mtd: " fmt "\n" , ## args)
-
-
 /* Info for the block device */
 struct block2mtd_dev {
        struct list_head list;
@@ -84,7 +83,7 @@ static int block2mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
        err = _block2mtd_erase(dev, from, len);
        mutex_unlock(&dev->write_mutex);
        if (err) {
-               ERROR("erase failed err = %d", err);
+               pr_err("erase failed err = %d\n", err);
                instr->state = MTD_ERASE_FAILED;
        } else
                instr->state = MTD_ERASE_DONE;
@@ -239,13 +238,13 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
 #endif
 
        if (IS_ERR(bdev)) {
-               ERROR("error: cannot open device %s", devname);
+               pr_err("error: cannot open device %s\n", devname);
                goto devinit_err;
        }
        dev->blkdev = bdev;
 
        if (MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) {
-               ERROR("attempting to use an MTD device as a block device");
+               pr_err("attempting to use an MTD device as a block device\n");
                goto devinit_err;
        }
 
@@ -277,9 +276,10 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
                goto devinit_err;
        }
        list_add(&dev->list, &blkmtd_device_list);
-       INFO("mtd%d: [%s] erase_size = %dKiB [%d]", dev->mtd.index,
-                       dev->mtd.name + strlen("block2mtd: "),
-                       dev->mtd.erasesize >> 10, dev->mtd.erasesize);
+       pr_info("mtd%d: [%s] erase_size = %dKiB [%d]\n",
+               dev->mtd.index,
+               dev->mtd.name + strlen("block2mtd: "),
+               dev->mtd.erasesize >> 10, dev->mtd.erasesize);
        return dev;
 
 devinit_err:
@@ -339,17 +339,11 @@ static inline void kill_final_newline(char *str)
 }
 
 
-#define parse_err(fmt, args...) do {   \
-       ERROR(fmt, ## args);            \
-       return 0;                       \
-} while (0)
-
 #ifndef MODULE
 static int block2mtd_init_called = 0;
 static char block2mtd_paramline[80 + 12]; /* 80 for device, 12 for erase size */
 #endif
 
-
 static int block2mtd_setup2(const char *val)
 {
        char buf[80 + 12]; /* 80 for device, 12 for erase size */
@@ -359,8 +353,10 @@ static int block2mtd_setup2(const char *val)
        size_t erase_size = PAGE_SIZE;
        int i, ret;
 
-       if (strnlen(val, sizeof(buf)) >= sizeof(buf))
-               parse_err("parameter too long");
+       if (strnlen(val, sizeof(buf)) >= sizeof(buf)) {
+               pr_err("parameter too long\n");
+               return 0;
+       }
 
        strcpy(str, val);
        kill_final_newline(str);
@@ -368,20 +364,27 @@ static int block2mtd_setup2(const char *val)
        for (i = 0; i < 2; i++)
                token[i] = strsep(&str, ",");
 
-       if (str)
-               parse_err("too many arguments");
+       if (str) {
+               pr_err("too many arguments\n");
+               return 0;
+       }
 
-       if (!token[0])
-               parse_err("no argument");
+       if (!token[0]) {
+               pr_err("no argument\n");
+               return 0;
+       }
 
        name = token[0];
-       if (strlen(name) + 1 > 80)
-               parse_err("device name too long");
+       if (strlen(name) + 1 > 80) {
+               pr_err("device name too long\n");
+               return 0;
+       }
 
        if (token[1]) {
                ret = parse_num(&erase_size, token[1]);
                if (ret) {
-                       parse_err("illegal erase size");
+                       pr_err("illegal erase size\n");
+                       return 0;
                }
        }
 
@@ -444,8 +447,9 @@ static void block2mtd_exit(void)
                struct block2mtd_dev *dev = list_entry(pos, typeof(*dev), list);
                block2mtd_sync(&dev->mtd);
                mtd_device_unregister(&dev->mtd);
-               INFO("mtd%d: [%s] removed", dev->mtd.index,
-                               dev->mtd.name + strlen("block2mtd: "));
+               pr_info("mtd%d: [%s] removed\n",
+                       dev->mtd.index,
+                       dev->mtd.name + strlen("block2mtd: "));
                list_del(&dev->list);
                block2mtd_free_device(dev);
        }
index dccef9fdc1f276269566bcc4ba03ae6e7a87111d..4f683d24de5ae92e29937eb4ee44c5cc9e1f3adf 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/of.h>
+#include <linux/sched.h>
 #include <linux/pm_runtime.h>
 #include <linux/platform_data/elm.h>
 
+#define ELM_SYSCONFIG                  0x010
 #define ELM_IRQSTATUS                  0x018
 #define ELM_IRQENABLE                  0x01c
 #define ELM_LOCATION_CONFIG            0x020
 #define ELM_PAGE_CTRL                  0x080
 #define ELM_SYNDROME_FRAGMENT_0                0x400
+#define ELM_SYNDROME_FRAGMENT_1                0x404
+#define ELM_SYNDROME_FRAGMENT_2                0x408
+#define ELM_SYNDROME_FRAGMENT_3                0x40c
+#define ELM_SYNDROME_FRAGMENT_4                0x410
+#define ELM_SYNDROME_FRAGMENT_5                0x414
 #define ELM_SYNDROME_FRAGMENT_6                0x418
 #define ELM_LOCATION_STATUS            0x800
 #define ELM_ERROR_LOCATION_0           0x880
 #define SYNDROME_FRAGMENT_REG_SIZE     0x40
 #define ERROR_LOCATION_SIZE            0x100
 
+struct elm_registers {
+       u32 elm_irqenable;
+       u32 elm_sysconfig;
+       u32 elm_location_config;
+       u32 elm_page_ctrl;
+       u32 elm_syndrome_fragment_6[ERROR_VECTOR_MAX];
+       u32 elm_syndrome_fragment_5[ERROR_VECTOR_MAX];
+       u32 elm_syndrome_fragment_4[ERROR_VECTOR_MAX];
+       u32 elm_syndrome_fragment_3[ERROR_VECTOR_MAX];
+       u32 elm_syndrome_fragment_2[ERROR_VECTOR_MAX];
+       u32 elm_syndrome_fragment_1[ERROR_VECTOR_MAX];
+       u32 elm_syndrome_fragment_0[ERROR_VECTOR_MAX];
+};
+
 struct elm_info {
        struct device *dev;
        void __iomem *elm_base;
        struct completion elm_completion;
        struct list_head list;
        enum bch_ecc bch_type;
+       struct elm_registers elm_regs;
 };
 
 static LIST_HEAD(elm_devices);
@@ -351,9 +373,9 @@ static int elm_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       info->elm_base = devm_request_and_ioremap(&pdev->dev, res);
-       if (!info->elm_base)
-               return -EADDRNOTAVAIL;
+       info->elm_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(info->elm_base))
+               return PTR_ERR(info->elm_base);
 
        ret = devm_request_irq(&pdev->dev, irq->start, elm_isr, 0,
                        pdev->name, info);
@@ -381,10 +403,103 @@ static int elm_remove(struct platform_device *pdev)
 {
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
-       platform_set_drvdata(pdev, NULL);
        return 0;
 }
 
+/**
+ * elm_context_save
+ * saves ELM configurations to preserve them across Hardware powered-down
+ */
+static int elm_context_save(struct elm_info *info)
+{
+       struct elm_registers *regs = &info->elm_regs;
+       enum bch_ecc bch_type = info->bch_type;
+       u32 offset = 0, i;
+
+       regs->elm_irqenable       = elm_read_reg(info, ELM_IRQENABLE);
+       regs->elm_sysconfig       = elm_read_reg(info, ELM_SYSCONFIG);
+       regs->elm_location_config = elm_read_reg(info, ELM_LOCATION_CONFIG);
+       regs->elm_page_ctrl       = elm_read_reg(info, ELM_PAGE_CTRL);
+       for (i = 0; i < ERROR_VECTOR_MAX; i++) {
+               offset = i * SYNDROME_FRAGMENT_REG_SIZE;
+               switch (bch_type) {
+               case BCH8_ECC:
+                       regs->elm_syndrome_fragment_3[i] = elm_read_reg(info,
+                                       ELM_SYNDROME_FRAGMENT_3 + offset);
+                       regs->elm_syndrome_fragment_2[i] = elm_read_reg(info,
+                                       ELM_SYNDROME_FRAGMENT_2 + offset);
+               case BCH4_ECC:
+                       regs->elm_syndrome_fragment_1[i] = elm_read_reg(info,
+                                       ELM_SYNDROME_FRAGMENT_1 + offset);
+                       regs->elm_syndrome_fragment_0[i] = elm_read_reg(info,
+                                       ELM_SYNDROME_FRAGMENT_0 + offset);
+               default:
+                       return -EINVAL;
+               }
+               /* ELM SYNDROME_VALID bit in SYNDROME_FRAGMENT_6[] needs
+                * to be saved for all BCH schemes*/
+               regs->elm_syndrome_fragment_6[i] = elm_read_reg(info,
+                                       ELM_SYNDROME_FRAGMENT_6 + offset);
+       }
+       return 0;
+}
+
+/**
+ * elm_context_restore
+ * writes configurations saved duing power-down back into ELM registers
+ */
+static int elm_context_restore(struct elm_info *info)
+{
+       struct elm_registers *regs = &info->elm_regs;
+       enum bch_ecc bch_type = info->bch_type;
+       u32 offset = 0, i;
+
+       elm_write_reg(info, ELM_IRQENABLE,       regs->elm_irqenable);
+       elm_write_reg(info, ELM_SYSCONFIG,       regs->elm_sysconfig);
+       elm_write_reg(info, ELM_LOCATION_CONFIG, regs->elm_location_config);
+       elm_write_reg(info, ELM_PAGE_CTRL,       regs->elm_page_ctrl);
+       for (i = 0; i < ERROR_VECTOR_MAX; i++) {
+               offset = i * SYNDROME_FRAGMENT_REG_SIZE;
+               switch (bch_type) {
+               case BCH8_ECC:
+                       elm_write_reg(info, ELM_SYNDROME_FRAGMENT_3 + offset,
+                                       regs->elm_syndrome_fragment_3[i]);
+                       elm_write_reg(info, ELM_SYNDROME_FRAGMENT_2 + offset,
+                                       regs->elm_syndrome_fragment_2[i]);
+               case BCH4_ECC:
+                       elm_write_reg(info, ELM_SYNDROME_FRAGMENT_1 + offset,
+                                       regs->elm_syndrome_fragment_1[i]);
+                       elm_write_reg(info, ELM_SYNDROME_FRAGMENT_0 + offset,
+                                       regs->elm_syndrome_fragment_0[i]);
+               default:
+                       return -EINVAL;
+               }
+               /* ELM_SYNDROME_VALID bit to be set in last to trigger FSM */
+               elm_write_reg(info, ELM_SYNDROME_FRAGMENT_6 + offset,
+                                       regs->elm_syndrome_fragment_6[i] &
+                                                        ELM_SYNDROME_VALID);
+       }
+       return 0;
+}
+
+static int elm_suspend(struct device *dev)
+{
+       struct elm_info *info = dev_get_drvdata(dev);
+       elm_context_save(info);
+       pm_runtime_put_sync(dev);
+       return 0;
+}
+
+static int elm_resume(struct device *dev)
+{
+       struct elm_info *info = dev_get_drvdata(dev);
+       pm_runtime_get_sync(dev);
+       elm_context_restore(info);
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(elm_pm_ops, elm_suspend, elm_resume);
+
 #ifdef CONFIG_OF
 static const struct of_device_id elm_of_match[] = {
        { .compatible = "ti,am3352-elm" },
@@ -398,6 +513,7 @@ static struct platform_driver elm_driver = {
                .name   = "elm",
                .owner  = THIS_MODULE,
                .of_match_table = of_match_ptr(elm_of_match),
+               .pm     = &elm_pm_ops,
        },
        .probe  = elm_probe,
        .remove = elm_remove,
index 2f3d2a5ff349a174dc0f473f07c67f477f0139c4..af972b2277e0a6fadf53569b00e39018b017880f 100644 (file)
 #define        OPCODE_SE               0xd8    /* Sector erase (usually 64KiB) */
 #define        OPCODE_RDID             0x9f    /* Read JEDEC ID */
 
+/* 4-byte address opcodes - used on Spansion and some Macronix flashes. */
+#define        OPCODE_NORM_READ_4B     0x13    /* Read data bytes (low frequency) */
+#define        OPCODE_FAST_READ_4B     0x0c    /* Read data bytes (high frequency) */
+#define        OPCODE_PP_4B            0x12    /* Page program (up to 256 bytes) */
+#define        OPCODE_SE_4B            0xdc    /* Sector erase (usually 64KiB) */
+
 /* Used for SST flashes only. */
 #define        OPCODE_BP               0x02    /* Byte program */
 #define        OPCODE_WRDI             0x04    /* Write disable */
 #define        OPCODE_AAI_WP           0xad    /* Auto address increment word program */
 
-/* Used for Macronix flashes only. */
+/* Used for Macronix and Winbond flashes. */
 #define        OPCODE_EN4B             0xb7    /* Enter 4-byte mode */
 #define        OPCODE_EX4B             0xe9    /* Exit 4-byte mode */
 
@@ -84,6 +90,8 @@ struct m25p {
        u16                     page_size;
        u16                     addr_width;
        u8                      erase_opcode;
+       u8                      read_opcode;
+       u8                      program_opcode;
        u8                      *command;
        bool                    fast_read;
 };
@@ -371,7 +379,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
         */
 
        /* Set up the write data buffer. */
-       opcode = flash->fast_read ? OPCODE_FAST_READ : OPCODE_NORM_READ;
+       opcode = flash->read_opcode;
        flash->command[0] = opcode;
        m25p_addr2cmd(flash, from, flash->command);
 
@@ -422,7 +430,7 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,
        write_enable(flash);
 
        /* Set up the opcode in the write buffer. */
-       flash->command[0] = OPCODE_PP;
+       flash->command[0] = flash->program_opcode;
        m25p_addr2cmd(flash, to, flash->command);
 
        page_offset = to & (flash->page_size - 1);
@@ -840,6 +848,7 @@ static const struct spi_device_id m25p_ids[] = {
        { "w25q32dw", INFO(0xef6016, 0, 64 * 1024,  64, SECT_4K) },
        { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
        { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
+       { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
        { "w25q80", INFO(0xef5014, 0, 64 * 1024,  16, SECT_4K) },
        { "w25q80bl", INFO(0xef4014, 0, 64 * 1024,  16, SECT_4K) },
        { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
@@ -972,7 +981,7 @@ static int m25p_probe(struct spi_device *spi)
 
        flash->spi = spi;
        mutex_init(&flash->lock);
-       dev_set_drvdata(&spi->dev, flash);
+       spi_set_drvdata(spi, flash);
 
        /*
         * Atmel, SST and Intel/Numonyx serial flash tend to power
@@ -1037,15 +1046,30 @@ static int m25p_probe(struct spi_device *spi)
        flash->fast_read = true;
 #endif
 
+       /* Default commands */
+       flash->read_opcode = flash->fast_read ?
+               OPCODE_FAST_READ :
+               OPCODE_NORM_READ;
+       flash->program_opcode = OPCODE_PP;
+
        if (info->addr_width)
                flash->addr_width = info->addr_width;
-       else {
+       else if (flash->mtd.size > 0x1000000) {
                /* enable 4-byte addressing if the device exceeds 16MiB */
-               if (flash->mtd.size > 0x1000000) {
-                       flash->addr_width = 4;
-                       set_4byte(flash, info->jedec_id, 1);
+               flash->addr_width = 4;
+               if (JEDEC_MFR(info->jedec_id) == CFI_MFR_AMD) {
+                       /* Dedicated 4-byte command set */
+                       flash->read_opcode = flash->fast_read ?
+                               OPCODE_FAST_READ_4B :
+                               OPCODE_NORM_READ_4B;
+                       flash->program_opcode = OPCODE_PP_4B;
+                       /* No small sector erase for 4-byte command set */
+                       flash->erase_opcode = OPCODE_SE_4B;
+                       flash->mtd.erasesize = info->sector_size;
                } else
-                       flash->addr_width = 3;
+                       set_4byte(flash, info->jedec_id, 1);
+       } else {
+               flash->addr_width = 3;
        }
 
        dev_info(&spi->dev, "%s (%lld Kbytes)\n", id->name,
@@ -1080,7 +1104,7 @@ static int m25p_probe(struct spi_device *spi)
 
 static int m25p_remove(struct spi_device *spi)
 {
-       struct m25p     *flash = dev_get_drvdata(&spi->dev);
+       struct m25p     *flash = spi_get_drvdata(spi);
        int             status;
 
        /* Clean up MTD stuff. */
index 28779b6dfcd98fc6c8b2ed5b49800d898fee7e81..4a4366437e1750caf8223a7d9641300b68b9157f 100644 (file)
@@ -661,7 +661,7 @@ static int add_dataflash_otp(struct spi_device *spi, char *name, int nr_pages,
        dev_info(&spi->dev, "%s (%lld KBytes) pagesize %d bytes%s\n",
                        name, (long long)((device->size + 1023) >> 10),
                        pagesize, otp_tag);
-       dev_set_drvdata(&spi->dev, priv);
+       spi_set_drvdata(spi, priv);
 
        ppdata.of_node = spi->dev.of_node;
        err = mtd_device_parse_register(device, NULL, &ppdata,
@@ -671,7 +671,7 @@ static int add_dataflash_otp(struct spi_device *spi, char *name, int nr_pages,
        if (!err)
                return 0;
 
-       dev_set_drvdata(&spi->dev, NULL);
+       spi_set_drvdata(spi, NULL);
        kfree(priv);
        return err;
 }
@@ -895,14 +895,14 @@ static int dataflash_probe(struct spi_device *spi)
 
 static int dataflash_remove(struct spi_device *spi)
 {
-       struct dataflash        *flash = dev_get_drvdata(&spi->dev);
+       struct dataflash        *flash = spi_get_drvdata(spi);
        int                     status;
 
        pr_debug("%s: remove\n", dev_name(&spi->dev));
 
        status = mtd_device_unregister(&flash->mtd);
        if (status == 0) {
-               dev_set_drvdata(&spi->dev, NULL);
+               spi_set_drvdata(spi, NULL);
                kfree(flash);
        }
        return status;
index 8a82b8bc21e185d7f62ca331d93f532470bb4399..092bb68b7742d2fa5d261f3245b35a0f74b6e910 100644 (file)
@@ -995,14 +995,12 @@ static int spear_smi_probe(struct platform_device *pdev)
                ret = spear_smi_setup_banks(pdev, i, pdata->np[i]);
                if (ret) {
                        dev_err(&dev->pdev->dev, "bank setup failed\n");
-                       goto err_bank_setup;
+                       goto err_irq;
                }
        }
 
        return 0;
 
-err_bank_setup:
-       platform_set_drvdata(pdev, NULL);
 err_irq:
        clk_disable_unprepare(dev->clk);
 err:
@@ -1040,12 +1038,11 @@ static int spear_smi_remove(struct platform_device *pdev)
        }
 
        clk_disable_unprepare(dev->clk);
-       platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int spear_smi_suspend(struct device *dev)
 {
        struct spear_smi *sdev = dev_get_drvdata(dev);
@@ -1068,9 +1065,9 @@ static int spear_smi_resume(struct device *dev)
                spear_smi_hw_init(sdev);
        return ret;
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(spear_smi_pm_ops, spear_smi_suspend, spear_smi_resume);
-#endif
 
 #ifdef CONFIG_OF
 static const struct of_device_id spear_smi_id_table[] = {
@@ -1086,9 +1083,7 @@ static struct platform_driver spear_smi_driver = {
                .bus = &platform_bus_type,
                .owner = THIS_MODULE,
                .of_match_table = of_match_ptr(spear_smi_id_table),
-#ifdef CONFIG_PM
                .pm = &spear_smi_pm_ops,
-#endif
        },
        .probe = spear_smi_probe,
        .remove = spear_smi_remove,
index 8091b016369430c0975835be79d3a6c381363846..38b59790f4b7925d002df6a435836724ce3b3d3b 100644 (file)
@@ -370,7 +370,7 @@ static int sst25l_probe(struct spi_device *spi)
 
        flash->spi = spi;
        mutex_init(&flash->lock);
-       dev_set_drvdata(&spi->dev, flash);
+       spi_set_drvdata(spi, flash);
 
        data = spi->dev.platform_data;
        if (data && data->name)
@@ -404,7 +404,7 @@ static int sst25l_probe(struct spi_device *spi)
                                        data ? data->nr_parts : 0);
        if (ret) {
                kfree(flash);
-               dev_set_drvdata(&spi->dev, NULL);
+               spi_set_drvdata(spi, NULL);
                return -ENODEV;
        }
 
@@ -413,7 +413,7 @@ static int sst25l_probe(struct spi_device *spi)
 
 static int sst25l_remove(struct spi_device *spi)
 {
-       struct sst25l_flash *flash = dev_get_drvdata(&spi->dev);
+       struct sst25l_flash *flash = spi_get_drvdata(spi);
        int ret;
 
        ret = mtd_device_unregister(&flash->mtd);
index 52b3410a105c943d47ce3b9ea873781948d028a4..09c542b3a7f03a8d83bfea0dc6b764e07847acb4 100644 (file)
@@ -155,8 +155,6 @@ static int ixp4xx_flash_remove(struct platform_device *dev)
        struct flash_platform_data *plat = dev->dev.platform_data;
        struct ixp4xx_flash_info *info = platform_get_drvdata(dev);
 
-       platform_set_drvdata(dev, NULL);
-
        if(!info)
                return 0;
 
index ab0fead56b8383f1a57579c0f9f3dfe0a5211d32..675ccb8c3cd951aaecb243d65c31f7f3a379948d 100644 (file)
@@ -102,7 +102,6 @@ static int latch_addr_flash_remove(struct platform_device *dev)
        info = platform_get_drvdata(dev);
        if (info == NULL)
                return 0;
-       platform_set_drvdata(dev, NULL);
 
        latch_addr_data = dev->dev.platform_data;
 
index e7a592c8c76591e02257e5c39b891aefbf43d9d3..9eb7ead97f3484cf0a43a0d5e30d71e80107640a 100644 (file)
@@ -40,7 +40,6 @@ static int physmap_flash_remove(struct platform_device *dev)
        info = platform_get_drvdata(dev);
        if (info == NULL)
                return 0;
-       platform_set_drvdata(dev, NULL);
 
        physmap_data = dev->dev.platform_data;
 
index 71fdda29594b7c3595d786c1572012d09b4df8af..b0b85ebaef0567a8280ef98401b6b5d502795999 100644 (file)
@@ -84,8 +84,6 @@ static int platram_remove(struct platform_device *pdev)
 {
        struct platram_info *info = to_platram_info(pdev);
 
-       platform_set_drvdata(pdev, NULL);
-
        dev_dbg(&pdev->dev, "removing device\n");
 
        if (info == NULL)
index acb1dbcf7ce58a438ed7ff9a1df9aecb2b57478f..22c55cbf31686d8af1ef5ff386affda734fd3737 100644 (file)
@@ -107,8 +107,6 @@ static int pxa2xx_flash_remove(struct platform_device *dev)
 {
        struct pxa2xx_flash_info *info = platform_get_drvdata(dev);
 
-       platform_set_drvdata(dev, NULL);
-
        mtd_device_unregister(info->mtd);
 
        map_destroy(info->mtd);
index ac02fbffd6df940f70e3802895811f5916843541..ab4ec55440256b69b3d07918f2cb14ba81621cfb 100644 (file)
@@ -34,7 +34,6 @@ static int rbtx4939_flash_remove(struct platform_device *dev)
        info = platform_get_drvdata(dev);
        if (!info)
                return 0;
-       platform_set_drvdata(dev, NULL);
 
        if (info->mtd) {
                struct rbtx4939_flash_data *pdata = dev->dev.platform_data;
index 29e3dcaa1d90413b15df9e30c04373d897c2f6c6..9e70f8e714b1113d08eb4b99b2fd99a6ecd30f10 100644 (file)
@@ -279,7 +279,6 @@ static int __exit sa1100_mtd_remove(struct platform_device *pdev)
        struct sa_info *info = platform_get_drvdata(pdev);
        struct flash_platform_data *plat = pdev->dev.platform_data;
 
-       platform_set_drvdata(pdev, NULL);
        sa1100_destroy(info, plat);
 
        return 0;
index 50543f1662150ade806e9967190c60426a9ab029..5ef8f5e848c3306eec3e7a7a887455aef837c4ad 100644 (file)
@@ -75,7 +75,7 @@ config MTD_NAND_DENALI_SCRATCH_REG_ADDR
 
 config MTD_NAND_GPIO
        tristate "GPIO NAND Flash driver"
-       depends on GPIOLIB && ARM
+       depends on GPIOLIB
        help
          This enables a GPIO based NAND flash driver.
 
index f1d71cdc8aac97f827f7fac7d9a136342f0a6a22..8611eb4b45fca90e73d84db280b55301640fcd93 100644 (file)
@@ -258,7 +258,6 @@ static int ams_delta_init(struct platform_device *pdev)
  out_mtd:
        gpio_free_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
 out_gpio:
-       platform_set_drvdata(pdev, NULL);
        gpio_free(AMS_DELTA_GPIO_PIN_NAND_RB);
        iounmap(io_base);
 out_free:
index 2d23d2929438053a255ccad183e111ac7fe633ba..7e50ed89e18a75f4551c5a3262f174d65f026670 100644 (file)
@@ -43,8 +43,6 @@
 #include <linux/platform_data/atmel.h>
 #include <linux/pinctrl/consumer.h>
 
-#include <mach/cpu.h>
-
 static int use_dma = 1;
 module_param(use_dma, int, 0);
 
@@ -128,11 +126,6 @@ struct atmel_nand_host {
 
 static struct nand_ecclayout atmel_pmecc_oobinfo;
 
-static int cpu_has_dma(void)
-{
-       return cpu_is_at91sam9rl() || cpu_is_at91sam9g45();
-}
-
 /*
  * Enable NAND.
  */
@@ -1174,10 +1167,9 @@ static int atmel_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
         * Workaround: Reset the parity registers before reading the
         * actual data.
         */
-       if (cpu_is_at32ap7000()) {
-               struct atmel_nand_host *host = chip->priv;
+       struct atmel_nand_host *host = chip->priv;
+       if (host->board.need_reset_workaround)
                ecc_writel(host->ecc, CR, ATMEL_ECC_RST);
-       }
 
        /* read the page */
        chip->read_buf(mtd, p, eccsize);
@@ -1298,11 +1290,11 @@ static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat,
  */
 static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)
 {
-       if (cpu_is_at32ap7000()) {
-               struct nand_chip *nand_chip = mtd->priv;
-               struct atmel_nand_host *host = nand_chip->priv;
+       struct nand_chip *nand_chip = mtd->priv;
+       struct atmel_nand_host *host = nand_chip->priv;
+
+       if (host->board.need_reset_workaround)
                ecc_writel(host->ecc, CR, ATMEL_ECC_RST);
-       }
 }
 
 #if defined(CONFIG_OF)
@@ -1337,6 +1329,8 @@ static int atmel_of_init_port(struct atmel_nand_host *host,
 
        board->on_flash_bbt = of_get_nand_on_flash_bbt(np);
 
+       board->has_dma = of_property_read_bool(np, "atmel,nand-has-dma");
+
        if (of_get_nand_bus_width(np) == 16)
                board->bus_width_16 = 1;
 
@@ -1601,7 +1595,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
                nand_chip->bbt_options |= NAND_BBT_USE_FLASH;
        }
 
-       if (!cpu_has_dma())
+       if (!host->board.has_dma)
                use_dma = 0;
 
        if (use_dma) {
@@ -1665,7 +1659,6 @@ err_hw_ecc:
 err_scan_ident:
 err_no_card:
        atmel_nand_disable(host);
-       platform_set_drvdata(pdev, NULL);
        if (host->dma_chan)
                dma_release_channel(host->dma_chan);
 err_ecc_ioremap:
index 776df3694f755865f88b7e0a499cac533dd04142..809a63c53fc57494baa2ce7ac732b747c3f8d17c 100644 (file)
@@ -671,8 +671,6 @@ static int bf5xx_nand_remove(struct platform_device *pdev)
 {
        struct bf5xx_nand_info *info = to_nand_info(pdev);
 
-       platform_set_drvdata(pdev, NULL);
-
        /* first thing we need to do is release all our mtds
         * and their partitions, then go through freeing the
         * resources used
@@ -832,7 +830,6 @@ static int bf5xx_nand_probe(struct platform_device *pdev)
 out_err_nand_scan:
        bf5xx_nand_dma_remove(info);
 out_err_hw_init:
-       platform_set_drvdata(pdev, NULL);
        kfree(info);
 out_err_kzalloc:
        peripheral_free_list(bfin_nfc_pin_req);
index c3e15a55817349eb4ed2e1c86009b042c38e2405..999ad9cb29012ff6d1d96db1fa33c134d84a133d 100644 (file)
@@ -623,11 +623,14 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
                goto err_nomem;
        }
 
-       vaddr = devm_request_and_ioremap(&pdev->dev, res1);
-       base = devm_request_and_ioremap(&pdev->dev, res2);
-       if (!vaddr || !base) {
-               dev_err(&pdev->dev, "ioremap failed\n");
-               ret = -EADDRNOTAVAIL;
+       vaddr = devm_ioremap_resource(&pdev->dev, res1);
+       if (IS_ERR(vaddr)) {
+               ret = PTR_ERR(vaddr);
+               goto err_ioremap;
+       }
+       base = devm_ioremap_resource(&pdev->dev, res2);
+       if (IS_ERR(base)) {
+               ret = PTR_ERR(base);
                goto err_ioremap;
        }
 
index fa25e7a08134d1cc6bf3d0a68eb15da42a44524b..dc86d4a3c3ddbbee5ef8e84486d31024cae28fba 100644 (file)
@@ -1368,7 +1368,6 @@ static int __init probe_docg4(struct platform_device *pdev)
                struct nand_chip *nand = mtd->priv;
                struct docg4_priv *doc = nand->priv;
                nand_release(mtd); /* deletes partitions and mtd devices */
-               platform_set_drvdata(pdev, NULL);
                free_bch(doc->bch);
                kfree(mtd);
        }
@@ -1380,7 +1379,6 @@ static int __exit cleanup_docg4(struct platform_device *pdev)
 {
        struct docg4_priv *doc = platform_get_drvdata(pdev);
        nand_release(doc->mtd);
-       platform_set_drvdata(pdev, NULL);
        free_bch(doc->bch);
        kfree(doc->mtd);
        iounmap(doc->virtadr);
index f1f7f12ab50184b3bc233e360a899b998ea8c724..317a771f1587c94f3fd57c45c8e140deeb08b982 100644 (file)
@@ -823,7 +823,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
 
        /* set up nand options */
        chip->bbt_options = NAND_BBT_USE_FLASH;
-
+       chip->options = NAND_NO_SUBPAGE_WRITE;
 
        if (ioread32be(&ifc->cspr_cs[priv->bank].cspr) & CSPR_PORT_SIZE_16) {
                chip->read_byte = fsl_ifc_read_byte16;
@@ -908,7 +908,6 @@ static int fsl_ifc_chip_remove(struct fsl_ifc_mtd *priv)
 
        ifc_nand_ctrl->chips[priv->bank] = NULL;
        dev_set_drvdata(priv->dev, NULL);
-       kfree(priv);
 
        return 0;
 }
index 911e2433fe304b107f1ad8b585621d653578e302..2a3b1b90a5620ab4f8cca50501c3c0bb325e3945 100644 (file)
@@ -889,6 +889,24 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
        if (of_get_property(np, "nand-skip-bbtscan", NULL))
                pdata->options = NAND_SKIP_BBTSCAN;
 
+       pdata->nand_timings = devm_kzalloc(&pdev->dev,
+                               sizeof(*pdata->nand_timings), GFP_KERNEL);
+       if (!pdata->nand_timings) {
+               dev_err(&pdev->dev, "no memory for nand_timing\n");
+               return -ENOMEM;
+       }
+       of_property_read_u8_array(np, "timings", (u8 *)pdata->nand_timings,
+                                               sizeof(*pdata->nand_timings));
+
+       /* Set default NAND bank to 0 */
+       pdata->bank = 0;
+       if (!of_property_read_u32(np, "bank", &val)) {
+               if (val > 3) {
+                       dev_err(&pdev->dev, "invalid bank %u\n", val);
+                       return -EINVAL;
+               }
+               pdata->bank = val;
+       }
        return 0;
 }
 #else
@@ -1174,8 +1192,6 @@ static int fsmc_nand_remove(struct platform_device *pdev)
 {
        struct fsmc_nand_data *host = platform_get_drvdata(pdev);
 
-       platform_set_drvdata(pdev, NULL);
-
        if (host) {
                nand_release(&host->mtd);
 
@@ -1190,7 +1206,7 @@ static int fsmc_nand_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int fsmc_nand_suspend(struct device *dev)
 {
        struct fsmc_nand_data *host = dev_get_drvdata(dev);
@@ -1210,9 +1226,9 @@ static int fsmc_nand_resume(struct device *dev)
        }
        return 0;
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(fsmc_nand_pm_ops, fsmc_nand_suspend, fsmc_nand_resume);
-#endif
 
 #ifdef CONFIG_OF
 static const struct of_device_id fsmc_nand_id_table[] = {
@@ -1229,9 +1245,7 @@ static struct platform_driver fsmc_nand_driver = {
                .owner = THIS_MODULE,
                .name = "fsmc-nand",
                .of_match_table = of_match_ptr(fsmc_nand_id_table),
-#ifdef CONFIG_PM
                .pm = &fsmc_nand_pm_ops,
-#endif
        },
 };
 
index 89065dd83d64d7ad64a6d83ca318f36ae65ec6cf..800a1cc5015d686d191f2cea58eb067a2a2a640e 100644 (file)
@@ -17,6 +17,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/err.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/module.h>
@@ -86,59 +87,11 @@ static void gpio_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
        gpio_nand_dosync(gpiomtd);
 }
 
-static void gpio_nand_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
-{
-       struct nand_chip *this = mtd->priv;
-
-       iowrite8_rep(this->IO_ADDR_W, buf, len);
-}
-
-static void gpio_nand_readbuf(struct mtd_info *mtd, u_char *buf, int len)
-{
-       struct nand_chip *this = mtd->priv;
-
-       ioread8_rep(this->IO_ADDR_R, buf, len);
-}
-
-static void gpio_nand_writebuf16(struct mtd_info *mtd, const u_char *buf,
-                                int len)
-{
-       struct nand_chip *this = mtd->priv;
-
-       if (IS_ALIGNED((unsigned long)buf, 2)) {
-               iowrite16_rep(this->IO_ADDR_W, buf, len>>1);
-       } else {
-               int i;
-               unsigned short *ptr = (unsigned short *)buf;
-
-               for (i = 0; i < len; i += 2, ptr++)
-                       writew(*ptr, this->IO_ADDR_W);
-       }
-}
-
-static void gpio_nand_readbuf16(struct mtd_info *mtd, u_char *buf, int len)
-{
-       struct nand_chip *this = mtd->priv;
-
-       if (IS_ALIGNED((unsigned long)buf, 2)) {
-               ioread16_rep(this->IO_ADDR_R, buf, len>>1);
-       } else {
-               int i;
-               unsigned short *ptr = (unsigned short *)buf;
-
-               for (i = 0; i < len; i += 2, ptr++)
-                       *ptr = readw(this->IO_ADDR_R);
-       }
-}
-
 static int gpio_nand_devready(struct mtd_info *mtd)
 {
        struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd);
 
-       if (gpio_is_valid(gpiomtd->plat.gpio_rdy))
-               return gpio_get_value(gpiomtd->plat.gpio_rdy);
-
-       return 1;
+       return gpio_get_value(gpiomtd->plat.gpio_rdy);
 }
 
 #ifdef CONFIG_OF
@@ -153,6 +106,9 @@ static int gpio_nand_get_config_of(const struct device *dev,
 {
        u32 val;
 
+       if (!dev->of_node)
+               return -ENODEV;
+
        if (!of_property_read_u32(dev->of_node, "bank-width", &val)) {
                if (val == 2) {
                        plat->options |= NAND_BUSWIDTH_16;
@@ -230,145 +186,100 @@ gpio_nand_get_io_sync(struct platform_device *pdev)
        return platform_get_resource(pdev, IORESOURCE_MEM, 1);
 }
 
-static int gpio_nand_remove(struct platform_device *dev)
+static int gpio_nand_remove(struct platform_device *pdev)
 {
-       struct gpiomtd *gpiomtd = platform_get_drvdata(dev);
-       struct resource *res;
+       struct gpiomtd *gpiomtd = platform_get_drvdata(pdev);
 
        nand_release(&gpiomtd->mtd_info);
 
-       res = gpio_nand_get_io_sync(dev);
-       iounmap(gpiomtd->io_sync);
-       if (res)
-               release_mem_region(res->start, resource_size(res));
-
-       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
-       iounmap(gpiomtd->nand_chip.IO_ADDR_R);
-       release_mem_region(res->start, resource_size(res));
-
        if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
                gpio_set_value(gpiomtd->plat.gpio_nwp, 0);
        gpio_set_value(gpiomtd->plat.gpio_nce, 1);
 
-       gpio_free(gpiomtd->plat.gpio_cle);
-       gpio_free(gpiomtd->plat.gpio_ale);
-       gpio_free(gpiomtd->plat.gpio_nce);
-       if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
-               gpio_free(gpiomtd->plat.gpio_nwp);
-       if (gpio_is_valid(gpiomtd->plat.gpio_rdy))
-               gpio_free(gpiomtd->plat.gpio_rdy);
-
        return 0;
 }
 
-static void __iomem *request_and_remap(struct resource *res, size_t size,
-                                       const char *name, int *err)
-{
-       void __iomem *ptr;
-
-       if (!request_mem_region(res->start, resource_size(res), name)) {
-               *err = -EBUSY;
-               return NULL;
-       }
-
-       ptr = ioremap(res->start, size);
-       if (!ptr) {
-               release_mem_region(res->start, resource_size(res));
-               *err = -ENOMEM;
-       }
-       return ptr;
-}
-
-static int gpio_nand_probe(struct platform_device *dev)
+static int gpio_nand_probe(struct platform_device *pdev)
 {
        struct gpiomtd *gpiomtd;
-       struct nand_chip *this;
-       struct resource *res0, *res1;
+       struct nand_chip *chip;
+       struct resource *res;
        struct mtd_part_parser_data ppdata = {};
        int ret = 0;
 
-       if (!dev->dev.of_node && !dev->dev.platform_data)
-               return -EINVAL;
-
-       res0 = platform_get_resource(dev, IORESOURCE_MEM, 0);
-       if (!res0)
+       if (!pdev->dev.of_node && !pdev->dev.platform_data)
                return -EINVAL;
 
-       gpiomtd = devm_kzalloc(&dev->dev, sizeof(*gpiomtd), GFP_KERNEL);
-       if (gpiomtd == NULL) {
-               dev_err(&dev->dev, "failed to create NAND MTD\n");
+       gpiomtd = devm_kzalloc(&pdev->dev, sizeof(*gpiomtd), GFP_KERNEL);
+       if (!gpiomtd) {
+               dev_err(&pdev->dev, "failed to create NAND MTD\n");
                return -ENOMEM;
        }
 
-       this = &gpiomtd->nand_chip;
-       this->IO_ADDR_R = request_and_remap(res0, 2, "NAND", &ret);
-       if (!this->IO_ADDR_R) {
-               dev_err(&dev->dev, "unable to map NAND\n");
-               goto err_map;
-       }
+       chip = &gpiomtd->nand_chip;
 
-       res1 = gpio_nand_get_io_sync(dev);
-       if (res1) {
-               gpiomtd->io_sync = request_and_remap(res1, 4, "NAND sync", &ret);
-               if (!gpiomtd->io_sync) {
-                       dev_err(&dev->dev, "unable to map sync NAND\n");
-                       goto err_sync;
-               }
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(chip->IO_ADDR_R))
+               return PTR_ERR(chip->IO_ADDR_R);
+
+       res = gpio_nand_get_io_sync(pdev);
+       if (res) {
+               gpiomtd->io_sync = devm_ioremap_resource(&pdev->dev, res);
+               if (IS_ERR(gpiomtd->io_sync))
+                       return PTR_ERR(gpiomtd->io_sync);
        }
 
-       ret = gpio_nand_get_config(&dev->dev, &gpiomtd->plat);
+       ret = gpio_nand_get_config(&pdev->dev, &gpiomtd->plat);
        if (ret)
-               goto err_nce;
+               return ret;
 
-       ret = gpio_request(gpiomtd->plat.gpio_nce, "NAND NCE");
+       ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_nce, "NAND NCE");
        if (ret)
-               goto err_nce;
+               return ret;
        gpio_direction_output(gpiomtd->plat.gpio_nce, 1);
+
        if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) {
-               ret = gpio_request(gpiomtd->plat.gpio_nwp, "NAND NWP");
+               ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_nwp,
+                                       "NAND NWP");
                if (ret)
-                       goto err_nwp;
-               gpio_direction_output(gpiomtd->plat.gpio_nwp, 1);
+                       return ret;
        }
-       ret = gpio_request(gpiomtd->plat.gpio_ale, "NAND ALE");
+
+       ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_ale, "NAND ALE");
        if (ret)
-               goto err_ale;
+               return ret;
        gpio_direction_output(gpiomtd->plat.gpio_ale, 0);
-       ret = gpio_request(gpiomtd->plat.gpio_cle, "NAND CLE");
+
+       ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_cle, "NAND CLE");
        if (ret)
-               goto err_cle;
+               return ret;
        gpio_direction_output(gpiomtd->plat.gpio_cle, 0);
+
        if (gpio_is_valid(gpiomtd->plat.gpio_rdy)) {
-               ret = gpio_request(gpiomtd->plat.gpio_rdy, "NAND RDY");
+               ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_rdy,
+                                       "NAND RDY");
                if (ret)
-                       goto err_rdy;
+                       return ret;
                gpio_direction_input(gpiomtd->plat.gpio_rdy);
+               chip->dev_ready = gpio_nand_devready;
        }
 
+       chip->IO_ADDR_W         = chip->IO_ADDR_R;
+       chip->ecc.mode          = NAND_ECC_SOFT;
+       chip->options           = gpiomtd->plat.options;
+       chip->chip_delay        = gpiomtd->plat.chip_delay;
+       chip->cmd_ctrl          = gpio_nand_cmd_ctrl;
 
-       this->IO_ADDR_W  = this->IO_ADDR_R;
-       this->ecc.mode   = NAND_ECC_SOFT;
-       this->options    = gpiomtd->plat.options;
-       this->chip_delay = gpiomtd->plat.chip_delay;
-
-       /* install our routines */
-       this->cmd_ctrl   = gpio_nand_cmd_ctrl;
-       this->dev_ready  = gpio_nand_devready;
+       gpiomtd->mtd_info.priv  = chip;
+       gpiomtd->mtd_info.owner = THIS_MODULE;
 
-       if (this->options & NAND_BUSWIDTH_16) {
-               this->read_buf   = gpio_nand_readbuf16;
-               this->write_buf  = gpio_nand_writebuf16;
-       } else {
-               this->read_buf   = gpio_nand_readbuf;
-               this->write_buf  = gpio_nand_writebuf;
-       }
+       platform_set_drvdata(pdev, gpiomtd);
 
-       /* set the mtd private data for the nand driver */
-       gpiomtd->mtd_info.priv = this;
-       gpiomtd->mtd_info.owner = THIS_MODULE;
+       if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
+               gpio_direction_output(gpiomtd->plat.gpio_nwp, 1);
 
        if (nand_scan(&gpiomtd->mtd_info, 1)) {
-               dev_err(&dev->dev, "no nand chips found?\n");
                ret = -ENXIO;
                goto err_wp;
        }
@@ -377,38 +288,17 @@ static int gpio_nand_probe(struct platform_device *dev)
                gpiomtd->plat.adjust_parts(&gpiomtd->plat,
                                           gpiomtd->mtd_info.size);
 
-       ppdata.of_node = dev->dev.of_node;
+       ppdata.of_node = pdev->dev.of_node;
        ret = mtd_device_parse_register(&gpiomtd->mtd_info, NULL, &ppdata,
                                        gpiomtd->plat.parts,
                                        gpiomtd->plat.num_parts);
-       if (ret)
-               goto err_wp;
-       platform_set_drvdata(dev, gpiomtd);
-
-       return 0;
+       if (!ret)
+               return 0;
 
 err_wp:
        if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
                gpio_set_value(gpiomtd->plat.gpio_nwp, 0);
-       if (gpio_is_valid(gpiomtd->plat.gpio_rdy))
-               gpio_free(gpiomtd->plat.gpio_rdy);
-err_rdy:
-       gpio_free(gpiomtd->plat.gpio_cle);
-err_cle:
-       gpio_free(gpiomtd->plat.gpio_ale);
-err_ale:
-       if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
-               gpio_free(gpiomtd->plat.gpio_nwp);
-err_nwp:
-       gpio_free(gpiomtd->plat.gpio_nce);
-err_nce:
-       iounmap(gpiomtd->io_sync);
-       if (res1)
-               release_mem_region(res1->start, resource_size(res1));
-err_sync:
-       iounmap(gpiomtd->nand_chip.IO_ADDR_R);
-       release_mem_region(res0->start, resource_size(res0));
-err_map:
+
        return ret;
 }
 
@@ -417,6 +307,7 @@ static struct platform_driver gpio_nand_driver = {
        .remove         = gpio_nand_remove,
        .driver         = {
                .name   = "gpio-nand",
+               .owner  = THIS_MODULE,
                .of_match_table = of_match_ptr(gpio_nand_id_table),
        },
 };
index 25ecfa1822a8fc75cf485b41c51602ad04a0489b..b741a6c695d7f58f18d1cf1d4eae5bd235b53629 100644 (file)
@@ -473,12 +473,14 @@ static int gpmi_get_clks(struct gpmi_nand_data *this)
        struct resources *r = &this->resources;
        char **extra_clks = NULL;
        struct clk *clk;
-       int i;
+       int err, i;
 
        /* The main clock is stored in the first. */
        r->clock[0] = clk_get(this->dev, "gpmi_io");
-       if (IS_ERR(r->clock[0]))
+       if (IS_ERR(r->clock[0])) {
+               err = PTR_ERR(r->clock[0]);
                goto err_clock;
+       }
 
        /* Get extra clocks */
        if (GPMI_IS_MX6Q(this))
@@ -491,8 +493,10 @@ static int gpmi_get_clks(struct gpmi_nand_data *this)
                        break;
 
                clk = clk_get(this->dev, extra_clks[i - 1]);
-               if (IS_ERR(clk))
+               if (IS_ERR(clk)) {
+                       err = PTR_ERR(clk);
                        goto err_clock;
+               }
 
                r->clock[i] = clk;
        }
@@ -511,7 +515,7 @@ static int gpmi_get_clks(struct gpmi_nand_data *this)
 err_clock:
        dev_dbg(this->dev, "failed in finding the clocks.\n");
        gpmi_put_clks(this);
-       return -ENOMEM;
+       return err;
 }
 
 static int acquire_resources(struct gpmi_nand_data *this)
@@ -1633,7 +1637,6 @@ static int gpmi_nand_probe(struct platform_device *pdev)
 exit_nfc_init:
        release_resources(this);
 exit_acquire_resources:
-       platform_set_drvdata(pdev, NULL);
        dev_err(this->dev, "driver registration failed: %d\n", ret);
        kfree(this);
 
@@ -1646,7 +1649,6 @@ static int gpmi_nand_remove(struct platform_device *pdev)
 
        gpmi_nfc_exit(this);
        release_resources(this);
-       platform_set_drvdata(pdev, NULL);
        kfree(this);
        return 0;
 }
index b76460eeaf2253f7db3e69404ff4afb51298f84b..698a4d1c1f93aabc4f5c34d41fb4f4861fcfd437 100644 (file)
@@ -538,7 +538,6 @@ err_unclaim_banks:
 err_gpio_busy:
        if (pdata && gpio_is_valid(pdata->busy_gpio))
                gpio_free(pdata->busy_gpio);
-       platform_set_drvdata(pdev, NULL);
 err_iounmap_mmio:
        jz_nand_iounmap_resource(nand->mem, nand->base);
 err_free:
@@ -570,7 +569,6 @@ static int jz_nand_remove(struct platform_device *pdev)
 
        jz_nand_iounmap_resource(nand->mem, nand->base);
 
-       platform_set_drvdata(pdev, NULL);
        kfree(nand);
 
        return 0;
index fd1df5e13ae44d77207d19fb492064166bf46525..74a469b83c0d2c04d931b904f00ab402ed092674 100644 (file)
@@ -828,7 +828,6 @@ err_exit3:
 err_exit2:
        clk_disable(host->clk);
        clk_put(host->clk);
-       platform_set_drvdata(pdev, NULL);
 err_exit1:
        lpc32xx_wp_enable(host);
        gpio_free(host->ncfg->wp_gpio);
@@ -851,7 +850,6 @@ static int lpc32xx_nand_remove(struct platform_device *pdev)
 
        clk_disable(host->clk);
        clk_put(host->clk);
-       platform_set_drvdata(pdev, NULL);
 
        lpc32xx_wp_enable(host);
        gpio_free(host->ncfg->wp_gpio);
index be94ed5abefb74aebde118529cf5eca82abe876e..a66f33f259741f21cd45a44bfc04b93ab939eb36 100644 (file)
@@ -936,7 +936,6 @@ err_exit3:
 err_exit2:
        clk_disable(host->clk);
        clk_put(host->clk);
-       platform_set_drvdata(pdev, NULL);
 err_exit1:
        lpc32xx_wp_enable(host);
        gpio_free(host->ncfg->wp_gpio);
@@ -963,7 +962,6 @@ static int lpc32xx_nand_remove(struct platform_device *pdev)
 
        clk_disable(host->clk);
        clk_put(host->clk);
-       platform_set_drvdata(pdev, NULL);
        lpc32xx_wp_enable(host);
        gpio_free(host->ncfg->wp_gpio);
 
index 07e5784e5cd3f365e459a651368afdd6b2ab6f1b..18855ad7babb5b3028e920ba3a08eab6255fb28a 100644 (file)
@@ -1578,8 +1578,6 @@ static int mxcnd_remove(struct platform_device *pdev)
 {
        struct mxc_nand_host *host = platform_get_drvdata(pdev);
 
-       platform_set_drvdata(pdev, NULL);
-
        nand_release(&host->mtd);
 
        return 0;
index dfcd0a565c5b3e8f66d9b24077ae3701f132ee36..1cbacffb51063d79d084d7ab9d12547bc8c57905 100644 (file)
@@ -211,11 +211,9 @@ static void nand_select_chip(struct mtd_info *mtd, int chipnr)
  */
 static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 {
-       int i;
        struct nand_chip *chip = mtd->priv;
 
-       for (i = 0; i < len; i++)
-               writeb(buf[i], chip->IO_ADDR_W);
+       iowrite8_rep(chip->IO_ADDR_W, buf, len);
 }
 
 /**
@@ -228,11 +226,9 @@ static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
  */
 static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 {
-       int i;
        struct nand_chip *chip = mtd->priv;
 
-       for (i = 0; i < len; i++)
-               buf[i] = readb(chip->IO_ADDR_R);
+       ioread8_rep(chip->IO_ADDR_R, buf, len);
 }
 
 /**
@@ -245,14 +241,10 @@ static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
  */
 static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
 {
-       int i;
        struct nand_chip *chip = mtd->priv;
        u16 *p = (u16 *) buf;
-       len >>= 1;
-
-       for (i = 0; i < len; i++)
-               writew(p[i], chip->IO_ADDR_W);
 
+       iowrite16_rep(chip->IO_ADDR_W, p, len >> 1);
 }
 
 /**
@@ -265,13 +257,10 @@ static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
  */
 static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
 {
-       int i;
        struct nand_chip *chip = mtd->priv;
        u16 *p = (u16 *) buf;
-       len >>= 1;
 
-       for (i = 0; i < len; i++)
-               p[i] = readw(chip->IO_ADDR_R);
+       ioread16_rep(chip->IO_ADDR_R, p, len >> 1);
 }
 
 /**
@@ -2720,7 +2709,9 @@ static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,
 {
        int status;
 
-       if (!chip->onfi_version)
+       if (!chip->onfi_version ||
+           !(le16_to_cpu(chip->onfi_params.opt_cmd)
+             & ONFI_OPT_CMD_SET_GET_FEATURES))
                return -EINVAL;
 
        chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, addr, -1);
@@ -2741,7 +2732,9 @@ static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,
 static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
                        int addr, uint8_t *subfeature_param)
 {
-       if (!chip->onfi_version)
+       if (!chip->onfi_version ||
+           !(le16_to_cpu(chip->onfi_params.opt_cmd)
+             & ONFI_OPT_CMD_SET_GET_FEATURES))
                return -EINVAL;
 
        /* clear the sub feature parameters */
index cd6be2ed53a86a86a1baca65440adb73183d10a8..52115151e4a7f325491a3dbf6f16ccd87221b37a 100644 (file)
@@ -324,8 +324,6 @@ static int nuc900_nand_remove(struct platform_device *pdev)
 
        kfree(nuc900_nand);
 
-       platform_set_drvdata(pdev, NULL);
-
        return 0;
 }
 
index 81b80af55872a4f2481dd6d3d0c61b762e02ff51..c4c7e0d306f17e3ccd085b20f3cd269f153ebf38 100644 (file)
 #include <linux/of.h>
 #include <linux/of_device.h>
 
-#ifdef CONFIG_MTD_NAND_OMAP_BCH
+#ifdef CONFIG_MTD_NAND_ECC_BCH
 #include <linux/bch.h>
+#endif
+#ifdef CONFIG_MTD_NAND_OMAP_BCH
 #include <linux/platform_data/elm.h>
 #endif
 
 #define BCH_ECC_SIZE0          0x0     /* ecc_size0 = 0, no oob protection */
 #define BCH_ECC_SIZE1          0x20    /* ecc_size1 = 32 */
 
+#define BADBLOCK_MARKER_LENGTH         0x2
+#define OMAP_ECC_BCH8_POLYNOMIAL       0x201b
+
 #ifdef CONFIG_MTD_NAND_OMAP_BCH
 static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc,
        0xac, 0x6b, 0xff, 0x99, 0x7b};
@@ -182,14 +187,11 @@ struct omap_nand_info {
        u_char                          *buf;
        int                                     buf_len;
        struct gpmc_nand_regs           reg;
-
-#ifdef CONFIG_MTD_NAND_OMAP_BCH
-       struct bch_control             *bch;
-       struct nand_ecclayout           ecclayout;
+       /* fields specific for BCHx_HW ECC scheme */
+       struct bch_control              *bch;
        bool                            is_elm_used;
        struct device                   *elm_dev;
        struct device_node              *of_node;
-#endif
 };
 
 /**
@@ -1058,8 +1060,6 @@ static int omap_dev_ready(struct mtd_info *mtd)
        }
 }
 
-#ifdef CONFIG_MTD_NAND_OMAP_BCH
-
 /**
  * omap3_enable_hwecc_bch - Program OMAP3 GPMC to perform BCH ECC correction
  * @mtd: MTD device structure
@@ -1141,6 +1141,7 @@ static void omap3_enable_hwecc_bch(struct mtd_info *mtd, int mode)
        writel(ECCCLEAR | ECC1, info->reg.gpmc_ecc_control);
 }
 
+#ifdef CONFIG_MTD_NAND_ECC_BCH
 /**
  * omap3_calculate_ecc_bch4 - Generate 7 bytes of ECC bytes
  * @mtd: MTD device structure
@@ -1226,6 +1227,62 @@ static int omap3_calculate_ecc_bch8(struct mtd_info *mtd, const u_char *dat,
        return 0;
 }
 
+/**
+ * omap3_correct_data_bch - Decode received data and correct errors
+ * @mtd: MTD device structure
+ * @data: page data
+ * @read_ecc: ecc read from nand flash
+ * @calc_ecc: ecc read from HW ECC registers
+ */
+static int omap3_correct_data_bch(struct mtd_info *mtd, u_char *data,
+                                 u_char *read_ecc, u_char *calc_ecc)
+{
+       int i, count;
+       /* cannot correct more than 8 errors */
+       unsigned int errloc[8];
+       struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
+                                                  mtd);
+
+       count = decode_bch(info->bch, NULL, 512, read_ecc, calc_ecc, NULL,
+                          errloc);
+       if (count > 0) {
+               /* correct errors */
+               for (i = 0; i < count; i++) {
+                       /* correct data only, not ecc bytes */
+                       if (errloc[i] < 8*512)
+                               data[errloc[i]/8] ^= 1 << (errloc[i] & 7);
+                       pr_debug("corrected bitflip %u\n", errloc[i]);
+               }
+       } else if (count < 0) {
+               pr_err("ecc unrecoverable error\n");
+       }
+       return count;
+}
+
+/**
+ * omap3_free_bch - Release BCH ecc resources
+ * @mtd: MTD device structure
+ */
+static void omap3_free_bch(struct mtd_info *mtd)
+{
+       struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
+                                                  mtd);
+       if (info->bch) {
+               free_bch(info->bch);
+               info->bch = NULL;
+       }
+}
+
+#else
+
+static void omap3_free_bch(struct mtd_info *mtd)
+{
+}
+
+#endif /* CONFIG_MTD_NAND_ECC_BCH */
+
+
+#ifdef CONFIG_MTD_NAND_OMAP_BCH
 /**
  * omap3_calculate_ecc_bch - Generate bytes of ECC bytes
  * @mtd:       MTD device structure
@@ -1518,38 +1575,6 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
        return stat;
 }
 
-/**
- * omap3_correct_data_bch - Decode received data and correct errors
- * @mtd: MTD device structure
- * @data: page data
- * @read_ecc: ecc read from nand flash
- * @calc_ecc: ecc read from HW ECC registers
- */
-static int omap3_correct_data_bch(struct mtd_info *mtd, u_char *data,
-                                 u_char *read_ecc, u_char *calc_ecc)
-{
-       int i, count;
-       /* cannot correct more than 8 errors */
-       unsigned int errloc[8];
-       struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
-                                                  mtd);
-
-       count = decode_bch(info->bch, NULL, 512, read_ecc, calc_ecc, NULL,
-                          errloc);
-       if (count > 0) {
-               /* correct errors */
-               for (i = 0; i < count; i++) {
-                       /* correct data only, not ecc bytes */
-                       if (errloc[i] < 8*512)
-                               data[errloc[i]/8] ^= 1 << (errloc[i] & 7);
-                       pr_debug("corrected bitflip %u\n", errloc[i]);
-               }
-       } else if (count < 0) {
-               pr_err("ecc unrecoverable error\n");
-       }
-       return count;
-}
-
 /**
  * omap_write_page_bch - BCH ecc based write page function for entire page
  * @mtd:               mtd info structure
@@ -1637,197 +1662,47 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
 }
 
 /**
- * omap3_free_bch - Release BCH ecc resources
- * @mtd: MTD device structure
- */
-static void omap3_free_bch(struct mtd_info *mtd)
-{
-       struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
-                                                  mtd);
-       if (info->bch) {
-               free_bch(info->bch);
-               info->bch = NULL;
-       }
-}
-
-/**
- * omap3_init_bch - Initialize BCH ECC
- * @mtd: MTD device structure
- * @ecc_opt: OMAP ECC mode (OMAP_ECC_BCH4_CODE_HW or OMAP_ECC_BCH8_CODE_HW)
+ * is_elm_present - checks for presence of ELM module by scanning DT nodes
+ * @omap_nand_info: NAND device structure containing platform data
+ * @bch_type: 0x0=BCH4, 0x1=BCH8, 0x2=BCH16
  */
-static int omap3_init_bch(struct mtd_info *mtd, int ecc_opt)
+static int is_elm_present(struct omap_nand_info *info, int bch_type)
 {
-       int max_errors;
-       struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
-                                                  mtd);
-#ifdef CONFIG_MTD_NAND_OMAP_BCH8
-       const int hw_errors = BCH8_MAX_ERROR;
-#else
-       const int hw_errors = BCH4_MAX_ERROR;
-#endif
-       enum bch_ecc bch_type;
        const __be32 *parp;
        int lenp;
        struct device_node *elm_node;
-
-       info->bch = NULL;
-
-       max_errors = (ecc_opt == OMAP_ECC_BCH8_CODE_HW) ?
-               BCH8_MAX_ERROR : BCH4_MAX_ERROR;
-       if (max_errors != hw_errors) {
-               pr_err("cannot configure %d-bit BCH ecc, only %d-bit supported",
-                      max_errors, hw_errors);
-               goto fail;
-       }
-
-       info->nand.ecc.size = 512;
-       info->nand.ecc.hwctl = omap3_enable_hwecc_bch;
-       info->nand.ecc.mode = NAND_ECC_HW;
-       info->nand.ecc.strength = max_errors;
-
-       if (hw_errors == BCH8_MAX_ERROR)
-               bch_type = BCH8_ECC;
-       else
-               bch_type = BCH4_ECC;
+       struct platform_device *pdev;
+       info->is_elm_used = false;
 
        /* Detect availability of ELM module */
        parp = of_get_property(info->of_node, "elm_id", &lenp);
        if ((parp == NULL) && (lenp != (sizeof(void *) * 2))) {
                pr_err("Missing elm_id property, fall back to Software BCH\n");
-               info->is_elm_used = false;
        } else {
-               struct platform_device *pdev;
-
                elm_node = of_find_node_by_phandle(be32_to_cpup(parp));
                pdev = of_find_device_by_node(elm_node);
                info->elm_dev = &pdev->dev;
-
-               if (elm_config(info->elm_dev, bch_type) == 0)
-                       info->is_elm_used = true;
-       }
-
-       if (info->is_elm_used && (mtd->writesize <= 4096)) {
-
-               if (hw_errors == BCH8_MAX_ERROR)
-                       info->nand.ecc.bytes = BCH8_SIZE;
-               else
-                       info->nand.ecc.bytes = BCH4_SIZE;
-
-               info->nand.ecc.correct = omap_elm_correct_data;
-               info->nand.ecc.calculate = omap3_calculate_ecc_bch;
-               info->nand.ecc.read_page = omap_read_page_bch;
-               info->nand.ecc.write_page = omap_write_page_bch;
-       } else {
-               /*
-                * software bch library is only used to detect and
-                * locate errors
-                */
-               info->bch = init_bch(13, max_errors,
-                               0x201b /* hw polynomial */);
-               if (!info->bch)
-                       goto fail;
-
-               info->nand.ecc.correct = omap3_correct_data_bch;
-
-               /*
-                * The number of corrected errors in an ecc block that will
-                * trigger block scrubbing defaults to the ecc strength (4 or 8)
-                * Set mtd->bitflip_threshold here to define a custom threshold.
-                */
-
-               if (max_errors == 8) {
-                       info->nand.ecc.bytes = 13;
-                       info->nand.ecc.calculate = omap3_calculate_ecc_bch8;
-               } else {
-                       info->nand.ecc.bytes = 7;
-                       info->nand.ecc.calculate = omap3_calculate_ecc_bch4;
-               }
-       }
-
-       pr_info("enabling NAND BCH ecc with %d-bit correction\n", max_errors);
-       return 0;
-fail:
-       omap3_free_bch(mtd);
-       return -1;
-}
-
-/**
- * omap3_init_bch_tail - Build an oob layout for BCH ECC correction.
- * @mtd: MTD device structure
- */
-static int omap3_init_bch_tail(struct mtd_info *mtd)
-{
-       int i, steps, offset;
-       struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
-                                                  mtd);
-       struct nand_ecclayout *layout = &info->ecclayout;
-
-       /* build oob layout */
-       steps = mtd->writesize/info->nand.ecc.size;
-       layout->eccbytes = steps*info->nand.ecc.bytes;
-
-       /* do not bother creating special oob layouts for small page devices */
-       if (mtd->oobsize < 64) {
-               pr_err("BCH ecc is not supported on small page devices\n");
-               goto fail;
-       }
-
-       /* reserve 2 bytes for bad block marker */
-       if (layout->eccbytes+2 > mtd->oobsize) {
-               pr_err("no oob layout available for oobsize %d eccbytes %u\n",
-                      mtd->oobsize, layout->eccbytes);
-               goto fail;
+               /* ELM module available, now configure it */
+               elm_config(info->elm_dev, bch_type);
+               info->is_elm_used = true;
+               return 0;
        }
 
-       /* ECC layout compatible with RBL for BCH8 */
-       if (info->is_elm_used && (info->nand.ecc.bytes == BCH8_SIZE))
-               offset = 2;
-       else
-               offset = mtd->oobsize - layout->eccbytes;
-
-       /* put ecc bytes at oob tail */
-       for (i = 0; i < layout->eccbytes; i++)
-               layout->eccpos[i] = offset + i;
-
-       if (info->is_elm_used && (info->nand.ecc.bytes == BCH8_SIZE))
-               layout->oobfree[0].offset = 2 + layout->eccbytes * steps;
-       else
-               layout->oobfree[0].offset = 2;
-
-       layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes;
-       info->nand.ecc.layout = layout;
-
-       if (!(info->nand.options & NAND_BUSWIDTH_16))
-               info->nand.badblock_pattern = &bb_descrip_flashbased;
-       return 0;
-fail:
-       omap3_free_bch(mtd);
-       return -1;
-}
-
-#else
-static int omap3_init_bch(struct mtd_info *mtd, int ecc_opt)
-{
-       pr_err("CONFIG_MTD_NAND_OMAP_BCH is not enabled\n");
-       return -1;
-}
-static int omap3_init_bch_tail(struct mtd_info *mtd)
-{
-       return -1;
-}
-static void omap3_free_bch(struct mtd_info *mtd)
-{
+       return -ENODEV;
 }
 #endif /* CONFIG_MTD_NAND_OMAP_BCH */
 
+
 static int omap_nand_probe(struct platform_device *pdev)
 {
        struct omap_nand_info           *info;
        struct omap_nand_platform_data  *pdata;
+       struct mtd_info                 *mtd;
+       struct nand_chip                *chip;
        int                             err;
-       int                             i, offset;
-       dma_cap_mask_t mask;
-       unsigned sig;
+       int                             i;
+       dma_cap_mask_t                  mask;
+       unsigned                        sig;
        struct resource                 *res;
        struct mtd_part_parser_data     ppdata = {};
 
@@ -1846,16 +1721,18 @@ static int omap_nand_probe(struct platform_device *pdev)
        spin_lock_init(&info->controller.lock);
        init_waitqueue_head(&info->controller.wq);
 
-       info->pdev = pdev;
+       mtd                     = &info->mtd;
+       mtd->name               = dev_name(&pdev->dev);
+       mtd->owner              = THIS_MODULE;
+       mtd->priv               = &info->nand;
+       chip                    = mtd->priv;
 
+       info->pdev              = pdev;
        info->gpmc_cs           = pdata->cs;
        info->reg               = pdata->reg;
+       info->bch               = NULL;
 
-       info->mtd.priv          = &info->nand;
-       info->mtd.name          = dev_name(&pdev->dev);
-       info->mtd.owner         = THIS_MODULE;
-
-       info->nand.options      = pdata->devsize;
+       info->nand.options      = NAND_BUSWIDTH_AUTO;
        info->nand.options      |= NAND_SKIP_BBTSCAN;
 #ifdef CONFIG_MTD_NAND_OMAP_BCH
        info->of_node           = pdata->of_node;
@@ -1903,6 +1780,31 @@ static int omap_nand_probe(struct platform_device *pdev)
                info->nand.chip_delay = 50;
        }
 
+       /* scan NAND device conncted to controller */
+       if (nand_scan_ident(mtd, 1, NULL)) {
+               err = -ENXIO;
+               goto out_release_mem_region;
+       }
+       pr_info("%s: detected %s NAND flash\n", DRIVER_NAME,
+                       (info->nand.options & NAND_BUSWIDTH_16) ? "x16" : "x8");
+       if ((info->nand.options & NAND_BUSWIDTH_16) !=
+                       (pdata->devsize & NAND_BUSWIDTH_16)) {
+               pr_err("%s: but incorrectly configured as %s", DRIVER_NAME,
+                       (pdata->devsize & NAND_BUSWIDTH_16) ? "x16" : "x8");
+               err = -EINVAL;
+               goto out_release_mem_region;
+       }
+
+       /* check for small page devices */
+       if ((mtd->oobsize < 64) &&
+               (pdata->ecc_opt != OMAP_ECC_HAMMING_CODE_DEFAULT) &&
+               (pdata->ecc_opt != OMAP_ECC_HAMMING_CODE_HW)) {
+               pr_err("small page devices are not supported\n");
+               err = -EINVAL;
+               goto out_release_mem_region;
+       }
+
+       /* populate read & write API based on xfer_type selected */
        switch (pdata->xfer_type) {
        case NAND_OMAP_PREFETCH_POLLED:
                info->nand.read_buf   = omap_read_buf_pref;
@@ -1992,66 +1894,154 @@ static int omap_nand_probe(struct platform_device *pdev)
                goto out_release_mem_region;
        }
 
-       /* select the ecc type */
-       if (pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_DEFAULT)
-               info->nand.ecc.mode = NAND_ECC_SOFT;
-       else if ((pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_HW) ||
-               (pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_HW_ROMCODE)) {
+       /* populate MTD interface based on ECC scheme */
+       switch (pdata->ecc_opt) {
+       case OMAP_ECC_HAMMING_CODE_DEFAULT:
+               pr_info("using OMAP_ECC_HAMMING_CODE_DEFAULT ECC scheme\n");
+               info->nand.ecc.mode             = NAND_ECC_SOFT;
+               goto generic_ecc_layout;
+
+       case OMAP_ECC_HAMMING_CODE_HW:
+               pr_info("using OMAP_ECC_HAMMING_CODE_HW ECC scheme\n");
+               info->nand.ecc.mode             = NAND_ECC_HW;
                info->nand.ecc.bytes            = 3;
                info->nand.ecc.size             = 512;
                info->nand.ecc.strength         = 1;
                info->nand.ecc.calculate        = omap_calculate_ecc;
                info->nand.ecc.hwctl            = omap_enable_hwecc;
                info->nand.ecc.correct          = omap_correct_data;
+               goto generic_ecc_layout;
+
+       case OMAP_ECC_HAMMING_CODE_HW_ROMCODE:
+               pr_info("using OMAP_ECC_HAMMING_CODE_HW_ROMCODE ECC scheme\n");
                info->nand.ecc.mode             = NAND_ECC_HW;
-       } else if ((pdata->ecc_opt == OMAP_ECC_BCH4_CODE_HW) ||
-                  (pdata->ecc_opt == OMAP_ECC_BCH8_CODE_HW)) {
-               err = omap3_init_bch(&info->mtd, pdata->ecc_opt);
-               if (err) {
+               info->nand.ecc.bytes            = 3;
+               info->nand.ecc.size             = 512;
+               info->nand.ecc.strength         = 1;
+               info->nand.ecc.calculate        = omap_calculate_ecc;
+               info->nand.ecc.hwctl            = omap_enable_hwecc;
+               info->nand.ecc.correct          = omap_correct_data;
+               /* define custom ECC layout */
+               omap_oobinfo.eccbytes           = info->nand.ecc.bytes *
+                                                       (mtd->writesize /
+                                                       info->nand.ecc.size);
+               if (info->nand.options & NAND_BUSWIDTH_16)
+                       omap_oobinfo.eccpos[0]  = BADBLOCK_MARKER_LENGTH;
+               else
+                       omap_oobinfo.eccpos[0]  = 1;
+               omap_oobinfo.oobfree->offset    = omap_oobinfo.eccpos[0] +
+                                                       omap_oobinfo.eccbytes;
+               goto custom_ecc_layout;
+
+#ifdef CONFIG_MTD_NAND_OMAP_BCH
+       case OMAP_ECC_BCH8_CODE_HW:
+               pr_info("using OMAP_ECC_BCH8_CODE_HW ECC scheme\n");
+               if (is_elm_present(info, ECC_TYPE_BCH8) < 0) {
+                       pr_err("ELM module not detected, required for ECC\n");
                        err = -EINVAL;
                        goto out_release_mem_region;
                }
-       }
-
-       /* DIP switches on some boards change between 8 and 16 bit
-        * bus widths for flash.  Try the other width if the first try fails.
-        */
-       if (nand_scan_ident(&info->mtd, 1, NULL)) {
-               info->nand.options ^= NAND_BUSWIDTH_16;
-               if (nand_scan_ident(&info->mtd, 1, NULL)) {
-                       err = -ENXIO;
+               info->nand.ecc.mode             = NAND_ECC_HW;
+               info->nand.ecc.size             = 512;
+               /* 14th bit is kept reserved for ROM-code compatibility */
+               info->nand.ecc.bytes            = 13 + 1;
+               info->nand.ecc.strength         = 8;
+               info->nand.ecc.hwctl            = omap3_enable_hwecc_bch;
+               info->nand.ecc.correct          = omap_elm_correct_data;
+               info->nand.ecc.calculate        = omap3_calculate_ecc_bch;
+               info->nand.ecc.read_page        = omap_read_page_bch;
+               info->nand.ecc.write_page       = omap_write_page_bch;
+               /* define custom ECC layout */
+               omap_oobinfo.eccbytes           = info->nand.ecc.bytes *
+                                                       (mtd->writesize /
+                                                       info->nand.ecc.size);
+               omap_oobinfo.eccpos[0]          = BADBLOCK_MARKER_LENGTH;
+               omap_oobinfo.oobfree->offset    = omap_oobinfo.eccpos[0] +
+                                                       omap_oobinfo.eccbytes;
+               goto custom_ecc_layout;
+#endif
+#ifdef CONFIG_MTD_NAND_ECC_BCH
+       case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
+               pr_info("using OMAP_ECC_BCH8_CODE_HW_DETECTION_SW ECC\n");
+               info->nand.ecc.mode             = NAND_ECC_HW;
+               info->nand.ecc.size             = 512;
+               info->nand.ecc.bytes            = 13;
+               info->nand.ecc.strength         = 8;
+               info->nand.ecc.hwctl            = omap3_enable_hwecc_bch;
+               info->nand.ecc.correct          = omap3_correct_data_bch;
+               info->nand.ecc.calculate        = omap3_calculate_ecc_bch8;
+               /* define custom ECC layout */
+               omap_oobinfo.eccbytes           = info->nand.ecc.bytes *
+                                                       (mtd->writesize /
+                                                       info->nand.ecc.size);
+               omap_oobinfo.eccpos[0]          = info->mtd.oobsize -
+                                                       omap_oobinfo.eccbytes;
+               omap_oobinfo.oobfree->offset    = BADBLOCK_MARKER_LENGTH;
+               /* software bch library is used for locating errors */
+               info->bch = init_bch(info->nand.ecc.bytes,
+                                       info->nand.ecc.strength,
+                                       OMAP_ECC_BCH8_POLYNOMIAL);
+               if (!info->bch) {
+                       pr_err("unable initialize S/W BCH logic\n");
+                       err = -EINVAL;
                        goto out_release_mem_region;
                }
-       }
-
-       /* rom code layout */
-       if (pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_HW_ROMCODE) {
-
-               if (info->nand.options & NAND_BUSWIDTH_16)
-                       offset = 2;
-               else {
-                       offset = 1;
-                       info->nand.badblock_pattern = &bb_descrip_flashbased;
-               }
-               omap_oobinfo.eccbytes = 3 * (info->mtd.oobsize/16);
-               for (i = 0; i < omap_oobinfo.eccbytes; i++)
-                       omap_oobinfo.eccpos[i] = i+offset;
-
-               omap_oobinfo.oobfree->offset = offset + omap_oobinfo.eccbytes;
-               omap_oobinfo.oobfree->length = info->mtd.oobsize -
-                                       (offset + omap_oobinfo.eccbytes);
-
-               info->nand.ecc.layout = &omap_oobinfo;
-       } else if ((pdata->ecc_opt == OMAP_ECC_BCH4_CODE_HW) ||
-                  (pdata->ecc_opt == OMAP_ECC_BCH8_CODE_HW)) {
-               /* build OOB layout for BCH ECC correction */
-               err = omap3_init_bch_tail(&info->mtd);
-               if (err) {
+               goto custom_ecc_layout;
+
+       case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
+               pr_info("using OMAP_ECC_BCH4_CODE_HW_DETECTION_SW ECC\n");
+               info->nand.ecc.mode             = NAND_ECC_HW;
+               info->nand.ecc.size             = 512;
+               info->nand.ecc.bytes            = 7;
+               info->nand.ecc.strength         = 4;
+               info->nand.ecc.hwctl            = omap3_enable_hwecc_bch;
+               info->nand.ecc.correct          = omap3_correct_data_bch;
+               info->nand.ecc.calculate        = omap3_calculate_ecc_bch4;
+               /* define custom ECC layout */
+               omap_oobinfo.eccbytes           = info->nand.ecc.bytes *
+                                                       (mtd->writesize /
+                                                       info->nand.ecc.size);
+               omap_oobinfo.eccpos[0]          = info->mtd.oobsize -
+                                                       omap_oobinfo.eccbytes;
+               omap_oobinfo.oobfree->offset    = BADBLOCK_MARKER_LENGTH;
+               /* software bch library is used for locating errors */
+               info->bch = init_bch(info->nand.ecc.bytes,
+                                       info->nand.ecc.strength,
+                                       OMAP_ECC_BCH8_POLYNOMIAL);
+               if (!info->bch) {
+                       pr_err("unable initialize S/W BCH logic\n");
                        err = -EINVAL;
                        goto out_release_mem_region;
                }
+               goto custom_ecc_layout;
+#endif
+       default:
+               pr_err("selected ECC scheme not supported or not enabled\n");
+               err = -EINVAL;
+               goto out_release_mem_region;
+       }
+
+custom_ecc_layout:
+       /* populate remaining info for custom ecc layout */
+       pr_info("%s: using custom ecc layout\n", DRIVER_NAME);
+       omap_oobinfo.oobfree->length = mtd->oobsize - BADBLOCK_MARKER_LENGTH
+                                               - omap_oobinfo.eccbytes;
+       if (!(info->nand.options & NAND_BUSWIDTH_16))
+               info->nand.badblock_pattern = &bb_descrip_flashbased;
+       for (i = 1; i < omap_oobinfo.eccbytes; i++)
+               omap_oobinfo.eccpos[i] = omap_oobinfo.eccpos[0] + i;
+
+       /* check if NAND OOBSIZE meets ECC scheme requirement */
+       if (mtd->oobsize < (omap_oobinfo.eccbytes +
+                                       BADBLOCK_MARKER_LENGTH)) {
+               pr_err("not enough OOB bytes required = %d, available=%d\n",
+                      mtd->oobsize, omap_oobinfo.eccbytes);
+               err = -EINVAL;
+               goto out_release_mem_region;
        }
+       info->nand.ecc.layout = &omap_oobinfo;
 
+generic_ecc_layout:
        /* second phase scan */
        if (nand_scan_tail(&info->mtd)) {
                err = -ENXIO;
@@ -2075,11 +2065,13 @@ out_release_mem_region:
                free_irq(info->gpmc_irq_fifo, info);
        release_mem_region(info->phys_base, info->mem_size);
 out_free_info:
+       omap3_free_bch(&info->mtd);
        kfree(info);
 
        return err;
 }
 
+
 static int omap_nand_remove(struct platform_device *pdev)
 {
        struct mtd_info *mtd = platform_get_drvdata(pdev);
@@ -2087,7 +2079,6 @@ static int omap_nand_remove(struct platform_device *pdev)
                                                        mtd);
        omap3_free_bch(&info->mtd);
 
-       platform_set_drvdata(pdev, NULL);
        if (info->dma)
                dma_release_channel(info->dma);
 
index 8fbd002086107f1fff96d26307e9b670b1ca7d95..46f308df84389f7b1def55f06deb501936f45f9d 100644 (file)
@@ -186,7 +186,6 @@ no_dev:
                clk_disable_unprepare(clk);
                clk_put(clk);
        }
-       platform_set_drvdata(pdev, NULL);
        iounmap(io_base);
 no_res:
        kfree(nc);
index c004566a9ad2ae383a311ea31587411e0a98aaa7..d42700a774e9ab04fa5e87773fc1e56e0d9e738e 100644 (file)
@@ -122,7 +122,6 @@ static int plat_nand_probe(struct platform_device *pdev)
 out:
        if (pdata->ctrl.remove)
                pdata->ctrl.remove(pdev);
-       platform_set_drvdata(pdev, NULL);
        iounmap(data->io_base);
 out_release_io:
        release_mem_region(res->start, resource_size(res));
index dec80ca6a5ce58dbd187690ea42fc706c9dc9325..fdc045d9d2acf44355e7a722f64998fb396fedc6 100644 (file)
@@ -506,6 +506,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
        info->buf_count         = 0;
        info->oob_size          = 0;
        info->use_ecc           = 0;
+       info->use_dma           = (use_dma) ? 1 : 0;
        info->is_ready          = 0;
        info->retcode           = ERR_NONE;
        if (info->cs != 0)
@@ -589,12 +590,23 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
                                | addr_cycle;
                break;
 
+       case NAND_CMD_PARAM:
+               cmd = NAND_CMD_PARAM;
+               info->buf_count = 256;
+               info->ndcb0 |= NDCB0_CMD_TYPE(0)
+                               | NDCB0_ADDR_CYC(1)
+                               | cmd;
+               info->ndcb1 = (column & 0xFF);
+               info->data_size = 256;
+               break;
+
        case NAND_CMD_READID:
                cmd = host->cmdset->read_id;
                info->buf_count = host->read_id_bytes;
                info->ndcb0 |= NDCB0_CMD_TYPE(3)
                                | NDCB0_ADDR_CYC(1)
                                | cmd;
+               info->ndcb1 = (column & 0xFF);
 
                info->data_size = 8;
                break;
@@ -912,6 +924,18 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
        return 0;
 }
 
+static void pxa3xx_nand_free_buff(struct pxa3xx_nand_info *info)
+{
+       struct platform_device *pdev = info->pdev;
+       if (use_dma) {
+               pxa_free_dma(info->data_dma_ch);
+               dma_free_coherent(&pdev->dev, MAX_BUFF_SIZE,
+                                 info->data_buff, info->data_buff_phys);
+       } else {
+               kfree(info->data_buff);
+       }
+}
+
 static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info)
 {
        struct mtd_info *mtd;
@@ -1035,12 +1059,10 @@ static int alloc_nand_resource(struct platform_device *pdev)
        int ret, irq, cs;
 
        pdata = pdev->dev.platform_data;
-       info = kzalloc(sizeof(*info) + (sizeof(*mtd) +
-                      sizeof(*host)) * pdata->num_cs, GFP_KERNEL);
-       if (!info) {
-               dev_err(&pdev->dev, "failed to allocate memory\n");
+       info = devm_kzalloc(&pdev->dev, sizeof(*info) + (sizeof(*mtd) +
+                           sizeof(*host)) * pdata->num_cs, GFP_KERNEL);
+       if (!info)
                return -ENOMEM;
-       }
 
        info->pdev = pdev;
        for (cs = 0; cs < pdata->num_cs; cs++) {
@@ -1069,20 +1091,21 @@ static int alloc_nand_resource(struct platform_device *pdev)
 
        spin_lock_init(&chip->controller->lock);
        init_waitqueue_head(&chip->controller->wq);
-       info->clk = clk_get(&pdev->dev, NULL);
+       info->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(info->clk)) {
                dev_err(&pdev->dev, "failed to get nand clock\n");
-               ret = PTR_ERR(info->clk);
-               goto fail_free_mtd;
+               return PTR_ERR(info->clk);
        }
-       clk_enable(info->clk);
+       ret = clk_prepare_enable(info->clk);
+       if (ret < 0)
+               return ret;
 
        /*
         * This is a dirty hack to make this driver work from devicetree
         * bindings. It can be removed once we have a prober DMA controller
         * framework for DT.
         */
-       if (pdev->dev.of_node && cpu_is_pxa3xx()) {
+       if (pdev->dev.of_node && of_machine_is_compatible("marvell,pxa3xx")) {
                info->drcmr_dat = 97;
                info->drcmr_cmd = 99;
        } else {
@@ -1090,7 +1113,7 @@ static int alloc_nand_resource(struct platform_device *pdev)
                if (r == NULL) {
                        dev_err(&pdev->dev, "no resource defined for data DMA\n");
                        ret = -ENXIO;
-                       goto fail_put_clk;
+                       goto fail_disable_clk;
                }
                info->drcmr_dat = r->start;
 
@@ -1098,7 +1121,7 @@ static int alloc_nand_resource(struct platform_device *pdev)
                if (r == NULL) {
                        dev_err(&pdev->dev, "no resource defined for command DMA\n");
                        ret = -ENXIO;
-                       goto fail_put_clk;
+                       goto fail_disable_clk;
                }
                info->drcmr_cmd = r->start;
        }
@@ -1107,34 +1130,20 @@ static int alloc_nand_resource(struct platform_device *pdev)
        if (irq < 0) {
                dev_err(&pdev->dev, "no IRQ resource defined\n");
                ret = -ENXIO;
-               goto fail_put_clk;
+               goto fail_disable_clk;
        }
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (r == NULL) {
-               dev_err(&pdev->dev, "no IO memory resource defined\n");
-               ret = -ENODEV;
-               goto fail_put_clk;
-       }
-
-       r = request_mem_region(r->start, resource_size(r), pdev->name);
-       if (r == NULL) {
-               dev_err(&pdev->dev, "failed to request memory resource\n");
-               ret = -EBUSY;
-               goto fail_put_clk;
-       }
-
-       info->mmio_base = ioremap(r->start, resource_size(r));
-       if (info->mmio_base == NULL) {
-               dev_err(&pdev->dev, "ioremap() failed\n");
-               ret = -ENODEV;
-               goto fail_free_res;
+       info->mmio_base = devm_ioremap_resource(&pdev->dev, r);
+       if (IS_ERR(info->mmio_base)) {
+               ret = PTR_ERR(info->mmio_base);
+               goto fail_disable_clk;
        }
        info->mmio_phys = r->start;
 
        ret = pxa3xx_nand_init_buff(info);
        if (ret)
-               goto fail_free_io;
+               goto fail_disable_clk;
 
        /* initialize all interrupts to be disabled */
        disable_int(info, NDSR_MASK);
@@ -1152,21 +1161,9 @@ static int alloc_nand_resource(struct platform_device *pdev)
 
 fail_free_buf:
        free_irq(irq, info);
-       if (use_dma) {
-               pxa_free_dma(info->data_dma_ch);
-               dma_free_coherent(&pdev->dev, MAX_BUFF_SIZE,
-                       info->data_buff, info->data_buff_phys);
-       } else
-               kfree(info->data_buff);
-fail_free_io:
-       iounmap(info->mmio_base);
-fail_free_res:
-       release_mem_region(r->start, resource_size(r));
-fail_put_clk:
-       clk_disable(info->clk);
-       clk_put(info->clk);
-fail_free_mtd:
-       kfree(info);
+       pxa3xx_nand_free_buff(info);
+fail_disable_clk:
+       clk_disable_unprepare(info->clk);
        return ret;
 }
 
@@ -1174,35 +1171,22 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)
 {
        struct pxa3xx_nand_info *info = platform_get_drvdata(pdev);
        struct pxa3xx_nand_platform_data *pdata;
-       struct resource *r;
        int irq, cs;
 
        if (!info)
                return 0;
 
        pdata = pdev->dev.platform_data;
-       platform_set_drvdata(pdev, NULL);
 
        irq = platform_get_irq(pdev, 0);
        if (irq >= 0)
                free_irq(irq, info);
-       if (use_dma) {
-               pxa_free_dma(info->data_dma_ch);
-               dma_free_writecombine(&pdev->dev, MAX_BUFF_SIZE,
-                               info->data_buff, info->data_buff_phys);
-       } else
-               kfree(info->data_buff);
-
-       iounmap(info->mmio_base);
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(r->start, resource_size(r));
+       pxa3xx_nand_free_buff(info);
 
-       clk_disable(info->clk);
-       clk_put(info->clk);
+       clk_disable_unprepare(info->clk);
 
        for (cs = 0; cs < pdata->num_cs; cs++)
                nand_release(info->host[cs]->mtd);
-       kfree(info);
        return 0;
 }
 
@@ -1211,7 +1195,7 @@ static struct of_device_id pxa3xx_nand_dt_ids[] = {
        { .compatible = "marvell,pxa3xx-nand" },
        {}
 };
-MODULE_DEVICE_TABLE(of, i2c_pxa_dt_ids);
+MODULE_DEVICE_TABLE(of, pxa3xx_nand_dt_ids);
 
 static int pxa3xx_nand_probe_dt(struct platform_device *pdev)
 {
index 4495f8551fa093fc6f30117475d624691e918430..ef72884825f3b275e76717d1e04a88078cb283cf 100644 (file)
@@ -1002,7 +1002,7 @@ void r852_shutdown(struct pci_dev *pci_dev)
        pci_disable_device(pci_dev);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int r852_suspend(struct device *device)
 {
        struct r852_device *dev = pci_get_drvdata(to_pci_dev(device));
@@ -1055,9 +1055,6 @@ static int r852_resume(struct device *device)
        r852_update_card_detect(dev);
        return 0;
 }
-#else
-#define r852_suspend   NULL
-#define r852_resume    NULL
 #endif
 
 static const struct pci_device_id r852_pci_id_tbl[] = {
index d65afd23e171c16587dffd4fd0044121eb43313a..191823ed706eaac294242bd026c54d196d6c8cca 100644 (file)
@@ -697,8 +697,6 @@ static int s3c24xx_nand_remove(struct platform_device *pdev)
 {
        struct s3c2410_nand_info *info = to_nand_info(pdev);
 
-       platform_set_drvdata(pdev, NULL);
-
        if (info == NULL)
                return 0;
 
index 127bc42718217a68c4c83fa89cf64b3cbed7d95c..1d41578d03361222120f1ab45ce56ded8cef5b5b 100644 (file)
@@ -194,7 +194,6 @@ err_add:
        nand_release(&sharpsl->mtd);
 
 err_scan:
-       platform_set_drvdata(pdev, NULL);
        iounmap(sharpsl->io);
 err_ioremap:
 err_get_res:
@@ -212,8 +211,6 @@ static int sharpsl_nand_remove(struct platform_device *pdev)
        /* Release resources, unregister device */
        nand_release(&sharpsl->mtd);
 
-       platform_set_drvdata(pdev, NULL);
-
        iounmap(sharpsl->io);
 
        /* Free the MTD device structure */
index 7ed654c68b0867af79c82da6f65cc210fb827498..0488dd5ea2f75752eedc498d334fa029df7e10aa 100644 (file)
@@ -387,7 +387,6 @@ static int __exit txx9ndfmc_remove(struct platform_device *dev)
        struct txx9ndfmc_drvdata *drvdata = platform_get_drvdata(dev);
        int i;
 
-       platform_set_drvdata(dev, NULL);
        if (!drvdata)
                return 0;
        for (i = 0; i < MAX_TXX9NDFMC_DEV; i++) {
index 9f11562f849dbb0f7f5a4836cc31ce9c9a7e3cb5..42520a39e7de0f295618c95fa87cbb41192f1f31 100644 (file)
@@ -94,8 +94,6 @@ static int generic_onenand_remove(struct platform_device *pdev)
        struct resource *res = pdev->resource;
        unsigned long size = resource_size(res);
 
-       platform_set_drvdata(pdev, NULL);
-
        if (info) {
                onenand_release(&info->mtd);
                release_mem_region(res->start, size);
index d98b198edd53a27139c1eaa0ffad5ae5f0fac9f2..cd43ceae6f5a12f45fc9fbebab4a6a472a8b8610 100644 (file)
@@ -810,7 +810,6 @@ static int omap2_onenand_remove(struct platform_device *pdev)
        if (c->dma_channel != -1)
                omap_free_dma(c->dma_channel);
        omap2_onenand_shutdown(pdev);
-       platform_set_drvdata(pdev, NULL);
        if (c->gpio_irq) {
                free_irq(gpio_to_irq(c->gpio_irq), c);
                gpio_free(c->gpio_irq);
index 2cf74085f93524c784f9adc3c3920713da570f5a..cebc48decd067a59e17fdac8321f32796995b68d 100644 (file)
@@ -1073,7 +1073,6 @@ static int s3c_onenand_remove(struct platform_device *pdev)
        release_mem_region(onenand->base_res->start,
                           resource_size(onenand->base_res));
 
-       platform_set_drvdata(pdev, NULL);
        kfree(onenand->oob_buf);
        kfree(onenand->page_buf);
        kfree(onenand);
index 3e24b379ffa42e8564df4e0be373ef2fe6aa21a5..ab81e9a5947ebe9e5fbb6540bd1cf20cb22d6537 100644 (file)
@@ -320,10 +320,8 @@ static int scan_for_bad_eraseblocks(void)
        int i, bad = 0;
 
        bbt = kmalloc(ebcnt, GFP_KERNEL);
-       if (!bbt) {
-               pr_err("error: cannot allocate memory\n");
+       if (!bbt)
                return -ENOMEM;
-       }
 
        pr_info("scanning for bad eraseblocks\n");
        for (i = 0; i < ebcnt; ++i) {
@@ -380,15 +378,11 @@ static int __init mtd_oobtest_init(void)
 
        err = -ENOMEM;
        readbuf = kmalloc(mtd->erasesize, GFP_KERNEL);
-       if (!readbuf) {
-               pr_err("error: cannot allocate memory\n");
+       if (!readbuf)
                goto out;
-       }
        writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
-       if (!writebuf) {
-               pr_err("error: cannot allocate memory\n");
+       if (!writebuf)
                goto out;
-       }
 
        err = scan_for_bad_eraseblocks();
        if (err)
index 0c1140b6c2863b92087d1b8156895a5a5162e664..acd991f4bf941a09d016f12cfea8def7e2c04433 100644 (file)
@@ -191,10 +191,8 @@ static int crosstest(void)
 
        pr_info("crosstest\n");
        pp1 = kmalloc(pgsize * 4, GFP_KERNEL);
-       if (!pp1) {
-               pr_err("error: cannot allocate memory\n");
+       if (!pp1)
                return -ENOMEM;
-       }
        pp2 = pp1 + pgsize;
        pp3 = pp2 + pgsize;
        pp4 = pp3 + pgsize;
@@ -456,10 +454,8 @@ static int scan_for_bad_eraseblocks(void)
        int i, bad = 0;
 
        bbt = kzalloc(ebcnt, GFP_KERNEL);
-       if (!bbt) {
-               pr_err("error: cannot allocate memory\n");
+       if (!bbt)
                return -ENOMEM;
-       }
 
        pr_info("scanning for bad eraseblocks\n");
        for (i = 0; i < ebcnt; ++i) {
@@ -516,20 +512,14 @@ static int __init mtd_pagetest_init(void)
        err = -ENOMEM;
        bufsize = pgsize * 2;
        writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
-       if (!writebuf) {
-               pr_err("error: cannot allocate memory\n");
+       if (!writebuf)
                goto out;
-       }
        twopages = kmalloc(bufsize, GFP_KERNEL);
-       if (!twopages) {
-               pr_err("error: cannot allocate memory\n");
+       if (!twopages)
                goto out;
-       }
        boundary = kmalloc(bufsize, GFP_KERNEL);
-       if (!boundary) {
-               pr_err("error: cannot allocate memory\n");
+       if (!boundary)
                goto out;
-       }
 
        err = scan_for_bad_eraseblocks();
        if (err)
index 266de04b6d29ef1666ab54ea05250411536ed0ef..2cdd0c47cac115d2381b7c8a0926985da4692148 100644 (file)
@@ -143,10 +143,8 @@ static int scan_for_bad_eraseblocks(void)
        int i, bad = 0;
 
        bbt = kzalloc(ebcnt, GFP_KERNEL);
-       if (!bbt) {
-               pr_err("error: cannot allocate memory\n");
+       if (!bbt)
                return -ENOMEM;
-       }
 
        if (!mtd_can_have_bb(mtd))
                return 0;
@@ -204,15 +202,11 @@ static int __init mtd_readtest_init(void)
 
        err = -ENOMEM;
        iobuf = kmalloc(mtd->erasesize, GFP_KERNEL);
-       if (!iobuf) {
-               pr_err("error: cannot allocate memory\n");
+       if (!iobuf)
                goto out;
-       }
        iobuf1 = kmalloc(mtd->erasesize, GFP_KERNEL);
-       if (!iobuf1) {
-               pr_err("error: cannot allocate memory\n");
+       if (!iobuf1)
                goto out;
-       }
 
        err = scan_for_bad_eraseblocks();
        if (err)
index a6ce9c1fa6c56c2cfcbc345e7fd53d323b7b7cbf..20b63d1ad494e6bd4deb6b95f525d6118b63e6c2 100644 (file)
@@ -313,10 +313,8 @@ static int scan_for_bad_eraseblocks(void)
        int i, bad = 0;
 
        bbt = kzalloc(ebcnt, GFP_KERNEL);
-       if (!bbt) {
-               pr_err("error: cannot allocate memory\n");
+       if (!bbt)
                return -ENOMEM;
-       }
 
        if (!mtd_can_have_bb(mtd))
                goto out;
@@ -384,10 +382,8 @@ static int __init mtd_speedtest_init(void)
 
        err = -ENOMEM;
        iobuf = kmalloc(mtd->erasesize, GFP_KERNEL);
-       if (!iobuf) {
-               pr_err("error: cannot allocate memory\n");
+       if (!iobuf)
                goto out;
-       }
 
        prandom_bytes(iobuf, mtd->erasesize);
 
index 787f539d16ca436099826f0626bb4c57efe6da6d..3a95e61b535da0e41c717420c7615908f8dcf39b 100644 (file)
@@ -202,10 +202,8 @@ static int scan_for_bad_eraseblocks(void)
        int i, bad = 0;
 
        bbt = kzalloc(ebcnt, GFP_KERNEL);
-       if (!bbt) {
-               pr_err("error: cannot allocate memory\n");
+       if (!bbt)
                return -ENOMEM;
-       }
 
        if (!mtd_can_have_bb(mtd))
                return 0;
@@ -276,10 +274,8 @@ static int __init mtd_stresstest_init(void)
        readbuf = vmalloc(bufsize);
        writebuf = vmalloc(bufsize);
        offsets = kmalloc(ebcnt * sizeof(int), GFP_KERNEL);
-       if (!readbuf || !writebuf || !offsets) {
-               pr_err("error: cannot allocate memory\n");
+       if (!readbuf || !writebuf || !offsets)
                goto out;
-       }
        for (i = 0; i < ebcnt; i++)
                offsets[i] = mtd->erasesize;
        prandom_bytes(writebuf, bufsize);
index aade56f2794541f9d0545be12a0110f9ffe18ea1..e41a04f5caab3c8fd4322cc09729f3dd094b3ce4 100644 (file)
@@ -333,10 +333,8 @@ static int scan_for_bad_eraseblocks(void)
        int i, bad = 0;
 
        bbt = kzalloc(ebcnt, GFP_KERNEL);
-       if (!bbt) {
-               pr_err("error: cannot allocate memory\n");
+       if (!bbt)
                return -ENOMEM;
-       }
 
        pr_info("scanning for bad eraseblocks\n");
        for (i = 0; i < ebcnt; ++i) {
@@ -393,15 +391,11 @@ static int __init mtd_subpagetest_init(void)
        err = -ENOMEM;
        bufsize = subpgsize * 32;
        writebuf = kmalloc(bufsize, GFP_KERNEL);
-       if (!writebuf) {
-               pr_info("error: cannot allocate memory\n");
+       if (!writebuf)
                goto out;
-       }
        readbuf = kmalloc(bufsize, GFP_KERNEL);
-       if (!readbuf) {
-               pr_info("error: cannot allocate memory\n");
+       if (!readbuf)
                goto out;
-       }
 
        err = scan_for_bad_eraseblocks();
        if (err)
index a746ba272f04b5e3b77a4e45f65809a398c73585..a956053608f9f6a9fdb94c877917150e6a25680e 100644 (file)
@@ -1007,7 +1007,7 @@ static void arcnet_rx(struct net_device *dev, int bufnum)
 
        soft = &pkt.soft.rfc1201;
 
-       lp->hw.copy_from_card(dev, bufnum, 0, &pkt, sizeof(ARC_HDR_SIZE));
+       lp->hw.copy_from_card(dev, bufnum, 0, &pkt, ARC_HDR_SIZE);
        if (pkt.hard.offset[0]) {
                ofs = pkt.hard.offset[0];
                length = 256 - ofs;
index 390061d096934f83c04171a1a8a62bf9d8345ec5..90102652c82a9651a09a49741453fd76dbeb47a4 100644 (file)
@@ -143,10 +143,9 @@ static inline struct bonding *__get_bond_by_port(struct port *port)
  */
 static inline struct port *__get_first_port(struct bonding *bond)
 {
-       if (bond->slave_cnt == 0)
-               return NULL;
+       struct slave *first_slave = bond_first_slave(bond);
 
-       return &(SLAVE_AD_INFO(bond->first_slave).port);
+       return first_slave ? &(SLAVE_AD_INFO(first_slave).port) : NULL;
 }
 
 /**
@@ -159,13 +158,16 @@ static inline struct port *__get_first_port(struct bonding *bond)
 static inline struct port *__get_next_port(struct port *port)
 {
        struct bonding *bond = __get_bond_by_port(port);
-       struct slave *slave = port->slave;
+       struct slave *slave = port->slave, *slave_next;
 
        // If there's no bond for this port, or this is the last slave
-       if ((bond == NULL) || (slave->next == bond->first_slave))
+       if (bond == NULL)
+               return NULL;
+       slave_next = bond_next_slave(bond, slave);
+       if (!slave_next || bond_is_first_slave(bond, slave_next))
                return NULL;
 
-       return &(SLAVE_AD_INFO(slave->next).port);
+       return &(SLAVE_AD_INFO(slave_next).port);
 }
 
 /**
@@ -178,12 +180,14 @@ static inline struct port *__get_next_port(struct port *port)
 static inline struct aggregator *__get_first_agg(struct port *port)
 {
        struct bonding *bond = __get_bond_by_port(port);
+       struct slave *first_slave;
 
        // If there's no bond for this port, or bond has no slaves
-       if ((bond == NULL) || (bond->slave_cnt == 0))
+       if (bond == NULL)
                return NULL;
+       first_slave = bond_first_slave(bond);
 
-       return &(SLAVE_AD_INFO(bond->first_slave).aggregator);
+       return first_slave ? &(SLAVE_AD_INFO(first_slave).aggregator) : NULL;
 }
 
 /**
@@ -195,14 +199,17 @@ static inline struct aggregator *__get_first_agg(struct port *port)
  */
 static inline struct aggregator *__get_next_agg(struct aggregator *aggregator)
 {
-       struct slave *slave = aggregator->slave;
+       struct slave *slave = aggregator->slave, *slave_next;
        struct bonding *bond = bond_get_bond_by_slave(slave);
 
        // If there's no bond for this aggregator, or this is the last slave
-       if ((bond == NULL) || (slave->next == bond->first_slave))
+       if (bond == NULL)
+               return NULL;
+       slave_next = bond_next_slave(bond, slave);
+       if (!slave_next || bond_is_first_slave(bond, slave_next))
                return NULL;
 
-       return &(SLAVE_AD_INFO(slave->next).aggregator);
+       return &(SLAVE_AD_INFO(slave_next).aggregator);
 }
 
 /*
@@ -2110,7 +2117,7 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
        read_lock(&bond->lock);
 
        //check if there are any slaves
-       if (bond->slave_cnt == 0)
+       if (list_empty(&bond->slave_list))
                goto re_arm;
 
        // check if agg_select_timer timer after initialize is timed out
@@ -2336,8 +2343,12 @@ void bond_3ad_handle_link_change(struct slave *slave, char link)
 int bond_3ad_set_carrier(struct bonding *bond)
 {
        struct aggregator *active;
+       struct slave *first_slave;
 
-       active = __get_active_agg(&(SLAVE_AD_INFO(bond->first_slave).aggregator));
+       first_slave = bond_first_slave(bond);
+       if (!first_slave)
+               return 0;
+       active = __get_active_agg(&(SLAVE_AD_INFO(first_slave).aggregator));
        if (active) {
                /* are enough slaves available to consider link up? */
                if (active->num_of_ports < bond->params.min_links) {
@@ -2415,6 +2426,7 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
        struct ad_info ad_info;
        int res = 1;
 
+       read_lock(&bond->lock);
        if (__bond_3ad_get_active_agg_info(bond, &ad_info)) {
                pr_debug("%s: Error: __bond_3ad_get_active_agg_info failed\n",
                         dev->name);
@@ -2432,7 +2444,7 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
 
        slave_agg_no = bond->xmit_hash_policy(skb, slaves_in_agg);
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator;
 
                if (agg && (agg->aggregator_identifier == agg_id)) {
@@ -2464,6 +2476,7 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
        }
 
 out:
+       read_unlock(&bond->lock);
        if (res) {
                /* no suitable interface, frame not sent */
                kfree_skb(skb);
@@ -2501,7 +2514,6 @@ int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
  */
 void bond_3ad_update_lacp_rate(struct bonding *bond)
 {
-       int i;
        struct slave *slave;
        struct port *port = NULL;
        int lacp_fast;
@@ -2509,7 +2521,7 @@ void bond_3ad_update_lacp_rate(struct bonding *bond)
        write_lock_bh(&bond->lock);
        lacp_fast = bond->params.lacp_fast;
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                port = &(SLAVE_AD_INFO(slave).port);
                if (port->slave == NULL)
                        continue;
index 4ea8ed150d469d55c741d63c09fa4fc7f7a29fa5..3a5db7b1df6845829c686bd8cece52e0467190e5 100644 (file)
@@ -224,13 +224,12 @@ static struct slave *tlb_get_least_loaded_slave(struct bonding *bond)
 {
        struct slave *slave, *least_loaded;
        long long max_gap;
-       int i;
 
        least_loaded = NULL;
        max_gap = LLONG_MIN;
 
        /* Find the slave with the largest gap */
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                if (SLAVE_IS_OK(slave)) {
                        long long gap = compute_gap(slave);
 
@@ -386,11 +385,10 @@ static struct slave *rlb_next_rx_slave(struct bonding *bond)
        struct slave *rx_slave, *slave, *start_at;
        int i = 0;
 
-       if (bond_info->next_rx_slave) {
+       if (bond_info->next_rx_slave)
                start_at = bond_info->next_rx_slave;
-       } else {
-               start_at = bond->first_slave;
-       }
+       else
+               start_at = bond_first_slave(bond);
 
        rx_slave = NULL;
 
@@ -405,7 +403,8 @@ static struct slave *rlb_next_rx_slave(struct bonding *bond)
        }
 
        if (rx_slave) {
-               bond_info->next_rx_slave = rx_slave->next;
+               slave = bond_next_slave(bond, rx_slave);
+               bond_info->next_rx_slave = slave;
        }
 
        return rx_slave;
@@ -1173,9 +1172,8 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
 {
        struct slave *tmp_slave1, *free_mac_slave = NULL;
        struct slave *has_bond_addr = bond->curr_active_slave;
-       int i;
 
-       if (bond->slave_cnt == 0) {
+       if (list_empty(&bond->slave_list)) {
                /* this is the first slave */
                return 0;
        }
@@ -1196,7 +1194,7 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
        /* The slave's address is equal to the address of the bond.
         * Search for a spare address in the bond for this slave.
         */
-       bond_for_each_slave(bond, tmp_slave1, i) {
+       bond_for_each_slave(bond, tmp_slave1) {
                if (!bond_slave_has_mac(bond, tmp_slave1->perm_hwaddr)) {
                        /* no slave has tmp_slave1's perm addr
                         * as its curr addr
@@ -1246,17 +1244,15 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
  */
 static int alb_set_mac_address(struct bonding *bond, void *addr)
 {
-       struct sockaddr sa;
-       struct slave *slave, *stop_at;
        char tmp_addr[ETH_ALEN];
+       struct slave *slave;
+       struct sockaddr sa;
        int res;
-       int i;
 
-       if (bond->alb_info.rlb_enabled) {
+       if (bond->alb_info.rlb_enabled)
                return 0;
-       }
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                /* save net_device's current hw address */
                memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN);
 
@@ -1276,8 +1272,7 @@ unwind:
        sa.sa_family = bond->dev->type;
 
        /* unwind from head to the slave that failed */
-       stop_at = slave;
-       bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) {
+       bond_for_each_slave_continue_reverse(bond, slave) {
                memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN);
                dev_set_mac_address(slave->dev, &sa);
                memcpy(slave->dev->dev_addr, tmp_addr, ETH_ALEN);
@@ -1342,6 +1337,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
 
        /* make sure that the curr_active_slave do not change during tx
         */
+       read_lock(&bond->lock);
        read_lock(&bond->curr_slave_lock);
 
        switch (ntohs(skb->protocol)) {
@@ -1446,11 +1442,12 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
        }
 
        read_unlock(&bond->curr_slave_lock);
-
+       read_unlock(&bond->lock);
        if (res) {
                /* no suitable interface, frame not sent */
                kfree_skb(skb);
        }
+
        return NETDEV_TX_OK;
 }
 
@@ -1460,11 +1457,10 @@ void bond_alb_monitor(struct work_struct *work)
                                            alb_work.work);
        struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
        struct slave *slave;
-       int i;
 
        read_lock(&bond->lock);
 
-       if (bond->slave_cnt == 0) {
+       if (list_empty(&bond->slave_list)) {
                bond_info->tx_rebalance_counter = 0;
                bond_info->lp_counter = 0;
                goto re_arm;
@@ -1482,9 +1478,8 @@ void bond_alb_monitor(struct work_struct *work)
                 */
                read_lock(&bond->curr_slave_lock);
 
-               bond_for_each_slave(bond, slave, i) {
+               bond_for_each_slave(bond, slave)
                        alb_send_learning_packets(slave, slave->dev->dev_addr);
-               }
 
                read_unlock(&bond->curr_slave_lock);
 
@@ -1496,7 +1491,7 @@ void bond_alb_monitor(struct work_struct *work)
 
                read_lock(&bond->curr_slave_lock);
 
-               bond_for_each_slave(bond, slave, i) {
+               bond_for_each_slave(bond, slave) {
                        tlb_clear_slave(bond, slave, 1);
                        if (slave == bond->curr_active_slave) {
                                SLAVE_TLB_INFO(slave).load =
@@ -1602,9 +1597,8 @@ int bond_alb_init_slave(struct bonding *bond, struct slave *slave)
  */
 void bond_alb_deinit_slave(struct bonding *bond, struct slave *slave)
 {
-       if (bond->slave_cnt > 1) {
+       if (!list_empty(&bond->slave_list))
                alb_change_hw_addr_on_detach(bond, slave);
-       }
 
        tlb_clear_slave(bond, slave, 0);
 
@@ -1661,9 +1655,8 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
 {
        struct slave *swap_slave;
 
-       if (bond->curr_active_slave == new_slave) {
+       if (bond->curr_active_slave == new_slave)
                return;
-       }
 
        if (bond->curr_active_slave && bond->alb_info.primary_is_promisc) {
                dev_set_promiscuity(bond->curr_active_slave->dev, -1);
@@ -1672,11 +1665,10 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
        }
 
        swap_slave = bond->curr_active_slave;
-       bond->curr_active_slave = new_slave;
+       rcu_assign_pointer(bond->curr_active_slave, new_slave);
 
-       if (!new_slave || (bond->slave_cnt == 0)) {
+       if (!new_slave || list_empty(&bond->slave_list))
                return;
-       }
 
        /* set the new curr_active_slave to the bonds mac address
         * i.e. swap mac addresses of old curr_active_slave and new curr_active_slave
@@ -1689,9 +1681,8 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
         * ignored so we can mess with their MAC addresses without
         * fear of interference from transmit activity.
         */
-       if (swap_slave) {
+       if (swap_slave)
                tlb_clear_slave(bond, swap_slave, 1);
-       }
        tlb_clear_slave(bond, new_slave, 1);
 
        write_unlock_bh(&bond->curr_slave_lock);
index 07f257d44a1e00a67b84a58685c5a2e490ce5ca8..1d37a9657e0d20201e9699a7a6253afe68af5154 100644 (file)
@@ -77,6 +77,7 @@
 #include <net/net_namespace.h>
 #include <net/netns/generic.h>
 #include <net/pkt_sched.h>
+#include <linux/rculist.h>
 #include "bonding.h"
 #include "bond_3ad.h"
 #include "bond_alb.h"
@@ -106,7 +107,7 @@ static char *arp_ip_target[BOND_MAX_ARP_TARGETS];
 static char *arp_validate;
 static char *arp_all_targets;
 static char *fail_over_mac;
-static int all_slaves_active = 0;
+static int all_slaves_active;
 static struct bond_params bonding_defaults;
 static int resend_igmp = BOND_DEFAULT_RESEND_IGMP;
 
@@ -273,7 +274,7 @@ const char *bond_mode_name(int mode)
                [BOND_MODE_ALB] = "adaptive load balancing",
        };
 
-       if (mode < 0 || mode > BOND_MODE_ALB)
+       if (mode < BOND_MODE_ROUNDROBIN || mode > BOND_MODE_ALB)
                return "unknown";
 
        return names[mode];
@@ -441,10 +442,10 @@ static int bond_vlan_rx_add_vid(struct net_device *bond_dev,
                                __be16 proto, u16 vid)
 {
        struct bonding *bond = netdev_priv(bond_dev);
-       struct slave *slave, *stop_at;
-       int i, res;
+       struct slave *slave;
+       int res;
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                res = vlan_vid_add(slave->dev, proto, vid);
                if (res)
                        goto unwind;
@@ -461,8 +462,7 @@ static int bond_vlan_rx_add_vid(struct net_device *bond_dev,
 
 unwind:
        /* unwind from head to the slave that failed */
-       stop_at = slave;
-       bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at)
+       bond_for_each_slave_continue_reverse(bond, slave)
                vlan_vid_del(slave->dev, proto, vid);
 
        return res;
@@ -478,9 +478,9 @@ static int bond_vlan_rx_kill_vid(struct net_device *bond_dev,
 {
        struct bonding *bond = netdev_priv(bond_dev);
        struct slave *slave;
-       int i, res;
+       int res;
 
-       bond_for_each_slave(bond, slave, i)
+       bond_for_each_slave(bond, slave)
                vlan_vid_del(slave->dev, proto, vid);
 
        res = bond_del_vlan(bond, vid);
@@ -532,15 +532,14 @@ static void bond_del_vlans_from_slave(struct bonding *bond,
 static int bond_set_carrier(struct bonding *bond)
 {
        struct slave *slave;
-       int i;
 
-       if (bond->slave_cnt == 0)
+       if (list_empty(&bond->slave_list))
                goto down;
 
        if (bond->params.mode == BOND_MODE_8023AD)
                return bond_3ad_set_carrier(bond);
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                if (slave->link == BOND_LINK_UP) {
                        if (!netif_carrier_ok(bond->dev)) {
                                netif_carrier_on(bond->dev);
@@ -681,8 +680,8 @@ static int bond_set_promiscuity(struct bonding *bond, int inc)
                }
        } else {
                struct slave *slave;
-               int i;
-               bond_for_each_slave(bond, slave, i) {
+
+               bond_for_each_slave(bond, slave) {
                        err = dev_set_promiscuity(slave->dev, inc);
                        if (err)
                                return err;
@@ -705,8 +704,8 @@ static int bond_set_allmulti(struct bonding *bond, int inc)
                }
        } else {
                struct slave *slave;
-               int i;
-               bond_for_each_slave(bond, slave, i) {
+
+               bond_for_each_slave(bond, slave) {
                        err = dev_set_allmulti(slave->dev, inc);
                        if (err)
                                return err;
@@ -715,15 +714,6 @@ static int bond_set_allmulti(struct bonding *bond, int inc)
        return err;
 }
 
-static void __bond_resend_igmp_join_requests(struct net_device *dev)
-{
-       struct in_device *in_dev;
-
-       in_dev = __in_dev_get_rcu(dev);
-       if (in_dev)
-               ip_mc_rejoin_groups(in_dev);
-}
-
 /*
  * Retrieve the list of registered multicast addresses for the bonding
  * device and retransmit an IGMP JOIN request to the current active
@@ -731,33 +721,12 @@ static void __bond_resend_igmp_join_requests(struct net_device *dev)
  */
 static void bond_resend_igmp_join_requests(struct bonding *bond)
 {
-       struct net_device *bond_dev, *vlan_dev, *upper_dev;
-       struct vlan_entry *vlan;
-
-       read_lock(&bond->lock);
-       rcu_read_lock();
-
-       bond_dev = bond->dev;
-
-       /* rejoin all groups on bond device */
-       __bond_resend_igmp_join_requests(bond_dev);
-
-       /*
-        * if bond is enslaved to a bridge,
-        * then rejoin all groups on its master
-        */
-       upper_dev = netdev_master_upper_dev_get_rcu(bond_dev);
-       if (upper_dev && upper_dev->priv_flags & IFF_EBRIDGE)
-               __bond_resend_igmp_join_requests(upper_dev);
-
-       /* rejoin all groups on vlan devices */
-       list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
-               vlan_dev = __vlan_find_dev_deep(bond_dev, htons(ETH_P_8021Q),
-                                               vlan->vlan_id);
-               if (vlan_dev)
-                       __bond_resend_igmp_join_requests(vlan_dev);
+       if (!rtnl_trylock()) {
+               queue_delayed_work(bond->wq, &bond->mcast_work, 1);
+               return;
        }
-       rcu_read_unlock();
+       call_netdevice_notifiers(NETDEV_RESEND_IGMP, bond->dev);
+       rtnl_unlock();
 
        /* We use curr_slave_lock to protect against concurrent access to
         * igmp_retrans from multiple running instances of this function and
@@ -769,7 +738,6 @@ static void bond_resend_igmp_join_requests(struct bonding *bond)
                queue_delayed_work(bond->wq, &bond->mcast_work, HZ/5);
        }
        write_unlock_bh(&bond->curr_slave_lock);
-       read_unlock(&bond->lock);
 }
 
 static void bond_resend_igmp_join_requests_delayed(struct work_struct *work)
@@ -966,9 +934,8 @@ static struct slave *bond_find_best_slave(struct bonding *bond)
        new_active = bond->curr_active_slave;
 
        if (!new_active) { /* there were no active slaves left */
-               if (bond->slave_cnt > 0)   /* found one slave */
-                       new_active = bond->first_slave;
-               else
+               new_active = bond_first_slave(bond);
+               if (!new_active)
                        return NULL; /* still no slave, return NULL */
        }
 
@@ -1071,7 +1038,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
                if (new_active)
                        bond_set_slave_active_flags(new_active);
        } else {
-               bond->curr_active_slave = new_active;
+               rcu_assign_pointer(bond->curr_active_slave, new_active);
        }
 
        if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) {
@@ -1115,7 +1082,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
            ((USES_PRIMARY(bond->params.mode) && new_active) ||
             bond->params.mode == BOND_MODE_ROUNDROBIN)) {
                bond->igmp_retrans = bond->params.resend_igmp;
-               queue_delayed_work(bond->wq, &bond->mcast_work, 0);
+               queue_delayed_work(bond->wq, &bond->mcast_work, 1);
        }
 }
 
@@ -1161,17 +1128,7 @@ void bond_select_active_slave(struct bonding *bond)
  */
 static void bond_attach_slave(struct bonding *bond, struct slave *new_slave)
 {
-       if (bond->first_slave == NULL) { /* attaching the first slave */
-               new_slave->next = new_slave;
-               new_slave->prev = new_slave;
-               bond->first_slave = new_slave;
-       } else {
-               new_slave->next = bond->first_slave;
-               new_slave->prev = bond->first_slave->prev;
-               new_slave->next->prev = new_slave;
-               new_slave->prev->next = new_slave;
-       }
-
+       list_add_tail_rcu(&new_slave->list, &bond->slave_list);
        bond->slave_cnt++;
 }
 
@@ -1187,22 +1144,7 @@ static void bond_attach_slave(struct bonding *bond, struct slave *new_slave)
  */
 static void bond_detach_slave(struct bonding *bond, struct slave *slave)
 {
-       if (slave->next)
-               slave->next->prev = slave->prev;
-
-       if (slave->prev)
-               slave->prev->next = slave->next;
-
-       if (bond->first_slave == slave) { /* slave is the first slave */
-               if (bond->slave_cnt > 1) { /* there are more slave */
-                       bond->first_slave = slave->next;
-               } else {
-                       bond->first_slave = NULL; /* slave was the last one */
-               }
-       }
-
-       slave->next = NULL;
-       slave->prev = NULL;
+       list_del_rcu(&slave->list);
        bond->slave_cnt--;
 }
 
@@ -1249,47 +1191,31 @@ static void bond_poll_controller(struct net_device *bond_dev)
 {
 }
 
-static void __bond_netpoll_cleanup(struct bonding *bond)
+static void bond_netpoll_cleanup(struct net_device *bond_dev)
 {
+       struct bonding *bond = netdev_priv(bond_dev);
        struct slave *slave;
-       int i;
 
-       bond_for_each_slave(bond, slave, i)
+       bond_for_each_slave(bond, slave)
                if (IS_UP(slave->dev))
                        slave_disable_netpoll(slave);
 }
-static void bond_netpoll_cleanup(struct net_device *bond_dev)
-{
-       struct bonding *bond = netdev_priv(bond_dev);
-
-       read_lock(&bond->lock);
-       __bond_netpoll_cleanup(bond);
-       read_unlock(&bond->lock);
-}
 
 static int bond_netpoll_setup(struct net_device *dev, struct netpoll_info *ni, gfp_t gfp)
 {
        struct bonding *bond = netdev_priv(dev);
        struct slave *slave;
-       int i, err = 0;
+       int err = 0;
 
-       read_lock(&bond->lock);
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                err = slave_enable_netpoll(slave);
                if (err) {
-                       __bond_netpoll_cleanup(bond);
+                       bond_netpoll_cleanup(dev);
                        break;
                }
        }
-       read_unlock(&bond->lock);
        return err;
 }
-
-static struct netpoll_info *bond_netpoll_info(struct bonding *bond)
-{
-       return bond->dev->npinfo;
-}
-
 #else
 static inline int slave_enable_netpoll(struct slave *slave)
 {
@@ -1311,11 +1237,10 @@ static netdev_features_t bond_fix_features(struct net_device *dev,
        struct slave *slave;
        struct bonding *bond = netdev_priv(dev);
        netdev_features_t mask;
-       int i;
 
        read_lock(&bond->lock);
 
-       if (!bond->first_slave) {
+       if (list_empty(&bond->slave_list)) {
                /* Disable adding VLANs to empty bond. But why? --mq */
                features |= NETIF_F_VLAN_CHALLENGED;
                goto out;
@@ -1325,7 +1250,7 @@ static netdev_features_t bond_fix_features(struct net_device *dev,
        features &= ~NETIF_F_ONE_FOR_ALL;
        features |= NETIF_F_ALL_FOR_ALL;
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                features = netdev_increment_features(features,
                                                     slave->dev->features,
                                                     mask);
@@ -1349,15 +1274,14 @@ static void bond_compute_features(struct bonding *bond)
        unsigned short max_hard_header_len = ETH_HLEN;
        unsigned int gso_max_size = GSO_MAX_SIZE;
        u16 gso_max_segs = GSO_MAX_SEGS;
-       int i;
        unsigned int flags, dst_release_flag = IFF_XMIT_DST_RELEASE;
 
        read_lock(&bond->lock);
 
-       if (!bond->first_slave)
+       if (list_empty(&bond->slave_list))
                goto done;
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                vlan_features = netdev_increment_features(vlan_features,
                        slave->dev->vlan_features, BOND_VLAN_FEATURES);
 
@@ -1545,7 +1469,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
         * bond ether type mutual exclusion - don't allow slaves of dissimilar
         * ether type (eg ARPHRD_ETHER and ARPHRD_INFINIBAND) share the same bond
         */
-       if (bond->slave_cnt == 0) {
+       if (list_empty(&bond->slave_list)) {
                if (bond_dev->type != slave_dev->type) {
                        pr_debug("%s: change device type from %d to %d\n",
                                 bond_dev->name,
@@ -1584,7 +1508,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
        }
 
        if (slave_ops->ndo_set_mac_address == NULL) {
-               if (bond->slave_cnt == 0) {
+               if (list_empty(&bond->slave_list)) {
                        pr_warning("%s: Warning: The first slave device specified does not support setting the MAC address. Setting fail_over_mac to active.",
                                   bond_dev->name);
                        bond->params.fail_over_mac = BOND_FOM_ACTIVE;
@@ -1600,7 +1524,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 
        /* If this is the first slave, then we need to set the master's hardware
         * address to be the same as the slave's. */
-       if (!bond->slave_cnt && bond->dev->addr_assign_type == NET_ADDR_RANDOM)
+       if (list_empty(&bond->slave_list) &&
+           bond->dev->addr_assign_type == NET_ADDR_RANDOM)
                bond_set_dev_addr(bond->dev, slave_dev);
 
        new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL);
@@ -1608,7 +1533,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                res = -ENOMEM;
                goto err_undo_flags;
        }
-
+       INIT_LIST_HEAD(&new_slave->list);
        /*
         * Set the new_slave's queue_id to be zero.  Queue ID mapping
         * is set via sysfs or module option if desired.
@@ -1794,15 +1719,18 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                 */
                bond_set_slave_inactive_flags(new_slave);
                /* if this is the first slave */
-               if (bond->slave_cnt == 1) {
+               if (bond_first_slave(bond) == new_slave) {
                        SLAVE_AD_INFO(new_slave).id = 1;
                        /* Initialize AD with the number of times that the AD timer is called in 1 second
                         * can be called only after the mac address of the bond is set
                         */
                        bond_3ad_initialize(bond, 1000/AD_TIMER_INTERVAL);
                } else {
+                       struct slave *prev_slave;
+
+                       prev_slave = bond_prev_slave(bond, new_slave);
                        SLAVE_AD_INFO(new_slave).id =
-                               SLAVE_AD_INFO(new_slave->prev).id + 1;
+                               SLAVE_AD_INFO(prev_slave).id + 1;
                }
 
                bond_3ad_bind_slave(new_slave);
@@ -1824,7 +1752,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                 * so we can change it without calling change_active_interface()
                 */
                if (!bond->curr_active_slave && new_slave->link == BOND_LINK_UP)
-                       bond->curr_active_slave = new_slave;
+                       rcu_assign_pointer(bond->curr_active_slave, new_slave);
 
                break;
        } /* switch(bond_mode) */
@@ -1834,7 +1762,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
        bond_set_carrier(bond);
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
-       slave_dev->npinfo = bond_netpoll_info(bond);
+       slave_dev->npinfo = bond->dev->npinfo;
        if (slave_dev->npinfo) {
                if (slave_enable_netpoll(new_slave)) {
                        read_unlock(&bond->lock);
@@ -1921,7 +1849,7 @@ err_free:
 err_undo_flags:
        bond_compute_features(bond);
        /* Enslave of first slave has failed and we need to fix master's mac */
-       if (bond->slave_cnt == 0 &&
+       if (list_empty(&bond->slave_list) &&
            ether_addr_equal(bond_dev->dev_addr, slave_dev->dev_addr))
                eth_hw_addr_random(bond_dev);
 
@@ -1977,15 +1905,6 @@ static int __bond_release_one(struct net_device *bond_dev,
        netdev_rx_handler_unregister(slave_dev);
        write_lock_bh(&bond->lock);
 
-       if (!all && !bond->params.fail_over_mac) {
-               if (ether_addr_equal(bond_dev->dev_addr, slave->perm_hwaddr) &&
-                   bond->slave_cnt > 1)
-                       pr_warning("%s: Warning: the permanent HWaddr of %s - %pM - is still in use by %s. Set the HWaddr of %s to a different address to avoid conflicts.\n",
-                                  bond_dev->name, slave_dev->name,
-                                  slave->perm_hwaddr,
-                                  bond_dev->name, slave_dev->name);
-       }
-
        /* Inform AD package of unbinding of slave. */
        if (bond->params.mode == BOND_MODE_8023AD) {
                /* must be called before the slave is
@@ -2006,6 +1925,15 @@ static int __bond_release_one(struct net_device *bond_dev,
        /* release the slave from its bond */
        bond_detach_slave(bond, slave);
 
+       if (!all && !bond->params.fail_over_mac) {
+               if (ether_addr_equal(bond_dev->dev_addr, slave->perm_hwaddr) &&
+                   !list_empty(&bond->slave_list))
+                       pr_warn("%s: Warning: the permanent HWaddr of %s - %pM - is still in use by %s. Set the HWaddr of %s to a different address to avoid conflicts.\n",
+                                  bond_dev->name, slave_dev->name,
+                                  slave->perm_hwaddr,
+                                  bond_dev->name, slave_dev->name);
+       }
+
        if (bond->primary_slave == slave)
                bond->primary_slave = NULL;
 
@@ -2024,7 +1952,7 @@ static int __bond_release_one(struct net_device *bond_dev,
        }
 
        if (all) {
-               bond->curr_active_slave = NULL;
+               rcu_assign_pointer(bond->curr_active_slave, NULL);
        } else if (oldcurrent == slave) {
                /*
                 * Note that we hold RTNL over this sequence, so there
@@ -2042,7 +1970,7 @@ static int __bond_release_one(struct net_device *bond_dev,
                write_lock_bh(&bond->lock);
        }
 
-       if (bond->slave_cnt == 0) {
+       if (list_empty(&bond->slave_list)) {
                bond_set_carrier(bond);
                eth_hw_addr_random(bond_dev);
 
@@ -2056,8 +1984,9 @@ static int __bond_release_one(struct net_device *bond_dev,
 
        write_unlock_bh(&bond->lock);
        unblock_netpoll_tx();
+       synchronize_rcu();
 
-       if (bond->slave_cnt == 0) {
+       if (list_empty(&bond->slave_list)) {
                call_netdevice_notifiers(NETDEV_CHANGEADDR, bond->dev);
                call_netdevice_notifiers(NETDEV_RELEASE, bond->dev);
        }
@@ -2128,7 +2057,7 @@ static int  bond_release_and_destroy(struct net_device *bond_dev,
        int ret;
 
        ret = bond_release(bond_dev, slave_dev);
-       if ((ret == 0) && (bond->slave_cnt == 0)) {
+       if (ret == 0 && list_empty(&bond->slave_list)) {
                bond_dev->priv_flags |= IFF_DISABLE_NETPOLL;
                pr_info("%s: destroying bond %s.\n",
                        bond_dev->name, bond_dev->name);
@@ -2165,23 +2094,19 @@ static int bond_ioctl_change_active(struct net_device *bond_dev, struct net_devi
 
        read_lock(&bond->lock);
 
-       read_lock(&bond->curr_slave_lock);
        old_active = bond->curr_active_slave;
-       read_unlock(&bond->curr_slave_lock);
-
        new_active = bond_get_slave_by_dev(bond, slave_dev);
-
        /*
         * Changing to the current active: do nothing; return success.
         */
-       if (new_active && (new_active == old_active)) {
+       if (new_active && new_active == old_active) {
                read_unlock(&bond->lock);
                return 0;
        }
 
-       if ((new_active) &&
-           (old_active) &&
-           (new_active->link == BOND_LINK_UP) &&
+       if (new_active &&
+           old_active &&
+           new_active->link == BOND_LINK_UP &&
            IS_UP(new_active->dev)) {
                block_netpoll_tx();
                write_lock_bh(&bond->curr_slave_lock);
@@ -2213,13 +2138,12 @@ static int bond_info_query(struct net_device *bond_dev, struct ifbond *info)
 static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *info)
 {
        struct bonding *bond = netdev_priv(bond_dev);
+       int i = 0, res = -ENODEV;
        struct slave *slave;
-       int i, res = -ENODEV;
 
        read_lock(&bond->lock);
-
-       bond_for_each_slave(bond, slave, i) {
-               if (i == (int)info->slave_id) {
+       bond_for_each_slave(bond, slave) {
+               if (i++ == (int)info->slave_id) {
                        res = 0;
                        strcpy(info->slave_name, slave->dev->name);
                        info->link = slave->link;
@@ -2228,7 +2152,6 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in
                        break;
                }
        }
-
        read_unlock(&bond->lock);
 
        return res;
@@ -2239,13 +2162,13 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in
 
 static int bond_miimon_inspect(struct bonding *bond)
 {
+       int link_state, commit = 0;
        struct slave *slave;
-       int i, link_state, commit = 0;
        bool ignore_updelay;
 
        ignore_updelay = !bond->curr_active_slave ? true : false;
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                slave->new_link = BOND_LINK_NOCHANGE;
 
                link_state = bond_check_dev_link(bond, slave->dev, 0);
@@ -2340,9 +2263,8 @@ static int bond_miimon_inspect(struct bonding *bond)
 static void bond_miimon_commit(struct bonding *bond)
 {
        struct slave *slave;
-       int i;
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                switch (slave->new_link) {
                case BOND_LINK_NOCHANGE:
                        continue;
@@ -2447,7 +2369,7 @@ void bond_mii_monitor(struct work_struct *work)
 
        delay = msecs_to_jiffies(bond->params.miimon);
 
-       if (bond->slave_cnt == 0)
+       if (list_empty(&bond->slave_list))
                goto re_arm;
 
        should_notify_peers = bond_should_notify_peers(bond);
@@ -2727,20 +2649,16 @@ void bond_loadbalance_arp_mon(struct work_struct *work)
        struct slave *slave, *oldcurrent;
        int do_failover = 0;
        int delta_in_ticks, extra_ticks;
-       int i;
 
        read_lock(&bond->lock);
 
        delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval);
        extra_ticks = delta_in_ticks / 2;
 
-       if (bond->slave_cnt == 0)
+       if (list_empty(&bond->slave_list))
                goto re_arm;
 
-       read_lock(&bond->curr_slave_lock);
        oldcurrent = bond->curr_active_slave;
-       read_unlock(&bond->curr_slave_lock);
-
        /* see if any of the previous devices are up now (i.e. they have
         * xmt and rcv traffic). the curr_active_slave does not come into
         * the picture unless it is null. also, slave->jiffies is not needed
@@ -2749,7 +2667,7 @@ void bond_loadbalance_arp_mon(struct work_struct *work)
         * TODO: what about up/down delay in arp mode? it wasn't here before
         *       so it can wait
         */
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                unsigned long trans_start = dev_trans_start(slave->dev);
 
                if (slave->link != BOND_LINK_UP) {
@@ -2846,10 +2764,10 @@ re_arm:
  */
 static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks)
 {
-       struct slave *slave;
-       int i, commit = 0;
        unsigned long trans_start;
+       struct slave *slave;
        int extra_ticks;
+       int commit = 0;
 
        /* All the time comparisons below need some extra time. Otherwise, on
         * fast networks the ARP probe/reply may arrive within the same jiffy
@@ -2858,7 +2776,7 @@ static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks)
         */
        extra_ticks = delta_in_ticks / 2;
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                slave->new_link = BOND_LINK_NOCHANGE;
 
                if (slave->link != BOND_LINK_UP) {
@@ -2937,11 +2855,10 @@ static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks)
  */
 static void bond_ab_arp_commit(struct bonding *bond, int delta_in_ticks)
 {
-       struct slave *slave;
-       int i;
        unsigned long trans_start;
+       struct slave *slave;
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                switch (slave->new_link) {
                case BOND_LINK_NOCHANGE:
                        continue;
@@ -3014,7 +2931,7 @@ do_failover:
  */
 static void bond_ab_arp_probe(struct bonding *bond)
 {
-       struct slave *slave;
+       struct slave *slave, *next_slave;
        int i;
 
        read_lock(&bond->curr_slave_lock);
@@ -3038,7 +2955,7 @@ static void bond_ab_arp_probe(struct bonding *bond)
         */
 
        if (!bond->current_arp_slave) {
-               bond->current_arp_slave = bond->first_slave;
+               bond->current_arp_slave = bond_first_slave(bond);
                if (!bond->current_arp_slave)
                        return;
        }
@@ -3046,7 +2963,8 @@ static void bond_ab_arp_probe(struct bonding *bond)
        bond_set_slave_inactive_flags(bond->current_arp_slave);
 
        /* search for next candidate */
-       bond_for_each_slave_from(bond, slave, i, bond->current_arp_slave->next) {
+       next_slave = bond_next_slave(bond, bond->current_arp_slave);
+       bond_for_each_slave_from(bond, slave, i, next_slave) {
                if (IS_UP(slave->dev)) {
                        slave->link = BOND_LINK_BACK;
                        bond_set_slave_active_flags(slave);
@@ -3087,7 +3005,7 @@ void bond_activebackup_arp_mon(struct work_struct *work)
 
        delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval);
 
-       if (bond->slave_cnt == 0)
+       if (list_empty(&bond->slave_list))
                goto re_arm;
 
        should_notify_peers = bond_should_notify_peers(bond);
@@ -3234,6 +3152,10 @@ static int bond_slave_netdev_event(unsigned long event,
        case NETDEV_FEAT_CHANGE:
                bond_compute_features(bond);
                break;
+       case NETDEV_RESEND_IGMP:
+               /* Propagate to master device */
+               call_netdevice_notifiers(event, slave->bond->dev);
+               break;
        default:
                break;
        }
@@ -3403,13 +3325,12 @@ static int bond_open(struct net_device *bond_dev)
 {
        struct bonding *bond = netdev_priv(bond_dev);
        struct slave *slave;
-       int i;
 
        /* reset slave->backup and slave->inactive */
        read_lock(&bond->lock);
-       if (bond->slave_cnt > 0) {
+       if (!list_empty(&bond->slave_list)) {
                read_lock(&bond->curr_slave_lock);
-               bond_for_each_slave(bond, slave, i) {
+               bond_for_each_slave(bond, slave) {
                        if ((bond->params.mode == BOND_MODE_ACTIVEBACKUP)
                                && (slave != bond->curr_active_slave)) {
                                bond_set_slave_inactive_flags(slave);
@@ -3477,13 +3398,11 @@ static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev,
        struct bonding *bond = netdev_priv(bond_dev);
        struct rtnl_link_stats64 temp;
        struct slave *slave;
-       int i;
 
        memset(stats, 0, sizeof(*stats));
 
        read_lock_bh(&bond->lock);
-
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                const struct rtnl_link_stats64 *sstats =
                        dev_get_stats(slave->dev, &temp);
 
@@ -3513,7 +3432,6 @@ static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev,
                stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors;
                stats->tx_window_errors += sstats->tx_window_errors;
        }
-
        read_unlock_bh(&bond->lock);
 
        return stats;
@@ -3652,7 +3570,6 @@ static void bond_set_rx_mode(struct net_device *bond_dev)
 {
        struct bonding *bond = netdev_priv(bond_dev);
        struct slave *slave;
-       int i;
 
        read_lock(&bond->lock);
 
@@ -3665,7 +3582,7 @@ static void bond_set_rx_mode(struct net_device *bond_dev)
                }
                read_unlock(&bond->curr_slave_lock);
        } else {
-               bond_for_each_slave(bond, slave, i) {
+               bond_for_each_slave(bond, slave) {
                        dev_uc_sync_multiple(slave->dev, bond_dev);
                        dev_mc_sync_multiple(slave->dev, bond_dev);
                }
@@ -3677,16 +3594,15 @@ static void bond_set_rx_mode(struct net_device *bond_dev)
 static int bond_neigh_init(struct neighbour *n)
 {
        struct bonding *bond = netdev_priv(n->dev);
-       struct slave *slave = bond->first_slave;
        const struct net_device_ops *slave_ops;
        struct neigh_parms parms;
+       struct slave *slave;
        int ret;
 
+       slave = bond_first_slave(bond);
        if (!slave)
                return 0;
-
        slave_ops = slave->dev->netdev_ops;
-
        if (!slave_ops->ndo_neigh_setup)
                return 0;
 
@@ -3729,9 +3645,8 @@ static int bond_neigh_setup(struct net_device *dev,
 static int bond_change_mtu(struct net_device *bond_dev, int new_mtu)
 {
        struct bonding *bond = netdev_priv(bond_dev);
-       struct slave *slave, *stop_at;
+       struct slave *slave;
        int res = 0;
-       int i;
 
        pr_debug("bond=%p, name=%s, new_mtu=%d\n", bond,
                 (bond_dev ? bond_dev->name : "None"), new_mtu);
@@ -3751,10 +3666,10 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu)
         * call to the base driver.
         */
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                pr_debug("s %p s->p %p c_m %p\n",
                         slave,
-                        slave->prev,
+                        bond_prev_slave(bond, slave),
                         slave->dev->netdev_ops->ndo_change_mtu);
 
                res = dev_set_mtu(slave->dev, new_mtu);
@@ -3779,8 +3694,7 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu)
 
 unwind:
        /* unwind from head to the slave that failed */
-       stop_at = slave;
-       bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) {
+       bond_for_each_slave_continue_reverse(bond, slave) {
                int tmp_res;
 
                tmp_res = dev_set_mtu(slave->dev, bond_dev->mtu);
@@ -3804,9 +3718,8 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr)
 {
        struct bonding *bond = netdev_priv(bond_dev);
        struct sockaddr *sa = addr, tmp_sa;
-       struct slave *slave, *stop_at;
+       struct slave *slave;
        int res = 0;
-       int i;
 
        if (bond->params.mode == BOND_MODE_ALB)
                return bond_alb_set_mac_address(bond_dev, addr);
@@ -3839,7 +3752,7 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr)
         * call to the base driver.
         */
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                const struct net_device_ops *slave_ops = slave->dev->netdev_ops;
                pr_debug("slave %p %s\n", slave, slave->dev->name);
 
@@ -3871,8 +3784,7 @@ unwind:
        tmp_sa.sa_family = bond_dev->type;
 
        /* unwind from head to the slave that failed */
-       stop_at = slave;
-       bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) {
+       bond_for_each_slave_continue_reverse(bond, slave) {
                int tmp_res;
 
                tmp_res = dev_set_mac_address(slave->dev, &tmp_sa);
@@ -3885,12 +3797,50 @@ unwind:
        return res;
 }
 
+/**
+ * bond_xmit_slave_id - transmit skb through slave with slave_id
+ * @bond: bonding device that is transmitting
+ * @skb: buffer to transmit
+ * @slave_id: slave id up to slave_cnt-1 through which to transmit
+ *
+ * This function tries to transmit through slave with slave_id but in case
+ * it fails, it tries to find the first available slave for transmission.
+ * The skb is consumed in all cases, thus the function is void.
+ */
+void bond_xmit_slave_id(struct bonding *bond, struct sk_buff *skb, int slave_id)
+{
+       struct slave *slave;
+       int i = slave_id;
+
+       /* Here we start from the slave with slave_id */
+       bond_for_each_slave_rcu(bond, slave) {
+               if (--i < 0) {
+                       if (slave_can_tx(slave)) {
+                               bond_dev_queue_xmit(bond, skb, slave->dev);
+                               return;
+                       }
+               }
+       }
+
+       /* Here we start from the first slave up to slave_id */
+       i = slave_id;
+       bond_for_each_slave_rcu(bond, slave) {
+               if (--i < 0)
+                       break;
+               if (slave_can_tx(slave)) {
+                       bond_dev_queue_xmit(bond, skb, slave->dev);
+                       return;
+               }
+       }
+       /* no slave that can tx has been found */
+       kfree_skb(skb);
+}
+
 static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev)
 {
        struct bonding *bond = netdev_priv(bond_dev);
-       struct slave *slave, *start_at;
-       int i, slave_no, res = 1;
        struct iphdr *iph = ip_hdr(skb);
+       struct slave *slave;
 
        /*
         * Start with the curr_active_slave that joined the bond as the
@@ -3899,50 +3849,20 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev
         * send the join/membership reports.  The curr_active_slave found
         * will send all of this type of traffic.
         */
-       if ((iph->protocol == IPPROTO_IGMP) &&
-           (skb->protocol == htons(ETH_P_IP))) {
-
-               read_lock(&bond->curr_slave_lock);
-               slave = bond->curr_active_slave;
-               read_unlock(&bond->curr_slave_lock);
-
-               if (!slave)
-                       goto out;
+       if (iph->protocol == IPPROTO_IGMP && skb->protocol == htons(ETH_P_IP)) {
+               slave = rcu_dereference(bond->curr_active_slave);
+               if (slave && slave_can_tx(slave))
+                       bond_dev_queue_xmit(bond, skb, slave->dev);
+               else
+                       bond_xmit_slave_id(bond, skb, 0);
        } else {
-               /*
-                * Concurrent TX may collide on rr_tx_counter; we accept
-                * that as being rare enough not to justify using an
-                * atomic op here.
-                */
-               slave_no = bond->rr_tx_counter++ % bond->slave_cnt;
-
-               bond_for_each_slave(bond, slave, i) {
-                       slave_no--;
-                       if (slave_no < 0)
-                               break;
-               }
-       }
-
-       start_at = slave;
-       bond_for_each_slave_from(bond, slave, i, start_at) {
-               if (IS_UP(slave->dev) &&
-                   (slave->link == BOND_LINK_UP) &&
-                   bond_is_active_slave(slave)) {
-                       res = bond_dev_queue_xmit(bond, skb, slave->dev);
-                       break;
-               }
-       }
-
-out:
-       if (res) {
-               /* no suitable interface, frame not sent */
-               kfree_skb(skb);
+               bond_xmit_slave_id(bond, skb,
+                                  bond->rr_tx_counter++ % bond->slave_cnt);
        }
 
        return NETDEV_TX_OK;
 }
 
-
 /*
  * in active-backup mode, we know that bond->curr_active_slave is always valid if
  * the bond has a usable interface.
@@ -3950,18 +3870,12 @@ out:
 static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_dev)
 {
        struct bonding *bond = netdev_priv(bond_dev);
-       int res = 1;
-
-       read_lock(&bond->curr_slave_lock);
-
-       if (bond->curr_active_slave)
-               res = bond_dev_queue_xmit(bond, skb,
-                       bond->curr_active_slave->dev);
-
-       read_unlock(&bond->curr_slave_lock);
+       struct slave *slave;
 
-       if (res)
-               /* no suitable interface, frame not sent */
+       slave = rcu_dereference(bond->curr_active_slave);
+       if (slave)
+               bond_dev_queue_xmit(bond, skb, slave->dev);
+       else
                kfree_skb(skb);
 
        return NETDEV_TX_OK;
@@ -3975,87 +3889,39 @@ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_d
 static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev)
 {
        struct bonding *bond = netdev_priv(bond_dev);
-       struct slave *slave, *start_at;
-       int slave_no;
-       int i;
-       int res = 1;
-
-       slave_no = bond->xmit_hash_policy(skb, bond->slave_cnt);
-
-       bond_for_each_slave(bond, slave, i) {
-               slave_no--;
-               if (slave_no < 0)
-                       break;
-       }
-
-       start_at = slave;
-
-       bond_for_each_slave_from(bond, slave, i, start_at) {
-               if (IS_UP(slave->dev) &&
-                   (slave->link == BOND_LINK_UP) &&
-                   bond_is_active_slave(slave)) {
-                       res = bond_dev_queue_xmit(bond, skb, slave->dev);
-                       break;
-               }
-       }
 
-       if (res) {
-               /* no suitable interface, frame not sent */
-               kfree_skb(skb);
-       }
+       bond_xmit_slave_id(bond, skb,
+                          bond->xmit_hash_policy(skb, bond->slave_cnt));
 
        return NETDEV_TX_OK;
 }
 
-/*
- * in broadcast mode, we send everything to all usable interfaces.
- */
+/* in broadcast mode, we send everything to all usable interfaces. */
 static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev)
 {
        struct bonding *bond = netdev_priv(bond_dev);
-       struct slave *slave, *start_at;
-       struct net_device *tx_dev = NULL;
-       int i;
-       int res = 1;
-
-       read_lock(&bond->curr_slave_lock);
-       start_at = bond->curr_active_slave;
-       read_unlock(&bond->curr_slave_lock);
-
-       if (!start_at)
-               goto out;
+       struct slave *slave = NULL;
 
-       bond_for_each_slave_from(bond, slave, i, start_at) {
-               if (IS_UP(slave->dev) &&
-                   (slave->link == BOND_LINK_UP) &&
-                   bond_is_active_slave(slave)) {
-                       if (tx_dev) {
-                               struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
-                               if (!skb2) {
-                                       pr_err("%s: Error: bond_xmit_broadcast(): skb_clone() failed\n",
-                                              bond_dev->name);
-                                       continue;
-                               }
+       bond_for_each_slave_rcu(bond, slave) {
+               if (bond_is_last_slave(bond, slave))
+                       break;
+               if (IS_UP(slave->dev) && slave->link == BOND_LINK_UP) {
+                       struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
 
-                               res = bond_dev_queue_xmit(bond, skb2, tx_dev);
-                               if (res) {
-                                       kfree_skb(skb2);
-                                       continue;
-                               }
+                       if (!skb2) {
+                               pr_err("%s: Error: bond_xmit_broadcast(): skb_clone() failed\n",
+                                      bond_dev->name);
+                               continue;
                        }
-                       tx_dev = slave->dev;
+                       /* bond_dev_queue_xmit always returns 0 */
+                       bond_dev_queue_xmit(bond, skb2, slave->dev);
                }
        }
-
-       if (tx_dev)
-               res = bond_dev_queue_xmit(bond, skb, tx_dev);
-
-out:
-       if (res)
-               /* no suitable interface, frame not sent */
+       if (slave && IS_UP(slave->dev) && slave->link == BOND_LINK_UP)
+               bond_dev_queue_xmit(bond, skb, slave->dev);
+       else
                kfree_skb(skb);
 
-       /* frame sent to all suitable interfaces */
        return NETDEV_TX_OK;
 }
 
@@ -4083,15 +3949,15 @@ static void bond_set_xmit_hash_policy(struct bonding *bond)
 static inline int bond_slave_override(struct bonding *bond,
                                      struct sk_buff *skb)
 {
-       int i, res = 1;
        struct slave *slave = NULL;
        struct slave *check_slave;
+       int res = 1;
 
        if (!skb->queue_mapping)
                return 1;
 
        /* Find out if any slaves have the same mapping as this skb. */
-       bond_for_each_slave(bond, check_slave, i) {
+       bond_for_each_slave_rcu(bond, check_slave) {
                if (check_slave->queue_id == skb->queue_mapping) {
                        slave = check_slave;
                        break;
@@ -4176,14 +4042,12 @@ static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev)
        if (is_netpoll_tx_blocked(dev))
                return NETDEV_TX_BUSY;
 
-       read_lock(&bond->lock);
-
-       if (bond->slave_cnt)
+       rcu_read_lock();
+       if (!list_empty(&bond->slave_list))
                ret = __bond_start_xmit(skb, dev);
        else
                kfree_skb(skb);
-
-       read_unlock(&bond->lock);
+       rcu_read_unlock();
 
        return ret;
 }
@@ -4224,9 +4088,8 @@ static int bond_ethtool_get_settings(struct net_device *bond_dev,
                                     struct ethtool_cmd *ecmd)
 {
        struct bonding *bond = netdev_priv(bond_dev);
-       struct slave *slave;
-       int i;
        unsigned long speed = 0;
+       struct slave *slave;
 
        ecmd->duplex = DUPLEX_UNKNOWN;
        ecmd->port = PORT_OTHER;
@@ -4237,7 +4100,7 @@ static int bond_ethtool_get_settings(struct net_device *bond_dev,
         * this is an accurate maximum.
         */
        read_lock(&bond->lock);
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                if (SLAVE_IS_OK(slave)) {
                        if (slave->speed != SPEED_UNKNOWN)
                                speed += slave->speed;
@@ -4248,6 +4111,7 @@ static int bond_ethtool_get_settings(struct net_device *bond_dev,
        }
        ethtool_cmd_speed_set(ecmd, speed ? : SPEED_UNKNOWN);
        read_unlock(&bond->lock);
+
        return 0;
 }
 
@@ -4311,7 +4175,7 @@ static void bond_setup(struct net_device *bond_dev)
        /* initialize rwlocks */
        rwlock_init(&bond->lock);
        rwlock_init(&bond->curr_slave_lock);
-
+       INIT_LIST_HEAD(&bond->slave_list);
        bond->params = bonding_defaults;
 
        /* Initialize pointers */
@@ -4368,13 +4232,14 @@ static void bond_setup(struct net_device *bond_dev)
 static void bond_uninit(struct net_device *bond_dev)
 {
        struct bonding *bond = netdev_priv(bond_dev);
+       struct slave *slave, *tmp_slave;
        struct vlan_entry *vlan, *tmp;
 
        bond_netpoll_cleanup(bond_dev);
 
        /* Release the bonded slaves */
-       while (bond->first_slave != NULL)
-               __bond_release_one(bond_dev, bond->first_slave->dev, true);
+       list_for_each_entry_safe(slave, tmp_slave, &bond->slave_list, list)
+               __bond_release_one(bond_dev, slave->dev, true);
        pr_info("%s: released all slaves\n", bond_dev->name);
 
        list_del(&bond->bond_list);
index 4060d41f0ee7b15bc228b6bda9488a9e6cc9c821..20a6ee25bb63e42cdf89c0273d8e1afa30234f26 100644 (file)
@@ -12,7 +12,6 @@ static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos)
        struct bonding *bond = seq->private;
        loff_t off = 0;
        struct slave *slave;
-       int i;
 
        /* make sure the bond won't be taken away */
        rcu_read_lock();
@@ -21,10 +20,9 @@ static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos)
        if (*pos == 0)
                return SEQ_START_TOKEN;
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave)
                if (++off == *pos)
                        return slave;
-       }
 
        return NULL;
 }
@@ -36,11 +34,13 @@ static void *bond_info_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 
        ++*pos;
        if (v == SEQ_START_TOKEN)
-               return bond->first_slave;
+               return bond_first_slave(bond);
 
-       slave = slave->next;
+       if (bond_is_last_slave(bond, slave))
+               return NULL;
+       slave = bond_next_slave(bond, slave);
 
-       return (slave == bond->first_slave) ? NULL : slave;
+       return slave;
 }
 
 static void bond_info_seq_stop(struct seq_file *seq, void *v)
index dc36a3d7d9e983a15583260a572e6dac7451acb5..0f539de640dcb6f471378a5d44e47c0946a01d0c 100644 (file)
@@ -209,12 +209,12 @@ void bond_destroy_slave_symlinks(struct net_device *master,
 static ssize_t bonding_show_slaves(struct device *d,
                                   struct device_attribute *attr, char *buf)
 {
-       struct slave *slave;
-       int i, res = 0;
        struct bonding *bond = to_bond(d);
+       struct slave *slave;
+       int res = 0;
 
        read_lock(&bond->lock);
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                if (res > (PAGE_SIZE - IFNAMSIZ)) {
                        /* not enough space for another interface name */
                        if ((PAGE_SIZE - res) > 10)
@@ -227,6 +227,7 @@ static ssize_t bonding_show_slaves(struct device *d,
        read_unlock(&bond->lock);
        if (res)
                buf[res-1] = '\n'; /* eat the leftover space */
+
        return res;
 }
 
@@ -325,7 +326,7 @@ static ssize_t bonding_store_mode(struct device *d,
                goto out;
        }
 
-       if (bond->slave_cnt > 0) {
+       if (!list_empty(&bond->slave_list)) {
                pr_err("unable to update mode of %s because it has slaves.\n",
                        bond->dev->name);
                ret = -EPERM;
@@ -501,20 +502,25 @@ static ssize_t bonding_store_fail_over_mac(struct device *d,
                                           struct device_attribute *attr,
                                           const char *buf, size_t count)
 {
-       int new_value;
+       int new_value, ret = count;
        struct bonding *bond = to_bond(d);
 
-       if (bond->slave_cnt != 0) {
+       if (!rtnl_trylock())
+               return restart_syscall();
+
+       if (!list_empty(&bond->slave_list)) {
                pr_err("%s: Can't alter fail_over_mac with slaves in bond.\n",
                       bond->dev->name);
-               return -EPERM;
+               ret = -EPERM;
+               goto out;
        }
 
        new_value = bond_parse_parm(buf, fail_over_mac_tbl);
        if (new_value < 0) {
                pr_err("%s: Ignoring invalid fail_over_mac value %s.\n",
                       bond->dev->name, buf);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out;
        }
 
        bond->params.fail_over_mac = new_value;
@@ -522,7 +528,9 @@ static ssize_t bonding_store_fail_over_mac(struct device *d,
                bond->dev->name, fail_over_mac_tbl[new_value].modename,
                new_value);
 
-       return count;
+out:
+       rtnl_unlock();
+       return ret;
 }
 
 static DEVICE_ATTR(fail_over_mac, S_IRUGO | S_IWUSR,
@@ -661,7 +669,7 @@ static ssize_t bonding_store_arp_targets(struct device *d,
                         &newtarget);
                /* not to race with bond_arp_rcv */
                write_lock_bh(&bond->lock);
-               bond_for_each_slave(bond, slave, i)
+               bond_for_each_slave(bond, slave)
                        slave->target_last_arp_rx[ind] = jiffies;
                targets[ind] = newtarget;
                write_unlock_bh(&bond->lock);
@@ -687,7 +695,7 @@ static ssize_t bonding_store_arp_targets(struct device *d,
                        &newtarget);
 
                write_lock_bh(&bond->lock);
-               bond_for_each_slave(bond, slave, i) {
+               bond_for_each_slave(bond, slave) {
                        targets_rx = slave->target_last_arp_rx;
                        j = ind;
                        for (; (j < BOND_MAX_ARP_TARGETS-1) && targets[j+1]; j++)
@@ -1078,10 +1086,9 @@ static ssize_t bonding_store_primary(struct device *d,
                                     struct device_attribute *attr,
                                     const char *buf, size_t count)
 {
-       int i;
-       struct slave *slave;
        struct bonding *bond = to_bond(d);
        char ifname[IFNAMSIZ];
+       struct slave *slave;
 
        if (!rtnl_trylock())
                return restart_syscall();
@@ -1107,7 +1114,7 @@ static ssize_t bonding_store_primary(struct device *d,
                goto out;
        }
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                if (strncmp(slave->dev->name, ifname, IFNAMSIZ) == 0) {
                        pr_info("%s: Setting %s as primary slave.\n",
                                bond->dev->name, slave->dev->name);
@@ -1236,16 +1243,16 @@ static ssize_t bonding_show_active_slave(struct device *d,
                                         struct device_attribute *attr,
                                         char *buf)
 {
-       struct slave *curr;
        struct bonding *bond = to_bond(d);
+       struct slave *curr;
        int count = 0;
 
-       read_lock(&bond->curr_slave_lock);
-       curr = bond->curr_active_slave;
-       read_unlock(&bond->curr_slave_lock);
-
+       rcu_read_lock();
+       curr = rcu_dereference(bond->curr_active_slave);
        if (USES_PRIMARY(bond->params.mode) && curr)
                count = sprintf(buf, "%s\n", curr->dev->name);
+       rcu_read_unlock();
+
        return count;
 }
 
@@ -1253,16 +1260,14 @@ static ssize_t bonding_store_active_slave(struct device *d,
                                          struct device_attribute *attr,
                                          const char *buf, size_t count)
 {
-       int i;
-       struct slave *slave;
-       struct slave *old_active = NULL;
-       struct slave *new_active = NULL;
+       struct slave *slave, *old_active, *new_active;
        struct bonding *bond = to_bond(d);
        char ifname[IFNAMSIZ];
 
        if (!rtnl_trylock())
                return restart_syscall();
 
+       old_active = new_active = NULL;
        block_netpoll_tx();
        read_lock(&bond->lock);
        write_lock_bh(&bond->curr_slave_lock);
@@ -1279,12 +1284,12 @@ static ssize_t bonding_store_active_slave(struct device *d,
        if (!strlen(ifname) || buf[0] == '\n') {
                pr_info("%s: Clearing current active slave.\n",
                        bond->dev->name);
-               bond->curr_active_slave = NULL;
+               rcu_assign_pointer(bond->curr_active_slave, NULL);
                bond_select_active_slave(bond);
                goto out;
        }
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                if (strncmp(slave->dev->name, ifname, IFNAMSIZ) == 0) {
                        old_active = bond->curr_active_slave;
                        new_active = slave;
@@ -1295,8 +1300,7 @@ static ssize_t bonding_store_active_slave(struct device *d,
                                        bond->dev->name,
                                        slave->dev->name);
                                goto out;
-                       }
-                       else {
+                       } else {
                                if ((new_active) &&
                                    (old_active) &&
                                    (new_active->link == BOND_LINK_UP) &&
@@ -1307,8 +1311,7 @@ static ssize_t bonding_store_active_slave(struct device *d,
                                                slave->dev->name);
                                        bond_change_active_slave(bond,
                                                                 new_active);
-                               }
-                               else {
+                               } else {
                                        pr_info("%s: Could not set %s as"
                                                " active slave; either %s is"
                                                " down or the link is down.\n",
@@ -1344,14 +1347,9 @@ static ssize_t bonding_show_mii_status(struct device *d,
                                       struct device_attribute *attr,
                                       char *buf)
 {
-       struct slave *curr;
        struct bonding *bond = to_bond(d);
 
-       read_lock(&bond->curr_slave_lock);
-       curr = bond->curr_active_slave;
-       read_unlock(&bond->curr_slave_lock);
-
-       return sprintf(buf, "%s\n", curr ? "up" : "down");
+       return sprintf(buf, "%s\n", bond->curr_active_slave ? "up" : "down");
 }
 static DEVICE_ATTR(mii_status, S_IRUGO, bonding_show_mii_status, NULL);
 
@@ -1470,15 +1468,15 @@ static ssize_t bonding_show_queue_id(struct device *d,
                                     struct device_attribute *attr,
                                     char *buf)
 {
-       struct slave *slave;
-       int i, res = 0;
        struct bonding *bond = to_bond(d);
+       struct slave *slave;
+       int res = 0;
 
        if (!rtnl_trylock())
                return restart_syscall();
 
        read_lock(&bond->lock);
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                if (res > (PAGE_SIZE - IFNAMSIZ - 6)) {
                        /* not enough space for another interface_name:queue_id pair */
                        if ((PAGE_SIZE - res) > 10)
@@ -1493,6 +1491,7 @@ static ssize_t bonding_show_queue_id(struct device *d,
        if (res)
                buf[res-1] = '\n'; /* eat the leftover space */
        rtnl_unlock();
+
        return res;
 }
 
@@ -1507,7 +1506,7 @@ static ssize_t bonding_store_queue_id(struct device *d,
        struct slave *slave, *update_slave;
        struct bonding *bond = to_bond(d);
        u16 qid;
-       int i, ret = count;
+       int ret = count;
        char *delim;
        struct net_device *sdev = NULL;
 
@@ -1542,7 +1541,7 @@ static ssize_t bonding_store_queue_id(struct device *d,
 
        /* Search for thes slave and check for duplicate qids */
        update_slave = NULL;
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                if (sdev == slave->dev)
                        /*
                         * We don't need to check the matching
@@ -1594,8 +1593,8 @@ static ssize_t bonding_store_slaves_active(struct device *d,
                                           struct device_attribute *attr,
                                           const char *buf, size_t count)
 {
-       int i, new_value, ret = count;
        struct bonding *bond = to_bond(d);
+       int new_value, ret = count;
        struct slave *slave;
 
        if (sscanf(buf, "%d", &new_value) != 1) {
@@ -1618,7 +1617,7 @@ static ssize_t bonding_store_slaves_active(struct device *d,
        }
 
        read_lock(&bond->lock);
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                if (!bond_is_active_slave(slave)) {
                        if (new_value)
                                slave->inactive = 0;
index 42d1c6599cba944cd1854759f010b5c6776c438b..4bf52d5f637ef687ef5bd9f31e848212c2b3ff62 100644 (file)
        set_fs(fs);                     \
        res; })
 
+/* slave list primitives */
+#define bond_to_slave(ptr) list_entry(ptr, struct slave, list)
+
+/* IMPORTANT: bond_first/last_slave can return NULL in case of an empty list */
+#define bond_first_slave(bond) \
+       list_first_entry_or_null(&(bond)->slave_list, struct slave, list)
+#define bond_last_slave(bond) \
+       (list_empty(&(bond)->slave_list) ? NULL : \
+                                          bond_to_slave((bond)->slave_list.prev))
+
+#define bond_is_first_slave(bond, pos) ((pos)->list.prev == &(bond)->slave_list)
+#define bond_is_last_slave(bond, pos) ((pos)->list.next == &(bond)->slave_list)
+
+/* Since bond_first/last_slave can return NULL, these can return NULL too */
+#define bond_next_slave(bond, pos) \
+       (bond_is_last_slave(bond, pos) ? bond_first_slave(bond) : \
+                                        bond_to_slave((pos)->list.next))
+
+#define bond_prev_slave(bond, pos) \
+       (bond_is_first_slave(bond, pos) ? bond_last_slave(bond) : \
+                                         bond_to_slave((pos)->list.prev))
+
 /**
  * bond_for_each_slave_from - iterate the slaves list from a starting point
  * @bond:      the bond holding this list.
  *
  * Caller must hold bond->lock
  */
-#define bond_for_each_slave_from(bond, pos, cnt, start)        \
-       for (cnt = 0, pos = start;                              \
-            cnt < (bond)->slave_cnt;                           \
-             cnt++, pos = (pos)->next)
+#define bond_for_each_slave_from(bond, pos, cnt, start) \
+       for (cnt = 0, pos = start; pos && cnt < (bond)->slave_cnt; \
+            cnt++, pos = bond_next_slave(bond, pos))
 
 /**
- * bond_for_each_slave_from_to - iterate the slaves list from start point to stop point
- * @bond:      the bond holding this list.
- * @pos:       current slave.
- * @cnt:       counter for number max of moves
- * @start:     start point.
- * @stop:      stop point.
+ * bond_for_each_slave - iterate over all slaves
+ * @bond:      the bond holding this list
+ * @pos:       current slave
  *
  * Caller must hold bond->lock
  */
-#define bond_for_each_slave_from_to(bond, pos, cnt, start, stop)       \
-       for (cnt = 0, pos = start;                                      \
-            ((cnt < (bond)->slave_cnt) && (pos != (stop)->next));      \
-             cnt++, pos = (pos)->next)
+#define bond_for_each_slave(bond, pos) \
+       list_for_each_entry(pos, &(bond)->slave_list, list)
+
+/* Caller must have rcu_read_lock */
+#define bond_for_each_slave_rcu(bond, pos) \
+       list_for_each_entry_rcu(pos, &(bond)->slave_list, list)
 
 /**
- * bond_for_each_slave - iterate the slaves list from head
- * @bond:      the bond holding this list.
- * @pos:       current slave.
- * @cnt:       counter for max number of moves
+ * bond_for_each_slave_reverse - iterate in reverse from a given position
+ * @bond:      the bond holding this list
+ * @pos:       slave to continue from
  *
  * Caller must hold bond->lock
  */
-#define bond_for_each_slave(bond, pos, cnt)    \
-               bond_for_each_slave_from(bond, pos, cnt, (bond)->first_slave)
-
+#define bond_for_each_slave_continue_reverse(bond, pos) \
+       list_for_each_entry_continue_reverse(pos, &(bond)->slave_list, list)
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
 extern atomic_t netpoll_block_tx;
@@ -174,8 +192,7 @@ struct vlan_entry {
 
 struct slave {
        struct net_device *dev; /* first - useful for panic debug */
-       struct slave *next;
-       struct slave *prev;
+       struct list_head list;
        struct bonding *bond; /* our master */
        int    delay;
        unsigned long jiffies;
@@ -215,7 +232,7 @@ struct slave {
  */
 struct bonding {
        struct   net_device *dev; /* first - useful for panic debug */
-       struct   slave *first_slave;
+       struct   list_head slave_list;
        struct   slave *curr_active_slave;
        struct   slave *current_arp_slave;
        struct   slave *primary_slave;
@@ -270,13 +287,10 @@ static inline struct slave *bond_get_slave_by_dev(struct bonding *bond,
                                                  struct net_device *slave_dev)
 {
        struct slave *slave = NULL;
-       int i;
 
-       bond_for_each_slave(bond, slave, i) {
-               if (slave->dev == slave_dev) {
+       bond_for_each_slave(bond, slave)
+               if (slave->dev == slave_dev)
                        return slave;
-               }
-       }
 
        return NULL;
 }
@@ -416,10 +430,20 @@ static inline __be32 bond_confirm_addr(struct net_device *dev, __be32 dst, __be3
        return addr;
 }
 
+static inline bool slave_can_tx(struct slave *slave)
+{
+       if (IS_UP(slave->dev) && slave->link == BOND_LINK_UP &&
+           bond_is_active_slave(slave))
+               return true;
+       else
+               return false;
+}
+
 struct bond_net;
 
 struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr);
 int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev);
+void bond_xmit_slave_id(struct bonding *bond, struct sk_buff *skb, int slave_id);
 int bond_create(struct net *net, const char *name);
 int bond_create_sysfs(struct bond_net *net);
 void bond_destroy_sysfs(struct bond_net *net);
@@ -477,10 +501,9 @@ static inline void bond_destroy_proc_dir(struct bond_net *bn)
 static inline struct slave *bond_slave_has_mac(struct bonding *bond,
                                               const u8 *mac)
 {
-       int i = 0;
        struct slave *tmp;
 
-       bond_for_each_slave(bond, tmp, i)
+       bond_for_each_slave(bond, tmp)
                if (ether_addr_equal_64bits(mac, tmp->dev->dev_addr))
                        return tmp;
 
index 7b0be0910f4be5116901b1ff25668bb089a033df..c48174ed49ccdbd1d4da15e356036d0bc6ca6c9f 100644 (file)
@@ -850,12 +850,17 @@ static int flexcan_open(struct net_device *dev)
        struct flexcan_priv *priv = netdev_priv(dev);
        int err;
 
-       clk_prepare_enable(priv->clk_ipg);
-       clk_prepare_enable(priv->clk_per);
+       err = clk_prepare_enable(priv->clk_ipg);
+       if (err)
+               return err;
+
+       err = clk_prepare_enable(priv->clk_per);
+       if (err)
+               goto out_disable_ipg;
 
        err = open_candev(dev);
        if (err)
-               goto out;
+               goto out_disable_per;
 
        err = request_irq(dev->irq, flexcan_irq, IRQF_SHARED, dev->name, dev);
        if (err)
@@ -875,8 +880,9 @@ static int flexcan_open(struct net_device *dev)
 
  out_close:
        close_candev(dev);
- out:
+ out_disable_per:
        clk_disable_unprepare(priv->clk_per);
+ out_disable_ipg:
        clk_disable_unprepare(priv->clk_ipg);
 
        return err;
@@ -933,8 +939,13 @@ static int register_flexcandev(struct net_device *dev)
        struct flexcan_regs __iomem *regs = priv->base;
        u32 reg, err;
 
-       clk_prepare_enable(priv->clk_ipg);
-       clk_prepare_enable(priv->clk_per);
+       err = clk_prepare_enable(priv->clk_ipg);
+       if (err)
+               return err;
+
+       err = clk_prepare_enable(priv->clk_per);
+       if (err)
+               goto out_disable_ipg;
 
        /* select "bus clock", chip must be disabled */
        flexcan_chip_disable(priv);
@@ -959,15 +970,16 @@ static int register_flexcandev(struct net_device *dev)
        if (!(reg & FLEXCAN_MCR_FEN)) {
                netdev_err(dev, "Could not enable RX FIFO, unsupported core\n");
                err = -ENODEV;
-               goto out;
+               goto out_disable_per;
        }
 
        err = register_candev(dev);
 
- out:
+ out_disable_per:
        /* disable core and turn off clocks */
        flexcan_chip_disable(priv);
        clk_disable_unprepare(priv->clk_per);
+ out_disable_ipg:
        clk_disable_unprepare(priv->clk_ipg);
 
        return err;
@@ -1001,7 +1013,6 @@ static int flexcan_probe(struct platform_device *pdev)
        struct resource *mem;
        struct clk *clk_ipg = NULL, *clk_per = NULL;
        void __iomem *base;
-       resource_size_t mem_size;
        int err, irq;
        u32 clock_freq = 0;
 
@@ -1013,43 +1024,25 @@ static int flexcan_probe(struct platform_device *pdev)
                clk_ipg = devm_clk_get(&pdev->dev, "ipg");
                if (IS_ERR(clk_ipg)) {
                        dev_err(&pdev->dev, "no ipg clock defined\n");
-                       err = PTR_ERR(clk_ipg);
-                       goto failed_clock;
+                       return PTR_ERR(clk_ipg);
                }
                clock_freq = clk_get_rate(clk_ipg);
 
                clk_per = devm_clk_get(&pdev->dev, "per");
                if (IS_ERR(clk_per)) {
                        dev_err(&pdev->dev, "no per clock defined\n");
-                       err = PTR_ERR(clk_per);
-                       goto failed_clock;
+                       return PTR_ERR(clk_per);
                }
        }
 
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        irq = platform_get_irq(pdev, 0);
-       if (!mem || irq <= 0) {
-               err = -ENODEV;
-               goto failed_get;
-       }
+       if (irq <= 0)
+               return -ENODEV;
 
-       mem_size = resource_size(mem);
-       if (!request_mem_region(mem->start, mem_size, pdev->name)) {
-               err = -EBUSY;
-               goto failed_get;
-       }
-
-       base = ioremap(mem->start, mem_size);
-       if (!base) {
-               err = -ENOMEM;
-               goto failed_map;
-       }
-
-       dev = alloc_candev(sizeof(struct flexcan_priv), 1);
-       if (!dev) {
-               err = -ENOMEM;
-               goto failed_alloc;
-       }
+       base = devm_ioremap_resource(&pdev->dev, mem);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
 
        of_id = of_match_device(flexcan_of_match, &pdev->dev);
        if (of_id) {
@@ -1058,10 +1051,13 @@ static int flexcan_probe(struct platform_device *pdev)
                devtype_data = (struct flexcan_devtype_data *)
                        pdev->id_entry->driver_data;
        } else {
-               err = -ENODEV;
-               goto failed_devtype;
+               return -ENODEV;
        }
 
+       dev = alloc_candev(sizeof(struct flexcan_priv), 1);
+       if (!dev)
+               return -ENOMEM;
+
        dev->netdev_ops = &flexcan_netdev_ops;
        dev->irq = irq;
        dev->flags |= IFF_ECHO;
@@ -1104,28 +1100,15 @@ static int flexcan_probe(struct platform_device *pdev)
        return 0;
 
  failed_register:
- failed_devtype:
        free_candev(dev);
- failed_alloc:
-       iounmap(base);
- failed_map:
-       release_mem_region(mem->start, mem_size);
- failed_get:
- failed_clock:
        return err;
 }
 
 static int flexcan_remove(struct platform_device *pdev)
 {
        struct net_device *dev = platform_get_drvdata(pdev);
-       struct flexcan_priv *priv = netdev_priv(dev);
-       struct resource *mem;
 
        unregister_flexcandev(dev);
-       iounmap(priv->base);
-
-       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(mem->start, resource_size(mem));
 
        free_candev(dev);
 
index 6aa7b3266c80904d8d2f2106869085a8b19d5248..ac6177d3befca611242f26906a9168f11ad3c23c 100644 (file)
@@ -412,10 +412,20 @@ static void esd_usb2_read_bulk_callback(struct urb *urb)
 
                switch (msg->msg.hdr.cmd) {
                case CMD_CAN_RX:
+                       if (msg->msg.rx.net >= dev->net_count) {
+                               dev_err(dev->udev->dev.parent, "format error\n");
+                               break;
+                       }
+
                        esd_usb2_rx_can_msg(dev->nets[msg->msg.rx.net], msg);
                        break;
 
                case CMD_CAN_TX:
+                       if (msg->msg.txdone.net >= dev->net_count) {
+                               dev_err(dev->udev->dev.parent, "format error\n");
+                               break;
+                       }
+
                        esd_usb2_tx_done_msg(dev->nets[msg->msg.txdone.net],
                                             msg);
                        break;
index cbd388eea68271c8ab7eaa2581ffb9145a4be429..8becd3d838b5eab2a520be8835c9fba3f3703482 100644 (file)
@@ -779,6 +779,7 @@ static int usb_8dev_start(struct usb_8dev_priv *priv)
                        usb_unanchor_urb(urb);
                        usb_free_coherent(priv->udev, RX_BUFFER_SIZE, buf,
                                          urb->transfer_dma);
+                       usb_free_urb(urb);
                        break;
                }
 
index 53ad213e865ba350176ac8b59d83bac0dc58ca09..d8d95d4cd45a9ef00ffa7c9c919188bc66d39465 100644 (file)
@@ -3,19 +3,20 @@
 #
 
 config NET_VENDOR_ALLWINNER
-       bool "Allwinner devices"
-       default y
-       depends on ARCH_SUNXI
-       ---help---
-         If you have a network (Ethernet) card belonging to this
-        class, say Y and read the Ethernet-HOWTO, available from
-        <http://www.tldp.org/docs.html#howto>.
+       bool "Allwinner devices"
+       default y
 
-        Note that the answer to this question doesn't directly
-        affect the kernel: saying N will just cause the configurator
-        to skip all the questions about Allwinner cards. If you say Y,
-        you will be asked for your specific card in the following
-        questions.
+       depends on ARCH_SUNXI
+       ---help---
+         If you have a network (Ethernet) card belonging to this
+         class, say Y and read the Ethernet-HOWTO, available from
+         <http://www.tldp.org/docs.html#howto>.
+
+         Note that the answer to this question doesn't directly
+         affect the kernel: saying N will just cause the configurator
+         to skip all the questions about Allwinner cards. If you say Y,
+         you will be asked for your specific card in the following
+         questions.
 
 if NET_VENDOR_ALLWINNER
 
@@ -26,6 +27,7 @@ config SUN4I_EMAC
        select CRC32
        select MII
        select PHYLIB
+       select MDIO_SUN4I
         ---help---
           Support for Allwinner A10 EMAC ethernet driver.
 
index b2bf324631dc89f7902f9d7322c549331daa1c78..0f0556526ba90bff7f764c4005d6f6e850220dd7 100644 (file)
@@ -520,6 +520,9 @@ struct atl1c_adapter {
        struct net_device   *netdev;
        struct pci_dev      *pdev;
        struct napi_struct  napi;
+       struct page         *rx_page;
+       unsigned int        rx_page_offset;
+       unsigned int        rx_frag_size;
        struct atl1c_hw        hw;
        struct atl1c_hw_stats  hw_stats;
        struct mii_if_info  mii;    /* MII interface info */
index 786a87483298ea400733b987da389144e297824b..a36a760ada28af64272a5132a60648c543963bed 100644 (file)
@@ -481,10 +481,15 @@ static int atl1c_set_mac_addr(struct net_device *netdev, void *p)
 static void atl1c_set_rxbufsize(struct atl1c_adapter *adapter,
                                struct net_device *dev)
 {
+       unsigned int head_size;
        int mtu = dev->mtu;
 
        adapter->rx_buffer_len = mtu > AT_RX_BUF_SIZE ?
                roundup(mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN, 8) : AT_RX_BUF_SIZE;
+
+       head_size = SKB_DATA_ALIGN(adapter->rx_buffer_len + NET_SKB_PAD) +
+                   SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+       adapter->rx_frag_size = roundup_pow_of_two(head_size);
 }
 
 static netdev_features_t atl1c_fix_features(struct net_device *netdev,
@@ -952,6 +957,10 @@ static void atl1c_free_ring_resources(struct atl1c_adapter *adapter)
                kfree(adapter->tpd_ring[0].buffer_info);
                adapter->tpd_ring[0].buffer_info = NULL;
        }
+       if (adapter->rx_page) {
+               put_page(adapter->rx_page);
+               adapter->rx_page = NULL;
+       }
 }
 
 /**
@@ -1639,6 +1648,35 @@ static inline void atl1c_rx_checksum(struct atl1c_adapter *adapter,
        skb_checksum_none_assert(skb);
 }
 
+static struct sk_buff *atl1c_alloc_skb(struct atl1c_adapter *adapter)
+{
+       struct sk_buff *skb;
+       struct page *page;
+
+       if (adapter->rx_frag_size > PAGE_SIZE)
+               return netdev_alloc_skb(adapter->netdev,
+                                       adapter->rx_buffer_len);
+
+       page = adapter->rx_page;
+       if (!page) {
+               adapter->rx_page = page = alloc_page(GFP_ATOMIC);
+               if (unlikely(!page))
+                       return NULL;
+               adapter->rx_page_offset = 0;
+       }
+
+       skb = build_skb(page_address(page) + adapter->rx_page_offset,
+                       adapter->rx_frag_size);
+       if (likely(skb)) {
+               adapter->rx_page_offset += adapter->rx_frag_size;
+               if (adapter->rx_page_offset >= PAGE_SIZE)
+                       adapter->rx_page = NULL;
+               else
+                       get_page(page);
+       }
+       return skb;
+}
+
 static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter)
 {
        struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring;
@@ -1660,7 +1698,7 @@ static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter)
        while (next_info->flags & ATL1C_BUFFER_FREE) {
                rfd_desc = ATL1C_RFD_DESC(rfd_ring, rfd_next_to_use);
 
-               skb = netdev_alloc_skb(adapter->netdev, adapter->rx_buffer_len);
+               skb = atl1c_alloc_skb(adapter);
                if (unlikely(!skb)) {
                        if (netif_msg_rx_err(adapter))
                                dev_warn(&pdev->dev, "alloc rx buffer failed\n");
index 52c96036dcc41ca5174f97b52c633126c8aea3cf..2fa5b86f139db626f1839c7b3bc9087444179b28 100644 (file)
@@ -130,7 +130,7 @@ config BNX2X_SRIOV
 
 config BGMAC
        tristate "BCMA bus GBit core support"
-       depends on BCMA_HOST_SOC && HAS_DMA
+       depends on BCMA_HOST_SOC && HAS_DMA && BCM47XX
        select PHYLIB
        ---help---
          This driver supports GBit MAC and BCM4706 GBit MAC cores on BCMA bus.
index dedbd76c033ede4d695e3c7498f99ff263ca860b..7ecb44ad24fbcb8865f4f3e1ec55d9fbdd899eb2 100644 (file)
@@ -486,7 +486,7 @@ struct bnx2x_fastpath {
 
        struct napi_struct      napi;
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        unsigned int state;
 #define BNX2X_FP_STATE_IDLE                  0
 #define BNX2X_FP_STATE_NAPI            (1 << 0)    /* NAPI owns this FP */
@@ -498,7 +498,7 @@ struct bnx2x_fastpath {
 #define BNX2X_FP_USER_PEND (BNX2X_FP_STATE_POLL | BNX2X_FP_STATE_POLL_YIELD)
        /* protect state */
        spinlock_t lock;
-#endif /* CONFIG_NET_LL_RX_POLL */
+#endif /* CONFIG_NET_RX_BUSY_POLL */
 
        union host_hc_status_block      status_blk;
        /* chip independent shortcuts into sb structure */
@@ -572,7 +572,7 @@ struct bnx2x_fastpath {
 #define bnx2x_fp_stats(bp, fp) (&((bp)->fp_stats[(fp)->index]))
 #define bnx2x_fp_qstats(bp, fp)        (&((bp)->fp_stats[(fp)->index].eth_q_stats))
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
 static inline void bnx2x_fp_init_lock(struct bnx2x_fastpath *fp)
 {
        spin_lock_init(&fp->lock);
@@ -680,7 +680,7 @@ static inline bool bnx2x_fp_ll_polling(struct bnx2x_fastpath *fp)
 {
        return false;
 }
-#endif /* CONFIG_NET_LL_RX_POLL */
+#endif /* CONFIG_NET_RX_BUSY_POLL */
 
 /* Use 2500 as a mini-jumbo MTU for FCoE */
 #define BNX2X_FCOE_MINI_JUMBO_MTU      2500
@@ -1331,7 +1331,7 @@ enum {
        BNX2X_SP_RTNL_ENABLE_SRIOV,
        BNX2X_SP_RTNL_VFPF_MCAST,
        BNX2X_SP_RTNL_VFPF_CHANNEL_DOWN,
-       BNX2X_SP_RTNL_VFPF_STORM_RX_MODE,
+       BNX2X_SP_RTNL_RX_MODE,
        BNX2X_SP_RTNL_HYPERVISOR_VLAN,
 };
 
index ee350bde1818cc38c4a20a0db70a466bf158ee2e..2e90868a9276edad8c754494f32d714ee1bc0620 100644 (file)
@@ -2060,7 +2060,11 @@ void bnx2x_squeeze_objects(struct bnx2x *bp)
        rparam.mcast_obj = &bp->mcast_obj;
        __set_bit(RAMROD_DRV_CLR_ONLY, &rparam.ramrod_flags);
 
-       /* Add a DEL command... */
+       /* Add a DEL command... - Since we're doing a driver cleanup only,
+        * we take a lock surrounding both the initial send and the CONTs,
+        * as we don't want a true completion to disrupt us in the middle.
+        */
+       netif_addr_lock_bh(bp->dev);
        rc = bnx2x_config_mcast(bp, &rparam, BNX2X_MCAST_CMD_DEL);
        if (rc < 0)
                BNX2X_ERR("Failed to add a new DEL command to a multi-cast object: %d\n",
@@ -2072,11 +2076,13 @@ void bnx2x_squeeze_objects(struct bnx2x *bp)
                if (rc < 0) {
                        BNX2X_ERR("Failed to clean multi-cast object: %d\n",
                                  rc);
+                       netif_addr_unlock_bh(bp->dev);
                        return;
                }
 
                rc = bnx2x_config_mcast(bp, &rparam, BNX2X_MCAST_CMD_CONT);
        }
+       netif_addr_unlock_bh(bp->dev);
 }
 
 #ifndef BNX2X_STOP_ON_ERROR
@@ -2432,9 +2438,7 @@ int bnx2x_load_cnic(struct bnx2x *bp)
        }
 
        /* Initialize Rx filter. */
-       netif_addr_lock_bh(bp->dev);
-       bnx2x_set_rx_mode(bp->dev);
-       netif_addr_unlock_bh(bp->dev);
+       bnx2x_set_rx_mode_inner(bp);
 
        /* re-read iscsi info */
        bnx2x_get_iscsi_info(bp);
@@ -2704,9 +2708,7 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
        /* Start fast path */
 
        /* Initialize Rx filter. */
-       netif_addr_lock_bh(bp->dev);
-       bnx2x_set_rx_mode(bp->dev);
-       netif_addr_unlock_bh(bp->dev);
+       bnx2x_set_rx_mode_inner(bp);
 
        /* Start the Tx */
        switch (load_mode) {
@@ -3117,7 +3119,7 @@ int bnx2x_poll(struct napi_struct *napi, int budget)
        return work_done;
 }
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
 /* must be called with local_bh_disable()d */
 int bnx2x_low_latency_recv(struct napi_struct *napi)
 {
index c07a6d054cfe970b031582400ef71212bd45780c..38be494ffa6eb65f6013127832c87d3b07491323 100644 (file)
@@ -418,6 +418,7 @@ int bnx2x_set_eth_mac(struct bnx2x *bp, bool set);
  * netif_addr_lock_bh()
  */
 void bnx2x_set_rx_mode(struct net_device *dev);
+void bnx2x_set_rx_mode_inner(struct bnx2x *bp);
 
 /**
  * bnx2x_set_storm_rx_mode - configure MAC filtering rules in a FW.
index e5da07858a2f0d5dca0747e1b7fe58992b799d5e..ab5bd6c319d344852b709be614b9f49a0d5f1eed 100644 (file)
@@ -9628,11 +9628,9 @@ sp_rtnl_not_reset:
                }
        }
 
-       if (test_and_clear_bit(BNX2X_SP_RTNL_VFPF_STORM_RX_MODE,
-                              &bp->sp_rtnl_state)) {
-               DP(BNX2X_MSG_SP,
-                  "sending set storm rx mode vf pf channel message from rtnl sp-task\n");
-               bnx2x_vfpf_storm_rx_mode(bp);
+       if (test_and_clear_bit(BNX2X_SP_RTNL_RX_MODE, &bp->sp_rtnl_state)) {
+               DP(BNX2X_MSG_SP, "Handling Rx Mode setting\n");
+               bnx2x_set_rx_mode_inner(bp);
        }
 
        if (test_and_clear_bit(BNX2X_SP_RTNL_HYPERVISOR_VLAN,
@@ -11849,34 +11847,48 @@ static int bnx2x_set_mc_list(struct bnx2x *bp)
 void bnx2x_set_rx_mode(struct net_device *dev)
 {
        struct bnx2x *bp = netdev_priv(dev);
-       u32 rx_mode = BNX2X_RX_MODE_NORMAL;
 
        if (bp->state != BNX2X_STATE_OPEN) {
                DP(NETIF_MSG_IFUP, "state is %x, returning\n", bp->state);
                return;
+       } else {
+               /* Schedule an SP task to handle rest of change */
+               DP(NETIF_MSG_IFUP, "Scheduling an Rx mode change\n");
+               smp_mb__before_clear_bit();
+               set_bit(BNX2X_SP_RTNL_RX_MODE, &bp->sp_rtnl_state);
+               smp_mb__after_clear_bit();
+               schedule_delayed_work(&bp->sp_rtnl_task, 0);
        }
+}
+
+void bnx2x_set_rx_mode_inner(struct bnx2x *bp)
+{
+       u32 rx_mode = BNX2X_RX_MODE_NORMAL;
 
        DP(NETIF_MSG_IFUP, "dev->flags = %x\n", bp->dev->flags);
 
-       if (dev->flags & IFF_PROMISC)
+       netif_addr_lock_bh(bp->dev);
+
+       if (bp->dev->flags & IFF_PROMISC) {
                rx_mode = BNX2X_RX_MODE_PROMISC;
-       else if ((dev->flags & IFF_ALLMULTI) ||
-                ((netdev_mc_count(dev) > BNX2X_MAX_MULTICAST) &&
-                 CHIP_IS_E1(bp)))
+       } else if ((bp->dev->flags & IFF_ALLMULTI) ||
+                  ((netdev_mc_count(bp->dev) > BNX2X_MAX_MULTICAST) &&
+                   CHIP_IS_E1(bp))) {
                rx_mode = BNX2X_RX_MODE_ALLMULTI;
-       else {
+       else {
                if (IS_PF(bp)) {
                        /* some multicasts */
                        if (bnx2x_set_mc_list(bp) < 0)
                                rx_mode = BNX2X_RX_MODE_ALLMULTI;
 
+                       /* release bh lock, as bnx2x_set_uc_list might sleep */
+                       netif_addr_unlock_bh(bp->dev);
                        if (bnx2x_set_uc_list(bp) < 0)
                                rx_mode = BNX2X_RX_MODE_PROMISC;
+                       netif_addr_lock_bh(bp->dev);
                } else {
                        /* configuring mcast to a vf involves sleeping (when we
-                        * wait for the pf's response). Since this function is
-                        * called from non sleepable context we must schedule
-                        * a work item for this purpose
+                        * wait for the pf's response).
                         */
                        smp_mb__before_clear_bit();
                        set_bit(BNX2X_SP_RTNL_VFPF_MCAST,
@@ -11894,22 +11906,20 @@ void bnx2x_set_rx_mode(struct net_device *dev)
        /* Schedule the rx_mode command */
        if (test_bit(BNX2X_FILTER_RX_MODE_PENDING, &bp->sp_state)) {
                set_bit(BNX2X_FILTER_RX_MODE_SCHED, &bp->sp_state);
+               netif_addr_unlock_bh(bp->dev);
                return;
        }
 
        if (IS_PF(bp)) {
                bnx2x_set_storm_rx_mode(bp);
+               netif_addr_unlock_bh(bp->dev);
        } else {
-               /* configuring rx mode to storms in a vf involves sleeping (when
-                * we wait for the pf's response). Since this function is
-                * called from non sleepable context we must schedule
-                * a work item for this purpose
+               /* VF will need to request the PF to make this change, and so
+                * the VF needs to release the bottom-half lock prior to the
+                * request (as it will likely require sleep on the VF side)
                 */
-               smp_mb__before_clear_bit();
-               set_bit(BNX2X_SP_RTNL_VFPF_STORM_RX_MODE,
-                       &bp->sp_rtnl_state);
-               smp_mb__after_clear_bit();
-               schedule_delayed_work(&bp->sp_rtnl_task, 0);
+               netif_addr_unlock_bh(bp->dev);
+               bnx2x_vfpf_storm_rx_mode(bp);
        }
 }
 
@@ -12026,7 +12036,7 @@ static const struct net_device_ops bnx2x_netdev_ops = {
        .ndo_fcoe_get_wwn       = bnx2x_fcoe_get_wwn,
 #endif
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        .ndo_busy_poll          = bnx2x_low_latency_recv,
 #endif
 };
index 8f03c984550f328c88764d83f04813b344445b1d..1d46b68fb7664d69ca0e26b66d6340d9d18cb233 100644 (file)
@@ -159,16 +159,6 @@ static inline void __bnx2x_exe_queue_reset_pending(
        }
 }
 
-static inline void bnx2x_exe_queue_reset_pending(struct bnx2x *bp,
-                                                struct bnx2x_exe_queue_obj *o)
-{
-       spin_lock_bh(&o->lock);
-
-       __bnx2x_exe_queue_reset_pending(bp, o);
-
-       spin_unlock_bh(&o->lock);
-}
-
 /**
  * bnx2x_exe_queue_step - execute one execution chunk atomically
  *
@@ -176,7 +166,7 @@ static inline void bnx2x_exe_queue_reset_pending(struct bnx2x *bp,
  * @o:                 queue
  * @ramrod_flags:      flags
  *
- * (Atomicity is ensured using the exe_queue->lock).
+ * (Should be called while holding the exe_queue->lock).
  */
 static inline int bnx2x_exe_queue_step(struct bnx2x *bp,
                                       struct bnx2x_exe_queue_obj *o,
@@ -187,8 +177,6 @@ static inline int bnx2x_exe_queue_step(struct bnx2x *bp,
 
        memset(&spacer, 0, sizeof(spacer));
 
-       spin_lock_bh(&o->lock);
-
        /* Next step should not be performed until the current is finished,
         * unless a DRV_CLEAR_ONLY bit is set. In this case we just want to
         * properly clear object internals without sending any command to the FW
@@ -200,7 +188,6 @@ static inline int bnx2x_exe_queue_step(struct bnx2x *bp,
                        DP(BNX2X_MSG_SP, "RAMROD_DRV_CLR_ONLY requested: resetting a pending_comp list\n");
                        __bnx2x_exe_queue_reset_pending(bp, o);
                } else {
-                       spin_unlock_bh(&o->lock);
                        return 1;
                }
        }
@@ -228,10 +215,8 @@ static inline int bnx2x_exe_queue_step(struct bnx2x *bp,
        }
 
        /* Sanity check */
-       if (!cur_len) {
-               spin_unlock_bh(&o->lock);
+       if (!cur_len)
                return 0;
-       }
 
        rc = o->execute(bp, o->owner, &o->pending_comp, ramrod_flags);
        if (rc < 0)
@@ -245,7 +230,6 @@ static inline int bnx2x_exe_queue_step(struct bnx2x *bp,
                 */
                __bnx2x_exe_queue_reset_pending(bp, o);
 
-       spin_unlock_bh(&o->lock);
        return rc;
 }
 
@@ -432,12 +416,219 @@ static bool bnx2x_put_credit_vlan_mac(struct bnx2x_vlan_mac_obj *o)
        return true;
 }
 
+/**
+ * __bnx2x_vlan_mac_h_write_trylock - try getting the vlan mac writer lock
+ *
+ * @bp:                device handle
+ * @o:         vlan_mac object
+ *
+ * @details: Non-blocking implementation; should be called under execution
+ *           queue lock.
+ */
+static int __bnx2x_vlan_mac_h_write_trylock(struct bnx2x *bp,
+                                           struct bnx2x_vlan_mac_obj *o)
+{
+       if (o->head_reader) {
+               DP(BNX2X_MSG_SP, "vlan_mac_lock writer - There are readers; Busy\n");
+               return -EBUSY;
+       }
+
+       DP(BNX2X_MSG_SP, "vlan_mac_lock writer - Taken\n");
+       return 0;
+}
+
+/**
+ * __bnx2x_vlan_mac_h_exec_pending - execute step instead of a previous step
+ *
+ * @bp:                device handle
+ * @o:         vlan_mac object
+ *
+ * @details Should be called under execution queue lock; notice it might release
+ *          and reclaim it during its run.
+ */
+static void __bnx2x_vlan_mac_h_exec_pending(struct bnx2x *bp,
+                                           struct bnx2x_vlan_mac_obj *o)
+{
+       int rc;
+       unsigned long ramrod_flags = o->saved_ramrod_flags;
+
+       DP(BNX2X_MSG_SP, "vlan_mac_lock execute pending command with ramrod flags %lu\n",
+          ramrod_flags);
+       o->head_exe_request = false;
+       o->saved_ramrod_flags = 0;
+       rc = bnx2x_exe_queue_step(bp, &o->exe_queue, &ramrod_flags);
+       if (rc != 0) {
+               BNX2X_ERR("execution of pending commands failed with rc %d\n",
+                         rc);
+#ifdef BNX2X_STOP_ON_ERROR
+               bnx2x_panic();
+#endif
+       }
+}
+
+/**
+ * __bnx2x_vlan_mac_h_pend - Pend an execution step which couldn't run
+ *
+ * @bp:                        device handle
+ * @o:                 vlan_mac object
+ * @ramrod_flags:      ramrod flags of missed execution
+ *
+ * @details Should be called under execution queue lock.
+ */
+static void __bnx2x_vlan_mac_h_pend(struct bnx2x *bp,
+                                   struct bnx2x_vlan_mac_obj *o,
+                                   unsigned long ramrod_flags)
+{
+       o->head_exe_request = true;
+       o->saved_ramrod_flags = ramrod_flags;
+       DP(BNX2X_MSG_SP, "Placing pending execution with ramrod flags %lu\n",
+          ramrod_flags);
+}
+
+/**
+ * __bnx2x_vlan_mac_h_write_unlock - unlock the vlan mac head list writer lock
+ *
+ * @bp:                        device handle
+ * @o:                 vlan_mac object
+ *
+ * @details Should be called under execution queue lock. Notice if a pending
+ *          execution exists, it would perform it - possibly releasing and
+ *          reclaiming the execution queue lock.
+ */
+static void __bnx2x_vlan_mac_h_write_unlock(struct bnx2x *bp,
+                                           struct bnx2x_vlan_mac_obj *o)
+{
+       /* It's possible a new pending execution was added since this writer
+        * executed. If so, execute again. [Ad infinitum]
+        */
+       while (o->head_exe_request) {
+               DP(BNX2X_MSG_SP, "vlan_mac_lock - writer release encountered a pending request\n");
+               __bnx2x_vlan_mac_h_exec_pending(bp, o);
+       }
+}
+
+/**
+ * bnx2x_vlan_mac_h_write_unlock - unlock the vlan mac head list writer lock
+ *
+ * @bp:                        device handle
+ * @o:                 vlan_mac object
+ *
+ * @details Notice if a pending execution exists, it would perform it -
+ *          possibly releasing and reclaiming the execution queue lock.
+ */
+void bnx2x_vlan_mac_h_write_unlock(struct bnx2x *bp,
+                                  struct bnx2x_vlan_mac_obj *o)
+{
+       spin_lock_bh(&o->exe_queue.lock);
+       __bnx2x_vlan_mac_h_write_unlock(bp, o);
+       spin_unlock_bh(&o->exe_queue.lock);
+}
+
+/**
+ * __bnx2x_vlan_mac_h_read_lock - lock the vlan mac head list reader lock
+ *
+ * @bp:                        device handle
+ * @o:                 vlan_mac object
+ *
+ * @details Should be called under the execution queue lock. May sleep. May
+ *          release and reclaim execution queue lock during its run.
+ */
+static int __bnx2x_vlan_mac_h_read_lock(struct bnx2x *bp,
+                                       struct bnx2x_vlan_mac_obj *o)
+{
+       /* If we got here, we're holding lock --> no WRITER exists */
+       o->head_reader++;
+       DP(BNX2X_MSG_SP, "vlan_mac_lock - locked reader - number %d\n",
+          o->head_reader);
+
+       return 0;
+}
+
+/**
+ * bnx2x_vlan_mac_h_read_lock - lock the vlan mac head list reader lock
+ *
+ * @bp:                        device handle
+ * @o:                 vlan_mac object
+ *
+ * @details May sleep. Claims and releases execution queue lock during its run.
+ */
+int bnx2x_vlan_mac_h_read_lock(struct bnx2x *bp,
+                              struct bnx2x_vlan_mac_obj *o)
+{
+       int rc;
+
+       spin_lock_bh(&o->exe_queue.lock);
+       rc = __bnx2x_vlan_mac_h_read_lock(bp, o);
+       spin_unlock_bh(&o->exe_queue.lock);
+
+       return rc;
+}
+
+/**
+ * __bnx2x_vlan_mac_h_read_unlock - unlock the vlan mac head list reader lock
+ *
+ * @bp:                        device handle
+ * @o:                 vlan_mac object
+ *
+ * @details Should be called under execution queue lock. Notice if a pending
+ *          execution exists, it would be performed if this was the last
+ *          reader. possibly releasing and reclaiming the execution queue lock.
+ */
+static void __bnx2x_vlan_mac_h_read_unlock(struct bnx2x *bp,
+                                         struct bnx2x_vlan_mac_obj *o)
+{
+       if (!o->head_reader) {
+               BNX2X_ERR("Need to release vlan mac reader lock, but lock isn't taken\n");
+#ifdef BNX2X_STOP_ON_ERROR
+               bnx2x_panic();
+#endif
+       } else {
+               o->head_reader--;
+               DP(BNX2X_MSG_SP, "vlan_mac_lock - decreased readers to %d\n",
+                  o->head_reader);
+       }
+
+       /* It's possible a new pending execution was added, and that this reader
+        * was last - if so we need to execute the command.
+        */
+       if (!o->head_reader && o->head_exe_request) {
+               DP(BNX2X_MSG_SP, "vlan_mac_lock - reader release encountered a pending request\n");
+
+               /* Writer release will do the trick */
+               __bnx2x_vlan_mac_h_write_unlock(bp, o);
+       }
+}
+
+/**
+ * bnx2x_vlan_mac_h_read_unlock - unlock the vlan mac head list reader lock
+ *
+ * @bp:                        device handle
+ * @o:                 vlan_mac object
+ *
+ * @details Notice if a pending execution exists, it would be performed if this
+ *          was the last reader. Claims and releases the execution queue lock
+ *          during its run.
+ */
+void bnx2x_vlan_mac_h_read_unlock(struct bnx2x *bp,
+                                 struct bnx2x_vlan_mac_obj *o)
+{
+       spin_lock_bh(&o->exe_queue.lock);
+       __bnx2x_vlan_mac_h_read_unlock(bp, o);
+       spin_unlock_bh(&o->exe_queue.lock);
+}
+
 static int bnx2x_get_n_elements(struct bnx2x *bp, struct bnx2x_vlan_mac_obj *o,
                                int n, u8 *base, u8 stride, u8 size)
 {
        struct bnx2x_vlan_mac_registry_elem *pos;
        u8 *next = base;
        int counter = 0;
+       int read_lock;
+
+       DP(BNX2X_MSG_SP, "get_n_elements - taking vlan_mac_lock (reader)\n");
+       read_lock = bnx2x_vlan_mac_h_read_lock(bp, o);
+       if (read_lock != 0)
+               BNX2X_ERR("get_n_elements failed to get vlan mac reader lock; Access without lock\n");
 
        /* traverse list */
        list_for_each_entry(pos, &o->head, link) {
@@ -449,6 +640,12 @@ static int bnx2x_get_n_elements(struct bnx2x *bp, struct bnx2x_vlan_mac_obj *o,
                        next += stride + size;
                }
        }
+
+       if (read_lock == 0) {
+               DP(BNX2X_MSG_SP, "get_n_elements - releasing vlan_mac_lock (reader)\n");
+               bnx2x_vlan_mac_h_read_unlock(bp, o);
+       }
+
        return counter * ETH_ALEN;
 }
 
@@ -1397,6 +1594,32 @@ static int bnx2x_wait_vlan_mac(struct bnx2x *bp,
        return -EBUSY;
 }
 
+static int __bnx2x_vlan_mac_execute_step(struct bnx2x *bp,
+                                        struct bnx2x_vlan_mac_obj *o,
+                                        unsigned long *ramrod_flags)
+{
+       int rc = 0;
+
+       spin_lock_bh(&o->exe_queue.lock);
+
+       DP(BNX2X_MSG_SP, "vlan_mac_execute_step - trying to take writer lock\n");
+       rc = __bnx2x_vlan_mac_h_write_trylock(bp, o);
+
+       if (rc != 0) {
+               __bnx2x_vlan_mac_h_pend(bp, o, *ramrod_flags);
+
+               /* Calling function should not diffrentiate between this case
+                * and the case in which there is already a pending ramrod
+                */
+               rc = 1;
+       } else {
+               rc = bnx2x_exe_queue_step(bp, &o->exe_queue, ramrod_flags);
+       }
+       spin_unlock_bh(&o->exe_queue.lock);
+
+       return rc;
+}
+
 /**
  * bnx2x_complete_vlan_mac - complete one VLAN-MAC ramrod
  *
@@ -1414,19 +1637,27 @@ static int bnx2x_complete_vlan_mac(struct bnx2x *bp,
        struct bnx2x_raw_obj *r = &o->raw;
        int rc;
 
+       /* Clearing the pending list & raw state should be made
+        * atomically (as execution flow assumes they represent the same).
+        */
+       spin_lock_bh(&o->exe_queue.lock);
+
        /* Reset pending list */
-       bnx2x_exe_queue_reset_pending(bp, &o->exe_queue);
+       __bnx2x_exe_queue_reset_pending(bp, &o->exe_queue);
 
        /* Clear pending */
        r->clear_pending(r);
 
+       spin_unlock_bh(&o->exe_queue.lock);
+
        /* If ramrod failed this is most likely a SW bug */
        if (cqe->message.error)
                return -EINVAL;
 
        /* Run the next bulk of pending commands if requested */
        if (test_bit(RAMROD_CONT, ramrod_flags)) {
-               rc = bnx2x_exe_queue_step(bp, &o->exe_queue, ramrod_flags);
+               rc = __bnx2x_vlan_mac_execute_step(bp, o, ramrod_flags);
+
                if (rc < 0)
                        return rc;
        }
@@ -1719,9 +1950,8 @@ static inline int bnx2x_vlan_mac_push_new_cmd(
  * @p:
  *
  */
-int bnx2x_config_vlan_mac(
-       struct bnx2x *bp,
-       struct bnx2x_vlan_mac_ramrod_params *p)
+int bnx2x_config_vlan_mac(struct bnx2x *bp,
+                          struct bnx2x_vlan_mac_ramrod_params *p)
 {
        int rc = 0;
        struct bnx2x_vlan_mac_obj *o = p->vlan_mac_obj;
@@ -1752,7 +1982,8 @@ int bnx2x_config_vlan_mac(
        /* Execute commands if required */
        if (cont || test_bit(RAMROD_EXEC, ramrod_flags) ||
            test_bit(RAMROD_COMP_WAIT, ramrod_flags)) {
-               rc = bnx2x_exe_queue_step(bp, &o->exe_queue, ramrod_flags);
+               rc = __bnx2x_vlan_mac_execute_step(bp, p->vlan_mac_obj,
+                                                  &p->ramrod_flags);
                if (rc < 0)
                        return rc;
        }
@@ -1775,8 +2006,9 @@ int bnx2x_config_vlan_mac(
                                return rc;
 
                        /* Make a next step */
-                       rc = bnx2x_exe_queue_step(bp, &o->exe_queue,
-                                                 ramrod_flags);
+                       rc = __bnx2x_vlan_mac_execute_step(bp,
+                                                          p->vlan_mac_obj,
+                                                          &p->ramrod_flags);
                        if (rc < 0)
                                return rc;
                }
@@ -1806,10 +2038,11 @@ static int bnx2x_vlan_mac_del_all(struct bnx2x *bp,
                                  unsigned long *ramrod_flags)
 {
        struct bnx2x_vlan_mac_registry_elem *pos = NULL;
-       int rc = 0;
        struct bnx2x_vlan_mac_ramrod_params p;
        struct bnx2x_exe_queue_obj *exeq = &o->exe_queue;
        struct bnx2x_exeq_elem *exeq_pos, *exeq_pos_n;
+       int read_lock;
+       int rc = 0;
 
        /* Clear pending commands first */
 
@@ -1844,6 +2077,11 @@ static int bnx2x_vlan_mac_del_all(struct bnx2x *bp,
        __clear_bit(RAMROD_EXEC, &p.ramrod_flags);
        __clear_bit(RAMROD_CONT, &p.ramrod_flags);
 
+       DP(BNX2X_MSG_SP, "vlan_mac_del_all -- taking vlan_mac_lock (reader)\n");
+       read_lock = bnx2x_vlan_mac_h_read_lock(bp, o);
+       if (read_lock != 0)
+               return read_lock;
+
        list_for_each_entry(pos, &o->head, link) {
                if (pos->vlan_mac_flags == *vlan_mac_flags) {
                        p.user_req.vlan_mac_flags = pos->vlan_mac_flags;
@@ -1851,11 +2089,15 @@ static int bnx2x_vlan_mac_del_all(struct bnx2x *bp,
                        rc = bnx2x_config_vlan_mac(bp, &p);
                        if (rc < 0) {
                                BNX2X_ERR("Failed to add a new DEL command\n");
+                               bnx2x_vlan_mac_h_read_unlock(bp, o);
                                return rc;
                        }
                }
        }
 
+       DP(BNX2X_MSG_SP, "vlan_mac_del_all -- releasing vlan_mac_lock (reader)\n");
+       bnx2x_vlan_mac_h_read_unlock(bp, o);
+
        p.ramrod_flags = *ramrod_flags;
        __set_bit(RAMROD_CONT, &p.ramrod_flags);
 
@@ -1887,6 +2129,9 @@ static inline void bnx2x_init_vlan_mac_common(struct bnx2x_vlan_mac_obj *o,
        struct bnx2x_credit_pool_obj *vlans_pool)
 {
        INIT_LIST_HEAD(&o->head);
+       o->head_reader = 0;
+       o->head_exe_request = false;
+       o->saved_ramrod_flags = 0;
 
        o->macs_pool = macs_pool;
        o->vlans_pool = vlans_pool;
index 798dfe9967336fedc4a5e07806c7216c83a955ed..533a3abd8c827b341ef0ca0ed9fc69262de1f646 100644 (file)
@@ -285,6 +285,12 @@ struct bnx2x_vlan_mac_obj {
         * entries.
         */
        struct list_head                head;
+       /* Implement a simple reader/writer lock on the head list.
+        * all these fields should only be accessed under the exe_queue lock
+        */
+       u8              head_reader; /* Num. of readers accessing head list */
+       bool            head_exe_request; /* Pending execution request. */
+       unsigned long   saved_ramrod_flags; /* Ramrods of pending execution */
 
        /* TODO: Add it's initialization in the init functions */
        struct bnx2x_exe_queue_obj      exe_queue;
@@ -1302,8 +1308,16 @@ void bnx2x_init_vlan_mac_obj(struct bnx2x *bp,
                             struct bnx2x_credit_pool_obj *macs_pool,
                             struct bnx2x_credit_pool_obj *vlans_pool);
 
+int bnx2x_vlan_mac_h_read_lock(struct bnx2x *bp,
+                                       struct bnx2x_vlan_mac_obj *o);
+void bnx2x_vlan_mac_h_read_unlock(struct bnx2x *bp,
+                                 struct bnx2x_vlan_mac_obj *o);
+int bnx2x_vlan_mac_h_write_lock(struct bnx2x *bp,
+                               struct bnx2x_vlan_mac_obj *o);
+void bnx2x_vlan_mac_h_write_unlock(struct bnx2x *bp,
+                                         struct bnx2x_vlan_mac_obj *o);
 int bnx2x_config_vlan_mac(struct bnx2x *bp,
-                         struct bnx2x_vlan_mac_ramrod_params *p);
+                          struct bnx2x_vlan_mac_ramrod_params *p);
 
 int bnx2x_vlan_mac_move(struct bnx2x *bp,
                        struct bnx2x_vlan_mac_ramrod_params *p,
index 95861efb505187f07bd1a176640e4f44af14a5de..6291324913e9063473fccd0a1c6a7da29a11bec3 100644 (file)
@@ -491,12 +491,20 @@ static inline void bnx2x_vfop_credit(struct bnx2x *bp,
         * and a valid credit counter
         */
        if (!vfop->rc && args->credit) {
-               int cnt = 0;
                struct list_head *pos;
+               int read_lock;
+               int cnt = 0;
+
+               read_lock = bnx2x_vlan_mac_h_read_lock(bp, obj);
+               if (read_lock)
+                       DP(BNX2X_MSG_SP, "Failed to take vlan mac read head; continuing anyway\n");
 
                list_for_each(pos, &obj->head)
                        cnt++;
 
+               if (!read_lock)
+                       bnx2x_vlan_mac_h_read_unlock(bp, obj);
+
                atomic_set(args->credit, cnt);
        }
 }
index d78d4cf140ed6d20a0e513d3c974740cf6c145cd..6bd6d143491b08e90c898c7891d3c397d328f594 100644 (file)
@@ -1,6 +1,6 @@
 /* cnic.c: Broadcom CNIC core network driver.
  *
- * Copyright (c) 2006-2012 Broadcom Corporation
+ * Copyright (c) 2006-2013 Broadcom Corporation
  *
  * 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
@@ -1427,6 +1427,28 @@ static void cnic_reply_bnx2x_kcqes(struct cnic_dev *dev, int ulp_type,
        rcu_read_unlock();
 }
 
+static void cnic_bnx2x_set_tcp_options(struct cnic_dev *dev, int time_stamps,
+                                      int en_tcp_dack)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+       struct bnx2x *bp = netdev_priv(dev->netdev);
+       u8 xstorm_flags = XSTORM_L5CM_TCP_FLAGS_WND_SCL_EN;
+       u16 tstorm_flags = 0;
+
+       if (time_stamps) {
+               xstorm_flags |= XSTORM_L5CM_TCP_FLAGS_TS_ENABLED;
+               tstorm_flags |= TSTORM_L5CM_TCP_FLAGS_TS_ENABLED;
+       }
+       if (en_tcp_dack)
+               tstorm_flags |= TSTORM_L5CM_TCP_FLAGS_DELAYED_ACK_EN;
+
+       CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
+                XSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(cp->pfid), xstorm_flags);
+
+       CNIC_WR16(dev, BAR_TSTRORM_INTMEM +
+                 TSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(cp->pfid), tstorm_flags);
+}
+
 static int cnic_bnx2x_iscsi_init1(struct cnic_dev *dev, struct kwqe *kwqe)
 {
        struct cnic_local *cp = dev->cnic_priv;
@@ -1506,6 +1528,10 @@ static int cnic_bnx2x_iscsi_init1(struct cnic_dev *dev, struct kwqe *kwqe)
        CNIC_WR16(dev, BAR_CSTRORM_INTMEM + CSTORM_ISCSI_HQ_SIZE_OFFSET(pfid),
                  hq_bds);
 
+       cnic_bnx2x_set_tcp_options(dev,
+                       req1->flags & ISCSI_KWQE_INIT1_TIME_STAMPS_ENABLE,
+                       req1->flags & ISCSI_KWQE_INIT1_DELAYED_ACK_ENABLE);
+
        return 0;
 }
 
@@ -2035,9 +2061,6 @@ static void cnic_init_storm_conn_bufs(struct cnic_dev *dev,
        xstorm_buf->pseudo_header_checksum =
                swab16(~csum_ipv6_magic(&src_ip, &dst_ip, 0, IPPROTO_TCP, 0));
 
-       if (!(kwqe1->tcp_flags & L4_KWQ_CONNECT_REQ1_NO_DELAY_ACK))
-               tstorm_buf->params |=
-                       L5CM_TSTORM_CONN_BUFFER_DELAYED_ACK_ENABLE;
        if (kwqe3->ka_timeout) {
                tstorm_buf->ka_enable = 1;
                tstorm_buf->ka_timeout = kwqe3->ka_timeout;
@@ -2084,25 +2107,6 @@ static void cnic_init_bnx2x_mac(struct cnic_dev *dev)
                 mac[0]);
 }
 
-static void cnic_bnx2x_set_tcp_timestamp(struct cnic_dev *dev, int tcp_ts)
-{
-       struct cnic_local *cp = dev->cnic_priv;
-       struct bnx2x *bp = netdev_priv(dev->netdev);
-       u8 xstorm_flags = XSTORM_L5CM_TCP_FLAGS_WND_SCL_EN;
-       u16 tstorm_flags = 0;
-
-       if (tcp_ts) {
-               xstorm_flags |= XSTORM_L5CM_TCP_FLAGS_TS_ENABLED;
-               tstorm_flags |= TSTORM_L5CM_TCP_FLAGS_TS_ENABLED;
-       }
-
-       CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
-                XSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(cp->pfid), xstorm_flags);
-
-       CNIC_WR16(dev, BAR_TSTRORM_INTMEM +
-                 TSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(cp->pfid), tstorm_flags);
-}
-
 static int cnic_bnx2x_connect(struct cnic_dev *dev, struct kwqe *wqes[],
                              u32 num, int *work)
 {
@@ -2178,9 +2182,6 @@ static int cnic_bnx2x_connect(struct cnic_dev *dev, struct kwqe *wqes[],
        CNIC_WR16(dev, BAR_XSTRORM_INTMEM +
                  XSTORM_ISCSI_LOCAL_VLAN_OFFSET(cp->pfid), csk->vlan_id);
 
-       cnic_bnx2x_set_tcp_timestamp(dev,
-               kwqe1->tcp_flags & L4_KWQ_CONNECT_REQ1_TIME_STAMP);
-
        ret = cnic_submit_kwqe_16(dev, L5CM_RAMROD_CMD_ID_TCP_CONNECT,
                        kwqe1->cid, ISCSI_CONNECTION_TYPE, &l5_data);
        if (!ret)
@@ -3603,6 +3604,7 @@ static int cnic_cm_create(struct cnic_dev *dev, int ulp_type, u32 cid,
        csk1->rcv_buf = DEF_RCV_BUF;
        csk1->snd_buf = DEF_SND_BUF;
        csk1->seed = DEF_SEED;
+       csk1->tcp_flags = 0;
 
        *csk = csk1;
        return 0;
@@ -4020,15 +4022,18 @@ static void cnic_cm_process_kcqe(struct cnic_dev *dev, struct kcqe *kcqe)
                cnic_cm_upcall(cp, csk, opcode);
                break;
 
-       case L5CM_RAMROD_CMD_ID_CLOSE:
-               if (l4kcqe->status != 0) {
-                       netdev_warn(dev->netdev, "RAMROD CLOSE compl with "
-                                   "status 0x%x\n", l4kcqe->status);
+       case L5CM_RAMROD_CMD_ID_CLOSE: {
+               struct iscsi_kcqe *l5kcqe = (struct iscsi_kcqe *) kcqe;
+
+               if (l4kcqe->status != 0 || l5kcqe->completion_status != 0) {
+                       netdev_warn(dev->netdev, "RAMROD CLOSE compl with status 0x%x completion status 0x%x\n",
+                                   l4kcqe->status, l5kcqe->completion_status);
                        opcode = L4_KCQE_OPCODE_VALUE_CLOSE_COMP;
                        /* Fall through */
                } else {
                        break;
                }
+       }
        case L4_KCQE_OPCODE_VALUE_RESET_RECEIVED:
        case L4_KCQE_OPCODE_VALUE_CLOSE_COMP:
        case L4_KCQE_OPCODE_VALUE_RESET_COMP:
@@ -4219,7 +4224,7 @@ static int cnic_cm_init_bnx2x_hw(struct cnic_dev *dev)
        u32 port = CNIC_PORT(cp);
 
        cnic_init_bnx2x_mac(dev);
-       cnic_bnx2x_set_tcp_timestamp(dev, 1);
+       cnic_bnx2x_set_tcp_options(dev, 0, 1);
 
        CNIC_WR16(dev, BAR_XSTRORM_INTMEM +
                  XSTORM_ISCSI_LOCAL_VLAN_OFFSET(pfid), 0);
@@ -5628,7 +5633,7 @@ static int cnic_netdev_event(struct notifier_block *this, unsigned long event,
 
        dev = cnic_from_netdev(netdev);
 
-       if (!dev && (event == NETDEV_REGISTER || netif_running(netdev))) {
+       if (!dev && event == NETDEV_REGISTER) {
                /* Check for the hot-plug device */
                dev = is_cnic_dev(netdev);
                if (dev) {
@@ -5644,7 +5649,7 @@ static int cnic_netdev_event(struct notifier_block *this, unsigned long event,
                else if (event == NETDEV_UNREGISTER)
                        cnic_ulp_exit(dev);
 
-               if (event == NETDEV_UP || (new_dev && netif_running(netdev))) {
+               if (event == NETDEV_UP) {
                        if (cnic_register_netdev(dev) != 0) {
                                cnic_put(dev);
                                goto done;
@@ -5693,21 +5698,8 @@ static struct notifier_block cnic_netdev_notifier = {
 
 static void cnic_release(void)
 {
-       struct cnic_dev *dev;
        struct cnic_uio_dev *udev;
 
-       while (!list_empty(&cnic_dev_list)) {
-               dev = list_entry(cnic_dev_list.next, struct cnic_dev, list);
-               if (test_bit(CNIC_F_CNIC_UP, &dev->flags)) {
-                       cnic_ulp_stop(dev);
-                       cnic_stop_hw(dev);
-               }
-
-               cnic_ulp_exit(dev);
-               cnic_unregister_netdev(dev);
-               list_del_init(&dev->list);
-               cnic_free_dev(dev);
-       }
        while (!list_empty(&cnic_udev_list)) {
                udev = list_entry(cnic_udev_list.next, struct cnic_uio_dev,
                                  list);
index 62c670619ae6600a631bad3a351ceb1abec08e5f..e7a247473596ebcbf10688935ab088ac9157a016 100644 (file)
@@ -1,6 +1,6 @@
 /* cnic.h: Broadcom CNIC core network driver.
  *
- * Copyright (c) 2006-2011 Broadcom Corporation
+ * Copyright (c) 2006-2013 Broadcom Corporation
  *
  * 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
index ede3db35d757e9c51a5f07cef320ecf323515295..95a8e4b11c9fcce45a0f24acea5bd1b86fa53ab9 100644 (file)
@@ -1,7 +1,7 @@
 
 /* cnic.c: Broadcom CNIC core network driver.
  *
- * Copyright (c) 2006-2012 Broadcom Corporation
+ * Copyright (c) 2006-2013 Broadcom Corporation
  *
  * 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
@@ -5400,8 +5400,8 @@ struct tstorm_l5cm_tcp_flags {
        u16 flags;
 #define TSTORM_L5CM_TCP_FLAGS_VLAN_ID (0xFFF<<0)
 #define TSTORM_L5CM_TCP_FLAGS_VLAN_ID_SHIFT 0
-#define TSTORM_L5CM_TCP_FLAGS_RSRV0 (0x1<<12)
-#define TSTORM_L5CM_TCP_FLAGS_RSRV0_SHIFT 12
+#define TSTORM_L5CM_TCP_FLAGS_DELAYED_ACK_EN (0x1<<12)
+#define TSTORM_L5CM_TCP_FLAGS_DELAYED_ACK_SHIFT 12
 #define TSTORM_L5CM_TCP_FLAGS_TS_ENABLED (0x1<<13)
 #define TSTORM_L5CM_TCP_FLAGS_TS_ENABLED_SHIFT 13
 #define TSTORM_L5CM_TCP_FLAGS_RSRV1 (0x3<<14)
index ec9bb9ad4bb35c852ef5f0ff62d86118ec6cbaa7..82a03120fcb1a7de37b063270438473dd9753923 100644 (file)
@@ -1,6 +1,6 @@
 /* cnic_if.h: Broadcom CNIC core network driver.
  *
- * Copyright (c) 2006-2012 Broadcom Corporation
+ * Copyright (c) 2006-2013 Broadcom Corporation
  *
  * 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
@@ -14,8 +14,8 @@
 
 #include "bnx2x/bnx2x_mfw_req.h"
 
-#define CNIC_MODULE_VERSION    "2.5.16"
-#define CNIC_MODULE_RELDATE    "Dec 05, 2012"
+#define CNIC_MODULE_VERSION    "2.5.17"
+#define CNIC_MODULE_RELDATE    "July 28, 2013"
 
 #define CNIC_ULP_RDMA          0
 #define CNIC_ULP_ISCSI         1
index d964f302ac94163f32780c4d1ed6667d4fb4165f..51bf9ca42faf79544543bf819d51b112bd9dafd7 100644 (file)
@@ -94,10 +94,10 @@ static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits)
 
 #define DRV_MODULE_NAME                "tg3"
 #define TG3_MAJ_NUM                    3
-#define TG3_MIN_NUM                    132
+#define TG3_MIN_NUM                    133
 #define DRV_MODULE_VERSION     \
        __stringify(TG3_MAJ_NUM) "." __stringify(TG3_MIN_NUM)
-#define DRV_MODULE_RELDATE     "May 21, 2013"
+#define DRV_MODULE_RELDATE     "Jul 29, 2013"
 
 #define RESET_KIND_SHUTDOWN    0
 #define RESET_KIND_INIT                1
@@ -4226,8 +4226,6 @@ static int tg3_power_down_prepare(struct tg3 *tp)
 
 static void tg3_power_down(struct tg3 *tp)
 {
-       tg3_power_down_prepare(tp);
-
        pci_wake_from_d3(tp->pdev, tg3_flag(tp, WOL_ENABLE));
        pci_set_power_state(tp->pdev, PCI_D3hot);
 }
@@ -6095,10 +6093,12 @@ static u64 tg3_refclk_read(struct tg3 *tp)
 /* tp->lock must be held */
 static void tg3_refclk_write(struct tg3 *tp, u64 newval)
 {
-       tw32(TG3_EAV_REF_CLCK_CTL, TG3_EAV_REF_CLCK_CTL_STOP);
+       u32 clock_ctl = tr32(TG3_EAV_REF_CLCK_CTL);
+
+       tw32(TG3_EAV_REF_CLCK_CTL, clock_ctl | TG3_EAV_REF_CLCK_CTL_STOP);
        tw32(TG3_EAV_REF_CLCK_LSB, newval & 0xffffffff);
        tw32(TG3_EAV_REF_CLCK_MSB, newval >> 32);
-       tw32_f(TG3_EAV_REF_CLCK_CTL, TG3_EAV_REF_CLCK_CTL_RESUME);
+       tw32_f(TG3_EAV_REF_CLCK_CTL, clock_ctl | TG3_EAV_REF_CLCK_CTL_RESUME);
 }
 
 static inline void tg3_full_lock(struct tg3 *tp, int irq_sync);
@@ -6214,6 +6214,59 @@ static int tg3_ptp_settime(struct ptp_clock_info *ptp,
 static int tg3_ptp_enable(struct ptp_clock_info *ptp,
                          struct ptp_clock_request *rq, int on)
 {
+       struct tg3 *tp = container_of(ptp, struct tg3, ptp_info);
+       u32 clock_ctl;
+       int rval = 0;
+
+       switch (rq->type) {
+       case PTP_CLK_REQ_PEROUT:
+               if (rq->perout.index != 0)
+                       return -EINVAL;
+
+               tg3_full_lock(tp, 0);
+               clock_ctl = tr32(TG3_EAV_REF_CLCK_CTL);
+               clock_ctl &= ~TG3_EAV_CTL_TSYNC_GPIO_MASK;
+
+               if (on) {
+                       u64 nsec;
+
+                       nsec = rq->perout.start.sec * 1000000000ULL +
+                              rq->perout.start.nsec;
+
+                       if (rq->perout.period.sec || rq->perout.period.nsec) {
+                               netdev_warn(tp->dev,
+                                           "Device supports only a one-shot timesync output, period must be 0\n");
+                               rval = -EINVAL;
+                               goto err_out;
+                       }
+
+                       if (nsec & (1ULL << 63)) {
+                               netdev_warn(tp->dev,
+                                           "Start value (nsec) is over limit. Maximum size of start is only 63 bits\n");
+                               rval = -EINVAL;
+                               goto err_out;
+                       }
+
+                       tw32(TG3_EAV_WATCHDOG0_LSB, (nsec & 0xffffffff));
+                       tw32(TG3_EAV_WATCHDOG0_MSB,
+                            TG3_EAV_WATCHDOG0_EN |
+                            ((nsec >> 32) & TG3_EAV_WATCHDOG_MSB_MASK));
+
+                       tw32(TG3_EAV_REF_CLCK_CTL,
+                            clock_ctl | TG3_EAV_CTL_TSYNC_WDOG0);
+               } else {
+                       tw32(TG3_EAV_WATCHDOG0_MSB, 0);
+                       tw32(TG3_EAV_REF_CLCK_CTL, clock_ctl);
+               }
+
+err_out:
+               tg3_full_unlock(tp);
+               return rval;
+
+       default:
+               break;
+       }
+
        return -EOPNOTSUPP;
 }
 
@@ -6223,7 +6276,7 @@ static const struct ptp_clock_info tg3_ptp_caps = {
        .max_adj        = 250000000,
        .n_alarm        = 0,
        .n_ext_ts       = 0,
-       .n_per_out      = 0,
+       .n_per_out      = 1,
        .pps            = 0,
        .adjfreq        = tg3_ptp_adjfreq,
        .adjtime        = tg3_ptp_adjtime,
@@ -10367,6 +10420,9 @@ static int tg3_reset_hw(struct tg3 *tp, bool reset_phy)
        if (tg3_flag(tp, 5755_PLUS))
                tp->rx_mode |= RX_MODE_IPV6_CSUM_ENABLE;
 
+       if (tg3_asic_rev(tp) == ASIC_REV_5762)
+               tp->rx_mode |= RX_MODE_IPV4_FRAG_FIX;
+
        if (tg3_flag(tp, ENABLE_RSS))
                tp->rx_mode |= RX_MODE_RSS_ENABLE |
                               RX_MODE_RSS_ITBL_HASH_BITS_7 |
@@ -11502,7 +11558,7 @@ static int tg3_close(struct net_device *dev)
        memset(&tp->net_stats_prev, 0, sizeof(tp->net_stats_prev));
        memset(&tp->estats_prev, 0, sizeof(tp->estats_prev));
 
-       tg3_power_down(tp);
+       tg3_power_down_prepare(tp);
 
        tg3_carrier_off(tp);
 
@@ -11724,9 +11780,6 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
        if (tg3_flag(tp, NO_NVRAM))
                return -EINVAL;
 
-       if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)
-               return -EAGAIN;
-
        offset = eeprom->offset;
        len = eeprom->len;
        eeprom->len = 0;
@@ -11784,9 +11837,6 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
        u8 *buf;
        __be32 start, end;
 
-       if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)
-               return -EAGAIN;
-
        if (tg3_flag(tp, NO_NVRAM) ||
            eeprom->magic != TG3_EEPROM_MAGIC)
                return -EINVAL;
@@ -13515,7 +13565,7 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
                        tg3_phy_start(tp);
        }
        if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)
-               tg3_power_down(tp);
+               tg3_power_down_prepare(tp);
 
 }
 
@@ -17547,11 +17597,6 @@ static int tg3_init_one(struct pci_dev *pdev,
            tg3_asic_rev(tp) == ASIC_REV_5762)
                tg3_flag_set(tp, PTP_CAPABLE);
 
-       if (tg3_flag(tp, 5717_PLUS)) {
-               /* Resume a low-power mode */
-               tg3_frob_aux_power(tp, false);
-       }
-
        tg3_timer_init(tp);
 
        tg3_carrier_off(tp);
@@ -17625,7 +17670,8 @@ err_out_free_res:
        pci_release_regions(pdev);
 
 err_out_disable_pdev:
-       pci_disable_device(pdev);
+       if (pci_is_enabled(pdev))
+               pci_disable_device(pdev);
        pci_set_drvdata(pdev, NULL);
        return err;
 }
@@ -17754,6 +17800,23 @@ out:
 
 static SIMPLE_DEV_PM_OPS(tg3_pm_ops, tg3_suspend, tg3_resume);
 
+static void tg3_shutdown(struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       struct tg3 *tp = netdev_priv(dev);
+
+       rtnl_lock();
+       netif_device_detach(dev);
+
+       if (netif_running(dev))
+               dev_close(dev);
+
+       if (system_state == SYSTEM_POWER_OFF)
+               tg3_power_down(tp);
+
+       rtnl_unlock();
+}
+
 /**
  * tg3_io_error_detected - called when PCI error is detected
  * @pdev: Pointer to PCI device
@@ -17773,7 +17836,8 @@ static pci_ers_result_t tg3_io_error_detected(struct pci_dev *pdev,
 
        rtnl_lock();
 
-       if (!netif_running(netdev))
+       /* We probably don't have netdev yet */
+       if (!netdev || !netif_running(netdev))
                goto done;
 
        tg3_phy_stop(tp);
@@ -17909,6 +17973,7 @@ static struct pci_driver tg3_driver = {
        .remove         = tg3_remove_one,
        .err_handler    = &tg3_err_handler,
        .driver.pm      = &tg3_pm_ops,
+       .shutdown       = tg3_shutdown,
 };
 
 module_pci_driver(tg3_driver);
index cd63d1189aae9fdfbcceb5615d76b8d6d74704d2..ddb8be1298eab2b66eac319a4abce91a72da8896 100644 (file)
 #define  RX_MODE_RSS_ITBL_HASH_BITS_7   0x00700000
 #define  RX_MODE_RSS_ENABLE             0x00800000
 #define  RX_MODE_IPV6_CSUM_ENABLE       0x01000000
+#define  RX_MODE_IPV4_FRAG_FIX          0x02000000
 #define MAC_RX_STATUS                  0x0000046c
 #define  RX_STATUS_REMOTE_TX_XOFFED     0x00000001
 #define  RX_STATUS_XOFF_RCVD            0x00000002
 #define TG3_EAV_REF_CLCK_CTL           0x00006908
 #define  TG3_EAV_REF_CLCK_CTL_STOP      0x00000002
 #define  TG3_EAV_REF_CLCK_CTL_RESUME    0x00000004
+#define  TG3_EAV_CTL_TSYNC_GPIO_MASK    (0x3 << 16)
+#define  TG3_EAV_CTL_TSYNC_WDOG0        (1 << 17)
+
+#define TG3_EAV_WATCHDOG0_LSB          0x00006918
+#define TG3_EAV_WATCHDOG0_MSB          0x0000691c
+#define  TG3_EAV_WATCHDOG0_EN           (1 << 31)
+#define  TG3_EAV_WATCHDOG_MSB_MASK     0x7fffffff
+
 #define TG3_EAV_REF_CLK_CORRECT_CTL    0x00006928
 #define  TG3_EAV_REF_CLK_CORRECT_EN     (1 << 31)
 #define  TG3_EAV_REF_CLK_CORRECT_NEG    (1 << 30)
 
 #define TG3_EAV_REF_CLK_CORRECT_MASK   0xffffff
-/* 0x690c --> 0x7000 unused */
+
+/* 0x692c --> 0x7000 unused */
 
 /* NVRAM Control registers */
 #define NVRAM_CMD                      0x00007000
index 9d4974bba247904162de48e382ae8989be8f1a7b..e52296d9b256f130257d07b1f6b9ede196b6f959 100644 (file)
@@ -1,5 +1,6 @@
 obj-$(CONFIG_ENIC) := enic.o
 
 enic-y := enic_main.o vnic_cq.o vnic_intr.o vnic_wq.o \
-       enic_res.o enic_dev.o enic_pp.o vnic_dev.o vnic_rq.o vnic_vic.o
+       enic_res.o enic_dev.o enic_pp.o vnic_dev.o vnic_rq.o vnic_vic.o \
+       enic_ethtool.o
 
index afe9b1662b8cef8c2ba09c73febdca3583f2642a..2e37c63981c1127ca86fce5cbbd92fd9926838e9 100644 (file)
@@ -127,9 +127,57 @@ static inline struct device *enic_get_dev(struct enic *enic)
        return &(enic->pdev->dev);
 }
 
+static inline unsigned int enic_cq_rq(struct enic *enic, unsigned int rq)
+{
+       return rq;
+}
+
+static inline unsigned int enic_cq_wq(struct enic *enic, unsigned int wq)
+{
+       return enic->rq_count + wq;
+}
+
+static inline unsigned int enic_legacy_io_intr(void)
+{
+       return 0;
+}
+
+static inline unsigned int enic_legacy_err_intr(void)
+{
+       return 1;
+}
+
+static inline unsigned int enic_legacy_notify_intr(void)
+{
+       return 2;
+}
+
+static inline unsigned int enic_msix_rq_intr(struct enic *enic,
+       unsigned int rq)
+{
+       return enic->cq[enic_cq_rq(enic, rq)].interrupt_offset;
+}
+
+static inline unsigned int enic_msix_wq_intr(struct enic *enic,
+       unsigned int wq)
+{
+       return enic->cq[enic_cq_wq(enic, wq)].interrupt_offset;
+}
+
+static inline unsigned int enic_msix_err_intr(struct enic *enic)
+{
+       return enic->rq_count + enic->wq_count;
+}
+
+static inline unsigned int enic_msix_notify_intr(struct enic *enic)
+{
+       return enic->rq_count + enic->wq_count + 1;
+}
+
 void enic_reset_addr_lists(struct enic *enic);
 int enic_sriov_enabled(struct enic *enic);
 int enic_is_valid_vf(struct enic *enic, int vf);
 int enic_is_dynamic(struct enic *enic);
+void enic_set_ethtool_ops(struct net_device *netdev);
 
 #endif /* _ENIC_H_ */
index 08bded051b93c1c0b3436056f20655fc08691a24..129b14a4efb088ef4c83212090a4c5a4125bee1a 100644 (file)
@@ -20,6 +20,7 @@
 #define _ENIC_DEV_H_
 
 #include "vnic_dev.h"
+#include "vnic_vic.h"
 
 /*
  * Calls the devcmd function given by argument vnicdevcmdfn.
diff --git a/drivers/net/ethernet/cisco/enic/enic_ethtool.c b/drivers/net/ethernet/cisco/enic/enic_ethtool.c
new file mode 100644 (file)
index 0000000..47e3562
--- /dev/null
@@ -0,0 +1,257 @@
+/**
+ * Copyright 2013 Cisco Systems, Inc.  All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+
+#include "enic_res.h"
+#include "enic.h"
+#include "enic_dev.h"
+
+struct enic_stat {
+       char name[ETH_GSTRING_LEN];
+       unsigned int index;
+};
+
+#define ENIC_TX_STAT(stat) { \
+       .name = #stat, \
+       .index = offsetof(struct vnic_tx_stats, stat) / sizeof(u64) \
+}
+
+#define ENIC_RX_STAT(stat) { \
+       .name = #stat, \
+       .index = offsetof(struct vnic_rx_stats, stat) / sizeof(u64) \
+}
+
+static const struct enic_stat enic_tx_stats[] = {
+       ENIC_TX_STAT(tx_frames_ok),
+       ENIC_TX_STAT(tx_unicast_frames_ok),
+       ENIC_TX_STAT(tx_multicast_frames_ok),
+       ENIC_TX_STAT(tx_broadcast_frames_ok),
+       ENIC_TX_STAT(tx_bytes_ok),
+       ENIC_TX_STAT(tx_unicast_bytes_ok),
+       ENIC_TX_STAT(tx_multicast_bytes_ok),
+       ENIC_TX_STAT(tx_broadcast_bytes_ok),
+       ENIC_TX_STAT(tx_drops),
+       ENIC_TX_STAT(tx_errors),
+       ENIC_TX_STAT(tx_tso),
+};
+
+static const struct enic_stat enic_rx_stats[] = {
+       ENIC_RX_STAT(rx_frames_ok),
+       ENIC_RX_STAT(rx_frames_total),
+       ENIC_RX_STAT(rx_unicast_frames_ok),
+       ENIC_RX_STAT(rx_multicast_frames_ok),
+       ENIC_RX_STAT(rx_broadcast_frames_ok),
+       ENIC_RX_STAT(rx_bytes_ok),
+       ENIC_RX_STAT(rx_unicast_bytes_ok),
+       ENIC_RX_STAT(rx_multicast_bytes_ok),
+       ENIC_RX_STAT(rx_broadcast_bytes_ok),
+       ENIC_RX_STAT(rx_drop),
+       ENIC_RX_STAT(rx_no_bufs),
+       ENIC_RX_STAT(rx_errors),
+       ENIC_RX_STAT(rx_rss),
+       ENIC_RX_STAT(rx_crc_errors),
+       ENIC_RX_STAT(rx_frames_64),
+       ENIC_RX_STAT(rx_frames_127),
+       ENIC_RX_STAT(rx_frames_255),
+       ENIC_RX_STAT(rx_frames_511),
+       ENIC_RX_STAT(rx_frames_1023),
+       ENIC_RX_STAT(rx_frames_1518),
+       ENIC_RX_STAT(rx_frames_to_max),
+};
+
+static const unsigned int enic_n_tx_stats = ARRAY_SIZE(enic_tx_stats);
+static const unsigned int enic_n_rx_stats = ARRAY_SIZE(enic_rx_stats);
+
+static int enic_get_settings(struct net_device *netdev,
+       struct ethtool_cmd *ecmd)
+{
+       struct enic *enic = netdev_priv(netdev);
+
+       ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
+       ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE);
+       ecmd->port = PORT_FIBRE;
+       ecmd->transceiver = XCVR_EXTERNAL;
+
+       if (netif_carrier_ok(netdev)) {
+               ethtool_cmd_speed_set(ecmd, vnic_dev_port_speed(enic->vdev));
+               ecmd->duplex = DUPLEX_FULL;
+       } else {
+               ethtool_cmd_speed_set(ecmd, -1);
+               ecmd->duplex = -1;
+       }
+
+       ecmd->autoneg = AUTONEG_DISABLE;
+
+       return 0;
+}
+
+static void enic_get_drvinfo(struct net_device *netdev,
+       struct ethtool_drvinfo *drvinfo)
+{
+       struct enic *enic = netdev_priv(netdev);
+       struct vnic_devcmd_fw_info *fw_info;
+
+       enic_dev_fw_info(enic, &fw_info);
+
+       strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
+       strlcpy(drvinfo->fw_version, fw_info->fw_version,
+               sizeof(drvinfo->fw_version));
+       strlcpy(drvinfo->bus_info, pci_name(enic->pdev),
+               sizeof(drvinfo->bus_info));
+}
+
+static void enic_get_strings(struct net_device *netdev, u32 stringset,
+       u8 *data)
+{
+       unsigned int i;
+
+       switch (stringset) {
+       case ETH_SS_STATS:
+               for (i = 0; i < enic_n_tx_stats; i++) {
+                       memcpy(data, enic_tx_stats[i].name, ETH_GSTRING_LEN);
+                       data += ETH_GSTRING_LEN;
+               }
+               for (i = 0; i < enic_n_rx_stats; i++) {
+                       memcpy(data, enic_rx_stats[i].name, ETH_GSTRING_LEN);
+                       data += ETH_GSTRING_LEN;
+               }
+               break;
+       }
+}
+
+static int enic_get_sset_count(struct net_device *netdev, int sset)
+{
+       switch (sset) {
+       case ETH_SS_STATS:
+               return enic_n_tx_stats + enic_n_rx_stats;
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static void enic_get_ethtool_stats(struct net_device *netdev,
+       struct ethtool_stats *stats, u64 *data)
+{
+       struct enic *enic = netdev_priv(netdev);
+       struct vnic_stats *vstats;
+       unsigned int i;
+
+       enic_dev_stats_dump(enic, &vstats);
+
+       for (i = 0; i < enic_n_tx_stats; i++)
+               *(data++) = ((u64 *)&vstats->tx)[enic_tx_stats[i].index];
+       for (i = 0; i < enic_n_rx_stats; i++)
+               *(data++) = ((u64 *)&vstats->rx)[enic_rx_stats[i].index];
+}
+
+static u32 enic_get_msglevel(struct net_device *netdev)
+{
+       struct enic *enic = netdev_priv(netdev);
+       return enic->msg_enable;
+}
+
+static void enic_set_msglevel(struct net_device *netdev, u32 value)
+{
+       struct enic *enic = netdev_priv(netdev);
+       enic->msg_enable = value;
+}
+
+static int enic_get_coalesce(struct net_device *netdev,
+       struct ethtool_coalesce *ecmd)
+{
+       struct enic *enic = netdev_priv(netdev);
+
+       ecmd->tx_coalesce_usecs = enic->tx_coalesce_usecs;
+       ecmd->rx_coalesce_usecs = enic->rx_coalesce_usecs;
+
+       return 0;
+}
+
+static int enic_set_coalesce(struct net_device *netdev,
+       struct ethtool_coalesce *ecmd)
+{
+       struct enic *enic = netdev_priv(netdev);
+       u32 tx_coalesce_usecs;
+       u32 rx_coalesce_usecs;
+       unsigned int i, intr;
+
+       tx_coalesce_usecs = min_t(u32, ecmd->tx_coalesce_usecs,
+               vnic_dev_get_intr_coal_timer_max(enic->vdev));
+       rx_coalesce_usecs = min_t(u32, ecmd->rx_coalesce_usecs,
+               vnic_dev_get_intr_coal_timer_max(enic->vdev));
+
+       switch (vnic_dev_get_intr_mode(enic->vdev)) {
+       case VNIC_DEV_INTR_MODE_INTX:
+               if (tx_coalesce_usecs != rx_coalesce_usecs)
+                       return -EINVAL;
+
+               intr = enic_legacy_io_intr();
+               vnic_intr_coalescing_timer_set(&enic->intr[intr],
+                       tx_coalesce_usecs);
+               break;
+       case VNIC_DEV_INTR_MODE_MSI:
+               if (tx_coalesce_usecs != rx_coalesce_usecs)
+                       return -EINVAL;
+
+               vnic_intr_coalescing_timer_set(&enic->intr[0],
+                       tx_coalesce_usecs);
+               break;
+       case VNIC_DEV_INTR_MODE_MSIX:
+               for (i = 0; i < enic->wq_count; i++) {
+                       intr = enic_msix_wq_intr(enic, i);
+                       vnic_intr_coalescing_timer_set(&enic->intr[intr],
+                               tx_coalesce_usecs);
+               }
+
+               for (i = 0; i < enic->rq_count; i++) {
+                       intr = enic_msix_rq_intr(enic, i);
+                       vnic_intr_coalescing_timer_set(&enic->intr[intr],
+                               rx_coalesce_usecs);
+               }
+
+               break;
+       default:
+               break;
+       }
+
+       enic->tx_coalesce_usecs = tx_coalesce_usecs;
+       enic->rx_coalesce_usecs = rx_coalesce_usecs;
+
+       return 0;
+}
+
+static const struct ethtool_ops enic_ethtool_ops = {
+       .get_settings = enic_get_settings,
+       .get_drvinfo = enic_get_drvinfo,
+       .get_msglevel = enic_get_msglevel,
+       .set_msglevel = enic_set_msglevel,
+       .get_link = ethtool_op_get_link,
+       .get_strings = enic_get_strings,
+       .get_sset_count = enic_get_sset_count,
+       .get_ethtool_stats = enic_get_ethtool_stats,
+       .get_coalesce = enic_get_coalesce,
+       .set_coalesce = enic_set_coalesce,
+};
+
+void enic_set_ethtool_ops(struct net_device *netdev)
+{
+       SET_ETHTOOL_OPS(netdev, &enic_ethtool_ops);
+}
index 992ec2ee64d919333ec1c28151a9a3acd52d25e0..b12b32bc53a687e8bf28512646b05e11e81ca040 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/if.h>
 #include <linux/if_ether.h>
 #include <linux/if_vlan.h>
-#include <linux/ethtool.h>
 #include <linux/in.h>
 #include <linux/ip.h>
 #include <linux/ipv6.h>
@@ -73,57 +72,6 @@ MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 MODULE_DEVICE_TABLE(pci, enic_id_table);
 
-struct enic_stat {
-       char name[ETH_GSTRING_LEN];
-       unsigned int offset;
-};
-
-#define ENIC_TX_STAT(stat)     \
-       { .name = #stat, .offset = offsetof(struct vnic_tx_stats, stat) / 8 }
-#define ENIC_RX_STAT(stat)     \
-       { .name = #stat, .offset = offsetof(struct vnic_rx_stats, stat) / 8 }
-
-static const struct enic_stat enic_tx_stats[] = {
-       ENIC_TX_STAT(tx_frames_ok),
-       ENIC_TX_STAT(tx_unicast_frames_ok),
-       ENIC_TX_STAT(tx_multicast_frames_ok),
-       ENIC_TX_STAT(tx_broadcast_frames_ok),
-       ENIC_TX_STAT(tx_bytes_ok),
-       ENIC_TX_STAT(tx_unicast_bytes_ok),
-       ENIC_TX_STAT(tx_multicast_bytes_ok),
-       ENIC_TX_STAT(tx_broadcast_bytes_ok),
-       ENIC_TX_STAT(tx_drops),
-       ENIC_TX_STAT(tx_errors),
-       ENIC_TX_STAT(tx_tso),
-};
-
-static const struct enic_stat enic_rx_stats[] = {
-       ENIC_RX_STAT(rx_frames_ok),
-       ENIC_RX_STAT(rx_frames_total),
-       ENIC_RX_STAT(rx_unicast_frames_ok),
-       ENIC_RX_STAT(rx_multicast_frames_ok),
-       ENIC_RX_STAT(rx_broadcast_frames_ok),
-       ENIC_RX_STAT(rx_bytes_ok),
-       ENIC_RX_STAT(rx_unicast_bytes_ok),
-       ENIC_RX_STAT(rx_multicast_bytes_ok),
-       ENIC_RX_STAT(rx_broadcast_bytes_ok),
-       ENIC_RX_STAT(rx_drop),
-       ENIC_RX_STAT(rx_no_bufs),
-       ENIC_RX_STAT(rx_errors),
-       ENIC_RX_STAT(rx_rss),
-       ENIC_RX_STAT(rx_crc_errors),
-       ENIC_RX_STAT(rx_frames_64),
-       ENIC_RX_STAT(rx_frames_127),
-       ENIC_RX_STAT(rx_frames_255),
-       ENIC_RX_STAT(rx_frames_511),
-       ENIC_RX_STAT(rx_frames_1023),
-       ENIC_RX_STAT(rx_frames_1518),
-       ENIC_RX_STAT(rx_frames_to_max),
-};
-
-static const unsigned int enic_n_tx_stats = ARRAY_SIZE(enic_tx_stats);
-static const unsigned int enic_n_rx_stats = ARRAY_SIZE(enic_rx_stats);
-
 int enic_is_dynamic(struct enic *enic)
 {
        return enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_DYN;
@@ -148,222 +96,6 @@ int enic_is_valid_vf(struct enic *enic, int vf)
 #endif
 }
 
-static inline unsigned int enic_cq_rq(struct enic *enic, unsigned int rq)
-{
-       return rq;
-}
-
-static inline unsigned int enic_cq_wq(struct enic *enic, unsigned int wq)
-{
-       return enic->rq_count + wq;
-}
-
-static inline unsigned int enic_legacy_io_intr(void)
-{
-       return 0;
-}
-
-static inline unsigned int enic_legacy_err_intr(void)
-{
-       return 1;
-}
-
-static inline unsigned int enic_legacy_notify_intr(void)
-{
-       return 2;
-}
-
-static inline unsigned int enic_msix_rq_intr(struct enic *enic, unsigned int rq)
-{
-       return enic->cq[enic_cq_rq(enic, rq)].interrupt_offset;
-}
-
-static inline unsigned int enic_msix_wq_intr(struct enic *enic, unsigned int wq)
-{
-       return enic->cq[enic_cq_wq(enic, wq)].interrupt_offset;
-}
-
-static inline unsigned int enic_msix_err_intr(struct enic *enic)
-{
-       return enic->rq_count + enic->wq_count;
-}
-
-static inline unsigned int enic_msix_notify_intr(struct enic *enic)
-{
-       return enic->rq_count + enic->wq_count + 1;
-}
-
-static int enic_get_settings(struct net_device *netdev,
-       struct ethtool_cmd *ecmd)
-{
-       struct enic *enic = netdev_priv(netdev);
-
-       ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
-       ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE);
-       ecmd->port = PORT_FIBRE;
-       ecmd->transceiver = XCVR_EXTERNAL;
-
-       if (netif_carrier_ok(netdev)) {
-               ethtool_cmd_speed_set(ecmd, vnic_dev_port_speed(enic->vdev));
-               ecmd->duplex = DUPLEX_FULL;
-       } else {
-               ethtool_cmd_speed_set(ecmd, -1);
-               ecmd->duplex = -1;
-       }
-
-       ecmd->autoneg = AUTONEG_DISABLE;
-
-       return 0;
-}
-
-static void enic_get_drvinfo(struct net_device *netdev,
-       struct ethtool_drvinfo *drvinfo)
-{
-       struct enic *enic = netdev_priv(netdev);
-       struct vnic_devcmd_fw_info *fw_info;
-
-       enic_dev_fw_info(enic, &fw_info);
-
-       strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
-       strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
-       strlcpy(drvinfo->fw_version, fw_info->fw_version,
-               sizeof(drvinfo->fw_version));
-       strlcpy(drvinfo->bus_info, pci_name(enic->pdev),
-               sizeof(drvinfo->bus_info));
-}
-
-static void enic_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
-{
-       unsigned int i;
-
-       switch (stringset) {
-       case ETH_SS_STATS:
-               for (i = 0; i < enic_n_tx_stats; i++) {
-                       memcpy(data, enic_tx_stats[i].name, ETH_GSTRING_LEN);
-                       data += ETH_GSTRING_LEN;
-               }
-               for (i = 0; i < enic_n_rx_stats; i++) {
-                       memcpy(data, enic_rx_stats[i].name, ETH_GSTRING_LEN);
-                       data += ETH_GSTRING_LEN;
-               }
-               break;
-       }
-}
-
-static int enic_get_sset_count(struct net_device *netdev, int sset)
-{
-       switch (sset) {
-       case ETH_SS_STATS:
-               return enic_n_tx_stats + enic_n_rx_stats;
-       default:
-               return -EOPNOTSUPP;
-       }
-}
-
-static void enic_get_ethtool_stats(struct net_device *netdev,
-       struct ethtool_stats *stats, u64 *data)
-{
-       struct enic *enic = netdev_priv(netdev);
-       struct vnic_stats *vstats;
-       unsigned int i;
-
-       enic_dev_stats_dump(enic, &vstats);
-
-       for (i = 0; i < enic_n_tx_stats; i++)
-               *(data++) = ((u64 *)&vstats->tx)[enic_tx_stats[i].offset];
-       for (i = 0; i < enic_n_rx_stats; i++)
-               *(data++) = ((u64 *)&vstats->rx)[enic_rx_stats[i].offset];
-}
-
-static u32 enic_get_msglevel(struct net_device *netdev)
-{
-       struct enic *enic = netdev_priv(netdev);
-       return enic->msg_enable;
-}
-
-static void enic_set_msglevel(struct net_device *netdev, u32 value)
-{
-       struct enic *enic = netdev_priv(netdev);
-       enic->msg_enable = value;
-}
-
-static int enic_get_coalesce(struct net_device *netdev,
-       struct ethtool_coalesce *ecmd)
-{
-       struct enic *enic = netdev_priv(netdev);
-
-       ecmd->tx_coalesce_usecs = enic->tx_coalesce_usecs;
-       ecmd->rx_coalesce_usecs = enic->rx_coalesce_usecs;
-
-       return 0;
-}
-
-static int enic_set_coalesce(struct net_device *netdev,
-       struct ethtool_coalesce *ecmd)
-{
-       struct enic *enic = netdev_priv(netdev);
-       u32 tx_coalesce_usecs;
-       u32 rx_coalesce_usecs;
-       unsigned int i, intr;
-
-       tx_coalesce_usecs = min_t(u32, ecmd->tx_coalesce_usecs,
-               vnic_dev_get_intr_coal_timer_max(enic->vdev));
-       rx_coalesce_usecs = min_t(u32, ecmd->rx_coalesce_usecs,
-               vnic_dev_get_intr_coal_timer_max(enic->vdev));
-
-       switch (vnic_dev_get_intr_mode(enic->vdev)) {
-       case VNIC_DEV_INTR_MODE_INTX:
-               if (tx_coalesce_usecs != rx_coalesce_usecs)
-                       return -EINVAL;
-
-               intr = enic_legacy_io_intr();
-               vnic_intr_coalescing_timer_set(&enic->intr[intr],
-                       tx_coalesce_usecs);
-               break;
-       case VNIC_DEV_INTR_MODE_MSI:
-               if (tx_coalesce_usecs != rx_coalesce_usecs)
-                       return -EINVAL;
-
-               vnic_intr_coalescing_timer_set(&enic->intr[0],
-                       tx_coalesce_usecs);
-               break;
-       case VNIC_DEV_INTR_MODE_MSIX:
-               for (i = 0; i < enic->wq_count; i++) {
-                       intr = enic_msix_wq_intr(enic, i);
-                       vnic_intr_coalescing_timer_set(&enic->intr[intr],
-                               tx_coalesce_usecs);
-               }
-
-               for (i = 0; i < enic->rq_count; i++) {
-                       intr = enic_msix_rq_intr(enic, i);
-                       vnic_intr_coalescing_timer_set(&enic->intr[intr],
-                               rx_coalesce_usecs);
-               }
-
-               break;
-       default:
-               break;
-       }
-
-       enic->tx_coalesce_usecs = tx_coalesce_usecs;
-       enic->rx_coalesce_usecs = rx_coalesce_usecs;
-
-       return 0;
-}
-
-static const struct ethtool_ops enic_ethtool_ops = {
-       .get_settings = enic_get_settings,
-       .get_drvinfo = enic_get_drvinfo,
-       .get_msglevel = enic_get_msglevel,
-       .set_msglevel = enic_set_msglevel,
-       .get_link = ethtool_op_get_link,
-       .get_strings = enic_get_strings,
-       .get_sset_count = enic_get_sset_count,
-       .get_ethtool_stats = enic_get_ethtool_stats,
-       .get_coalesce = enic_get_coalesce,
-       .set_coalesce = enic_set_coalesce,
-};
-
 static void enic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf)
 {
        struct enic *enic = vnic_dev_priv(wq->vdev);
@@ -2496,7 +2228,7 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                netdev->netdev_ops = &enic_netdev_ops;
 
        netdev->watchdog_timeo = 2 * HZ;
-       netdev->ethtool_ops = &enic_ethtool_ops;
+       enic_set_ethtool_ops(netdev);
 
        netdev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
        if (ENIC_SETTING(enic, LOOP)) {
index 6e6e0a117ee2fe16061ae8e0b77a51aaacd3336b..613d8879b3451da3ba47c42fa5ab8652a31b9d4b 100644 (file)
@@ -1339,6 +1339,10 @@ int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, u32 en_flags,
        if (!status) {
                struct be_cmd_resp_if_create *resp = embedded_payload(wrb);
                *if_handle = le32_to_cpu(resp->interface_id);
+
+               /* Hack to retrieve VF's pmac-id on BE3 */
+               if (BE3_chip(adapter) && !be_physfn(adapter))
+                       adapter->pmac_id[0] = le32_to_cpu(resp->pmac_id);
        }
 
 err:
@@ -2606,9 +2610,44 @@ err:
        return status;
 }
 
-/* Uses synchronous MCCQ */
+/* Set privilege(s) for a function */
+int be_cmd_set_fn_privileges(struct be_adapter *adapter, u32 privileges,
+                            u32 domain)
+{
+       struct be_mcc_wrb *wrb;
+       struct be_cmd_req_set_fn_privileges *req;
+       int status;
+
+       spin_lock_bh(&adapter->mcc_lock);
+
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+               status = -EBUSY;
+               goto err;
+       }
+
+       req = embedded_payload(wrb);
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+                              OPCODE_COMMON_SET_FN_PRIVILEGES, sizeof(*req),
+                              wrb, NULL);
+       req->hdr.domain = domain;
+       if (lancer_chip(adapter))
+               req->privileges_lancer = cpu_to_le32(privileges);
+       else
+               req->privileges = cpu_to_le32(privileges);
+
+       status = be_mcc_notify_wait(adapter);
+err:
+       spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+}
+
+/* pmac_id_valid: true => pmac_id is supplied and MAC address is requested.
+ * pmac_id_valid: false => pmac_id or MAC address is requested.
+ *               If pmac_id is returned, pmac_id_valid is returned as true
+ */
 int be_cmd_get_mac_from_list(struct be_adapter *adapter, u8 *mac,
-                            bool *pmac_id_active, u32 *pmac_id, u8 domain)
+                            bool *pmac_id_valid, u32 *pmac_id, u8 domain)
 {
        struct be_mcc_wrb *wrb;
        struct be_cmd_req_get_mac_list *req;
@@ -2644,12 +2683,25 @@ int be_cmd_get_mac_from_list(struct be_adapter *adapter, u8 *mac,
                               get_mac_list_cmd.size, wrb, &get_mac_list_cmd);
        req->hdr.domain = domain;
        req->mac_type = MAC_ADDRESS_TYPE_NETWORK;
-       req->perm_override = 1;
+       if (*pmac_id_valid) {
+               req->mac_id = cpu_to_le32(*pmac_id);
+               req->iface_id = cpu_to_le16(adapter->if_handle);
+               req->perm_override = 0;
+       } else {
+               req->perm_override = 1;
+       }
 
        status = be_mcc_notify_wait(adapter);
        if (!status) {
                struct be_cmd_resp_get_mac_list *resp =
                                                get_mac_list_cmd.va;
+
+               if (*pmac_id_valid) {
+                       memcpy(mac, resp->macid_macaddr.mac_addr_id.macaddr,
+                              ETH_ALEN);
+                       goto out;
+               }
+
                mac_count = resp->true_mac_count + resp->pseudo_mac_count;
                /* Mac list returned could contain one or more active mac_ids
                 * or one or more true or pseudo permanant mac addresses.
@@ -2667,14 +2719,14 @@ int be_cmd_get_mac_from_list(struct be_adapter *adapter, u8 *mac,
                         * is 6 bytes
                         */
                        if (mac_addr_size == sizeof(u32)) {
-                               *pmac_id_active = true;
+                               *pmac_id_valid = true;
                                mac_id = mac_entry->mac_addr_id.s_mac_id.mac_id;
                                *pmac_id = le32_to_cpu(mac_id);
                                goto out;
                        }
                }
                /* If no active mac_id found, return first mac addr */
-               *pmac_id_active = false;
+               *pmac_id_valid = false;
                memcpy(mac, resp->macaddr_list[0].mac_addr_id.macaddr,
                                                                ETH_ALEN);
        }
@@ -2686,6 +2738,41 @@ out:
        return status;
 }
 
+int be_cmd_get_active_mac(struct be_adapter *adapter, u32 curr_pmac_id, u8 *mac)
+{
+       bool active = true;
+
+       if (BEx_chip(adapter))
+               return be_cmd_mac_addr_query(adapter, mac, false,
+                                            adapter->if_handle, curr_pmac_id);
+       else
+               /* Fetch the MAC address using pmac_id */
+               return be_cmd_get_mac_from_list(adapter, mac, &active,
+                                               &curr_pmac_id, 0);
+}
+
+int be_cmd_get_perm_mac(struct be_adapter *adapter, u8 *mac)
+{
+       int status;
+       bool pmac_valid = false;
+
+       memset(mac, 0, ETH_ALEN);
+
+       if (BEx_chip(adapter)) {
+               if (be_physfn(adapter))
+                       status = be_cmd_mac_addr_query(adapter, mac, true, 0,
+                                                      0);
+               else
+                       status = be_cmd_mac_addr_query(adapter, mac, false,
+                                                      adapter->if_handle, 0);
+       } else {
+               status = be_cmd_get_mac_from_list(adapter, mac, &pmac_valid,
+                                                 NULL, 0);
+       }
+
+       return status;
+}
+
 /* Uses synchronous MCCQ */
 int be_cmd_set_mac_list(struct be_adapter *adapter, u8 *mac_array,
                        u8 mac_count, u32 domain)
@@ -2729,6 +2816,25 @@ err:
        return status;
 }
 
+/* Wrapper to delete any active MACs and provision the new mac.
+ * Changes to MAC_LIST are allowed iff none of the MAC addresses in the
+ * current list are active.
+ */
+int be_cmd_set_mac(struct be_adapter *adapter, u8 *mac, int if_id, u32 dom)
+{
+       bool active_mac = false;
+       u8 old_mac[ETH_ALEN];
+       u32 pmac_id;
+       int status;
+
+       status = be_cmd_get_mac_from_list(adapter, old_mac, &active_mac,
+                                         &pmac_id, dom);
+       if (!status && active_mac)
+               be_cmd_pmac_del(adapter, if_id, pmac_id, dom);
+
+       return be_cmd_set_mac_list(adapter, mac, mac ? 1 : 0, dom);
+}
+
 int be_cmd_set_hsw_config(struct be_adapter *adapter, u16 pvid,
                        u32 domain, u16 intf_id)
 {
index 5228d88c5a024e8e20be18e4f9fec69de7865e42..eb541f0dfee8f74646a4f6470e1eebeeeb944612 100644 (file)
@@ -202,6 +202,7 @@ struct be_mcc_mailbox {
 #define OPCODE_COMMON_READ_TRANSRECV_DATA              73
 #define OPCODE_COMMON_GET_PORT_NAME                    77
 #define OPCODE_COMMON_SET_INTERRUPT_ENABLE             89
+#define OPCODE_COMMON_SET_FN_PRIVILEGES                        100
 #define OPCODE_COMMON_GET_PHY_DETAILS                  102
 #define OPCODE_COMMON_SET_DRIVER_FUNCTION_CAP          103
 #define OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES   121
@@ -1474,6 +1475,11 @@ struct be_cmd_resp_get_fn_privileges {
        u32 privilege_mask;
 };
 
+struct be_cmd_req_set_fn_privileges {
+       struct be_cmd_req_hdr hdr;
+       u32 privileges;         /* Used by BE3, SH-R */
+       u32 privileges_lancer;  /* Used by Lancer */
+};
 
 /******************** GET/SET_MACLIST  **************************/
 #define BE_MAX_MAC                     64
@@ -1921,11 +1927,18 @@ extern int be_cmd_get_reg_len(struct be_adapter *adapter, u32 *log_size);
 extern void be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf);
 extern int be_cmd_get_fn_privileges(struct be_adapter *adapter,
                                    u32 *privilege, u32 domain);
+extern int be_cmd_set_fn_privileges(struct be_adapter *adapter,
+                                   u32 privileges, u32 vf_num);
 extern int be_cmd_get_mac_from_list(struct be_adapter *adapter, u8 *mac,
                                    bool *pmac_id_active, u32 *pmac_id,
                                    u8 domain);
+extern int be_cmd_get_active_mac(struct be_adapter *adapter, u32 pmac_id,
+                                u8 *mac);
+extern int be_cmd_get_perm_mac(struct be_adapter *adapter, u8 *mac);
 extern int be_cmd_set_mac_list(struct be_adapter *adapter, u8 *mac_array,
                                                u8 mac_count, u32 domain);
+extern int be_cmd_set_mac(struct be_adapter *adapter, u8 *mac, int if_id,
+                         u32 dom);
 extern int be_cmd_set_hsw_config(struct be_adapter *adapter, u16 pvid,
                        u32 domain, u16 intf_id);
 extern int be_cmd_get_hsw_config(struct be_adapter *adapter, u16 *pvid,
index 181edb522450ada0c9ba72e9a736d312594cc183..3df15033b91a9bbac4d0fab2af3b7c3ca4944ea9 100644 (file)
@@ -247,54 +247,54 @@ void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, u16 num_popped)
 static int be_mac_addr_set(struct net_device *netdev, void *p)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
+       struct device *dev = &adapter->pdev->dev;
        struct sockaddr *addr = p;
-       int status = 0;
-       u8 current_mac[ETH_ALEN];
-       u32 pmac_id = adapter->pmac_id[0];
-       bool active_mac = true;
+       int status;
+       u8 mac[ETH_ALEN];
+       u32 old_pmac_id = adapter->pmac_id[0], curr_pmac_id = 0;
 
        if (!is_valid_ether_addr(addr->sa_data))
                return -EADDRNOTAVAIL;
 
-       /* For BE VF, MAC address is already activated by PF.
-        * Hence only operation left is updating netdev->devaddr.
-        * Update it if user is passing the same MAC which was used
-        * during configuring VF MAC from PF(Hypervisor).
+       /* The PMAC_ADD cmd may fail if the VF doesn't have FILTMGMT
+        * privilege or if PF did not provision the new MAC address.
+        * On BE3, this cmd will always fail if the VF doesn't have the
+        * FILTMGMT privilege. This failure is OK, only if the PF programmed
+        * the MAC for the VF.
         */
-       if (!lancer_chip(adapter) && !be_physfn(adapter)) {
-               status = be_cmd_mac_addr_query(adapter, current_mac,
-                                              false, adapter->if_handle, 0);
-               if (!status && !memcmp(current_mac, addr->sa_data, ETH_ALEN))
-                       goto done;
-               else
-                       goto err;
-       }
+       status = be_cmd_pmac_add(adapter, (u8 *)addr->sa_data,
+                                adapter->if_handle, &adapter->pmac_id[0], 0);
+       if (!status) {
+               curr_pmac_id = adapter->pmac_id[0];
 
-       if (!memcmp(addr->sa_data, netdev->dev_addr, ETH_ALEN))
-               goto done;
+               /* Delete the old programmed MAC. This call may fail if the
+                * old MAC was already deleted by the PF driver.
+                */
+               if (adapter->pmac_id[0] != old_pmac_id)
+                       be_cmd_pmac_del(adapter, adapter->if_handle,
+                                       old_pmac_id, 0);
+       }
 
-       /* For Lancer check if any MAC is active.
-        * If active, get its mac id.
+       /* Decide if the new MAC is successfully activated only after
+        * querying the FW
         */
-       if (lancer_chip(adapter) && !be_physfn(adapter))
-               be_cmd_get_mac_from_list(adapter, current_mac, &active_mac,
-                                        &pmac_id, 0);
-
-       status = be_cmd_pmac_add(adapter, (u8 *)addr->sa_data,
-                                adapter->if_handle,
-                                &adapter->pmac_id[0], 0);
-
+       status = be_cmd_get_active_mac(adapter, curr_pmac_id, mac);
        if (status)
                goto err;
 
-       if (active_mac)
-               be_cmd_pmac_del(adapter, adapter->if_handle,
-                               pmac_id, 0);
-done:
+       /* The MAC change did not happen, either due to lack of privilege
+        * or PF didn't pre-provision.
+        */
+       if (memcmp(addr->sa_data, mac, ETH_ALEN)) {
+               status = -EPERM;
+               goto err;
+       }
+
        memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+       dev_info(dev, "MAC address changed to %pM\n", mac);
        return 0;
 err:
-       dev_err(&adapter->pdev->dev, "MAC %pM set Failed\n", addr->sa_data);
+       dev_warn(dev, "MAC address change to %pM failed\n", addr->sa_data);
        return status;
 }
 
@@ -1146,9 +1146,6 @@ static int be_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
        struct be_adapter *adapter = netdev_priv(netdev);
        struct be_vf_cfg *vf_cfg = &adapter->vf_cfg[vf];
        int status;
-       bool active_mac = false;
-       u32 pmac_id;
-       u8 old_mac[ETH_ALEN];
 
        if (!sriov_enabled(adapter))
                return -EPERM;
@@ -1156,20 +1153,15 @@ static int be_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
        if (!is_valid_ether_addr(mac) || vf >= adapter->num_vfs)
                return -EINVAL;
 
-       if (lancer_chip(adapter)) {
-               status = be_cmd_get_mac_from_list(adapter, old_mac, &active_mac,
-                                                 &pmac_id, vf + 1);
-               if (!status && active_mac)
-                       be_cmd_pmac_del(adapter, vf_cfg->if_handle,
-                                       pmac_id, vf + 1);
-
-               status = be_cmd_set_mac_list(adapter,  mac, 1, vf + 1);
-       } else {
-               status = be_cmd_pmac_del(adapter, vf_cfg->if_handle,
-                                        vf_cfg->pmac_id, vf + 1);
+       if (BEx_chip(adapter)) {
+               be_cmd_pmac_del(adapter, vf_cfg->if_handle, vf_cfg->pmac_id,
+                               vf + 1);
 
                status = be_cmd_pmac_add(adapter, mac, vf_cfg->if_handle,
                                         &vf_cfg->pmac_id, vf + 1);
+       } else {
+               status = be_cmd_set_mac(adapter, mac, vf_cfg->if_handle,
+                                       vf + 1);
        }
 
        if (status)
@@ -2735,13 +2727,13 @@ static int be_vf_eth_addr_config(struct be_adapter *adapter)
        be_vf_eth_addr_generate(adapter, mac);
 
        for_all_vfs(adapter, vf_cfg, vf) {
-               if (lancer_chip(adapter)) {
-                       status = be_cmd_set_mac_list(adapter,  mac, 1, vf + 1);
-               } else {
+               if (BEx_chip(adapter))
                        status = be_cmd_pmac_add(adapter, mac,
                                                 vf_cfg->if_handle,
                                                 &vf_cfg->pmac_id, vf + 1);
-               }
+               else
+                       status = be_cmd_set_mac(adapter, mac, vf_cfg->if_handle,
+                                               vf + 1);
 
                if (status)
                        dev_err(&adapter->pdev->dev,
@@ -2759,7 +2751,7 @@ static int be_vfs_mac_query(struct be_adapter *adapter)
        int status, vf;
        u8 mac[ETH_ALEN];
        struct be_vf_cfg *vf_cfg;
-       bool active;
+       bool active = false;
 
        for_all_vfs(adapter, vf_cfg, vf) {
                be_cmd_get_mac_from_list(adapter, mac, &active,
@@ -2788,11 +2780,12 @@ static void be_vf_clear(struct be_adapter *adapter)
        pci_disable_sriov(adapter->pdev);
 
        for_all_vfs(adapter, vf_cfg, vf) {
-               if (lancer_chip(adapter))
-                       be_cmd_set_mac_list(adapter, NULL, 0, vf + 1);
-               else
+               if (BEx_chip(adapter))
                        be_cmd_pmac_del(adapter, vf_cfg->if_handle,
                                        vf_cfg->pmac_id, vf + 1);
+               else
+                       be_cmd_set_mac(adapter, NULL, vf_cfg->if_handle,
+                                      vf + 1);
 
                be_cmd_if_destroy(adapter, vf_cfg->if_handle, vf + 1);
        }
@@ -2803,7 +2796,7 @@ done:
 
 static int be_clear(struct be_adapter *adapter)
 {
-       int i = 1;
+       int i;
 
        if (adapter->flags & BE_FLAGS_WORKER_SCHEDULED) {
                cancel_delayed_work_sync(&adapter->work);
@@ -2813,9 +2806,11 @@ static int be_clear(struct be_adapter *adapter)
        if (sriov_enabled(adapter))
                be_vf_clear(adapter);
 
-       for (; adapter->uc_macs > 0; adapter->uc_macs--, i++)
+       /* delete the primary mac along with the uc-mac list */
+       for (i = 0; i < (adapter->uc_macs + 1); i++)
                be_cmd_pmac_del(adapter, adapter->if_handle,
-                       adapter->pmac_id[i], 0);
+                               adapter->pmac_id[i], 0);
+       adapter->uc_macs = 0;
 
        be_cmd_if_destroy(adapter, adapter->if_handle,  0);
 
@@ -2880,6 +2875,7 @@ static int be_vf_setup(struct be_adapter *adapter)
        u16 def_vlan, lnk_speed;
        int status, old_vfs, vf;
        struct device *dev = &adapter->pdev->dev;
+       u32 privileges;
 
        old_vfs = pci_num_vf(adapter->pdev);
        if (old_vfs) {
@@ -2923,6 +2919,18 @@ static int be_vf_setup(struct be_adapter *adapter)
        }
 
        for_all_vfs(adapter, vf_cfg, vf) {
+               /* Allow VFs to programs MAC/VLAN filters */
+               status = be_cmd_get_fn_privileges(adapter, &privileges, vf + 1);
+               if (!status && !(privileges & BE_PRIV_FILTMGMT)) {
+                       status = be_cmd_set_fn_privileges(adapter,
+                                                         privileges |
+                                                         BE_PRIV_FILTMGMT,
+                                                         vf + 1);
+                       if (!status)
+                               dev_info(dev, "VF%d has FILTMGMT privilege\n",
+                                        vf);
+               }
+
                /* BE3 FW, by default, caps VF TX-rate to 100mbps.
                 * Allow full available bandwidth
                 */
@@ -2971,41 +2979,6 @@ static void be_setup_init(struct be_adapter *adapter)
                adapter->cmd_privileges = MIN_PRIVILEGES;
 }
 
-static int be_get_mac_addr(struct be_adapter *adapter, u8 *mac, u32 if_handle,
-                          bool *active_mac, u32 *pmac_id)
-{
-       int status = 0;
-
-       if (!is_zero_ether_addr(adapter->netdev->perm_addr)) {
-               memcpy(mac, adapter->netdev->dev_addr, ETH_ALEN);
-               if (!lancer_chip(adapter) && !be_physfn(adapter))
-                       *active_mac = true;
-               else
-                       *active_mac = false;
-
-               return status;
-       }
-
-       if (lancer_chip(adapter)) {
-               status = be_cmd_get_mac_from_list(adapter, mac,
-                                                 active_mac, pmac_id, 0);
-               if (*active_mac) {
-                       status = be_cmd_mac_addr_query(adapter, mac, false,
-                                                      if_handle, *pmac_id);
-               }
-       } else if (be_physfn(adapter)) {
-               /* For BE3, for PF get permanent MAC */
-               status = be_cmd_mac_addr_query(adapter, mac, true, 0, 0);
-               *active_mac = false;
-       } else {
-               /* For BE3, for VF get soft MAC assigned by PF*/
-               status = be_cmd_mac_addr_query(adapter, mac, false,
-                                              if_handle, 0);
-               *active_mac = true;
-       }
-       return status;
-}
-
 static void be_get_resources(struct be_adapter *adapter)
 {
        u16 dev_num_vfs;
@@ -3111,14 +3084,38 @@ err:
        return status;
 }
 
+static int be_mac_setup(struct be_adapter *adapter)
+{
+       u8 mac[ETH_ALEN];
+       int status;
+
+       if (is_zero_ether_addr(adapter->netdev->dev_addr)) {
+               status = be_cmd_get_perm_mac(adapter, mac);
+               if (status)
+                       return status;
+
+               memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN);
+               memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN);
+       } else {
+               /* Maybe the HW was reset; dev_addr must be re-programmed */
+               memcpy(mac, adapter->netdev->dev_addr, ETH_ALEN);
+       }
+
+       /* On BE3 VFs this cmd may fail due to lack of privilege.
+        * Ignore the failure as in this case pmac_id is fetched
+        * in the IFACE_CREATE cmd.
+        */
+       be_cmd_pmac_add(adapter, mac, adapter->if_handle,
+                       &adapter->pmac_id[0], 0);
+       return 0;
+}
+
 static int be_setup(struct be_adapter *adapter)
 {
        struct device *dev = &adapter->pdev->dev;
        u32 en_flags;
        u32 tx_fc, rx_fc;
        int status;
-       u8 mac[ETH_ALEN];
-       bool active_mac;
 
        be_setup_init(adapter);
 
@@ -3158,36 +3155,18 @@ static int be_setup(struct be_adapter *adapter)
 
        en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
                        BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_PASS_L3L4_ERRORS;
-
        if (adapter->function_caps & BE_FUNCTION_CAPS_RSS)
                en_flags |= BE_IF_FLAGS_RSS;
-
        en_flags = en_flags & adapter->if_cap_flags;
-
        status = be_cmd_if_create(adapter, adapter->if_cap_flags, en_flags,
                                  &adapter->if_handle, 0);
        if (status != 0)
                goto err;
 
-       memset(mac, 0, ETH_ALEN);
-       active_mac = false;
-       status = be_get_mac_addr(adapter, mac, adapter->if_handle,
-                                &active_mac, &adapter->pmac_id[0]);
-       if (status != 0)
+       status = be_mac_setup(adapter);
+       if (status)
                goto err;
 
-       if (!active_mac) {
-               status = be_cmd_pmac_add(adapter, mac, adapter->if_handle,
-                                        &adapter->pmac_id[0], 0);
-               if (status != 0)
-                       goto err;
-       }
-
-       if (is_zero_ether_addr(adapter->netdev->dev_addr)) {
-               memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN);
-               memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN);
-       }
-
        status = be_tx_qs_create(adapter);
        if (status)
                goto err;
@@ -4253,7 +4232,7 @@ static int be_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id)
 
        status = pci_enable_pcie_error_reporting(pdev);
        if (status)
-               dev_err(&pdev->dev, "Could not use PCIe error reporting\n");
+               dev_info(&pdev->dev, "Could not use PCIe error reporting\n");
 
        status = be_ctrl_init(adapter);
        if (status)
index 2b0a0ea4f8e7eab210535c703b2a3d4987546d1d..ae236009f1a8c5dc857326751ce28ea68b2a4681 100644 (file)
@@ -259,6 +259,7 @@ struct bufdesc_ex {
 struct fec_enet_delayed_work {
        struct delayed_work delay_work;
        bool timeout;
+       bool trig_tx;
 };
 
 /* The FEC buffer descriptors track the ring buffers.  The rx_bd_base and
index d3ad5ea711d316e1455cbe7d8eab61ecad8cb3d4..fdf9307ba9e6ee412e832266d5f05edcf9269334 100644 (file)
@@ -93,6 +93,20 @@ static void set_multicast_list(struct net_device *ndev);
 #define FEC_QUIRK_HAS_CSUM             (1 << 5)
 /* Controller has hardware vlan support */
 #define FEC_QUIRK_HAS_VLAN             (1 << 6)
+/* ENET IP errata ERR006358
+ *
+ * If the ready bit in the transmit buffer descriptor (TxBD[R]) is previously
+ * detected as not set during a prior frame transmission, then the
+ * ENET_TDAR[TDAR] bit is cleared at a later time, even if additional TxBDs
+ * were added to the ring and the ENET_TDAR[TDAR] bit is set. This results in
+ * If the ready bit in the transmit buffer descriptor (TxBD[R]) is previously
+ * detected as not set during a prior frame transmission, then the
+ * ENET_TDAR[TDAR] bit is cleared at a later time, even if additional TxBDs
+ * were added to the ring and the ENET_TDAR[TDAR] bit is set. This results in
+ * frames not being transmitted until there is a 0-to-1 transition on
+ * ENET_TDAR[TDAR].
+ */
+#define FEC_QUIRK_ERR006358            (1 << 7)
 
 static struct platform_device_id fec_devtype[] = {
        {
@@ -112,7 +126,7 @@ static struct platform_device_id fec_devtype[] = {
                .name = "imx6q-fec",
                .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
                                FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
-                               FEC_QUIRK_HAS_VLAN,
+                               FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR006358,
        }, {
                .name = "mvf600-fec",
                .driver_data = FEC_QUIRK_ENET_MAC,
@@ -275,16 +289,11 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        struct fec_enet_private *fep = netdev_priv(ndev);
        const struct platform_device_id *id_entry =
                                platform_get_device_id(fep->pdev);
-       struct bufdesc *bdp;
+       struct bufdesc *bdp, *bdp_pre;
        void *bufaddr;
        unsigned short  status;
        unsigned int index;
 
-       if (!fep->link) {
-               /* Link is down or auto-negotiation is in progress. */
-               return NETDEV_TX_BUSY;
-       }
-
        /* Fill in a Tx ring entry */
        bdp = fep->cur_tx;
 
@@ -370,6 +379,15 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                                ebdp->cbd_esc |= BD_ENET_TX_PINS;
                }
        }
+
+       bdp_pre = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex);
+       if ((id_entry->driver_data & FEC_QUIRK_ERR006358) &&
+           !(bdp_pre->cbd_sc & BD_ENET_TX_READY)) {
+               fep->delay_work.trig_tx = true;
+               schedule_delayed_work(&(fep->delay_work.delay_work),
+                                       msecs_to_jiffies(1));
+       }
+
        /* If this was the last BD in the ring, start at the beginning again. */
        if (status & BD_ENET_TX_WRAP)
                bdp = fep->tx_bd_base;
@@ -689,6 +707,11 @@ static void fec_enet_work(struct work_struct *work)
                fec_restart(fep->netdev, fep->full_duplex);
                netif_wake_queue(fep->netdev);
        }
+
+       if (fep->delay_work.trig_tx) {
+               fep->delay_work.trig_tx = false;
+               writel(0, fep->hwp + FEC_X_DES_ACTIVE);
+       }
 }
 
 static void
@@ -2033,10 +2056,6 @@ fec_probe(struct platform_device *pdev)
        if (of_id)
                pdev->id_entry = of_id->data;
 
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!r)
-               return -ENXIO;
-
        /* Init network device */
        ndev = alloc_etherdev(sizeof(struct fec_enet_private));
        if (!ndev)
@@ -2054,6 +2073,7 @@ fec_probe(struct platform_device *pdev)
                fep->pause_flag |= FEC_PAUSE_FLAG_AUTONEG;
 #endif
 
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        fep->hwp = devm_ioremap_resource(&pdev->dev, r);
        if (IS_ERR(fep->hwp)) {
                ret = PTR_ERR(fep->hwp);
@@ -2103,10 +2123,25 @@ fec_probe(struct platform_device *pdev)
                fep->bufdesc_ex = 0;
        }
 
-       clk_prepare_enable(fep->clk_ahb);
-       clk_prepare_enable(fep->clk_ipg);
-       clk_prepare_enable(fep->clk_enet_out);
-       clk_prepare_enable(fep->clk_ptp);
+       ret = clk_prepare_enable(fep->clk_ahb);
+       if (ret)
+               goto failed_clk;
+
+       ret = clk_prepare_enable(fep->clk_ipg);
+       if (ret)
+               goto failed_clk_ipg;
+
+       if (fep->clk_enet_out) {
+               ret = clk_prepare_enable(fep->clk_enet_out);
+               if (ret)
+                       goto failed_clk_enet_out;
+       }
+
+       if (fep->clk_ptp) {
+               ret = clk_prepare_enable(fep->clk_ptp);
+               if (ret)
+                       goto failed_clk_ptp;
+       }
 
        fep->reg_phy = devm_regulator_get(&pdev->dev, "phy");
        if (!IS_ERR(fep->reg_phy)) {
@@ -2137,14 +2172,10 @@ fec_probe(struct platform_device *pdev)
                        ret = irq;
                        goto failed_irq;
                }
-               ret = request_irq(irq, fec_enet_interrupt, IRQF_DISABLED, pdev->name, ndev);
-               if (ret) {
-                       while (--i >= 0) {
-                               irq = platform_get_irq(pdev, i);
-                               free_irq(irq, ndev);
-                       }
+               ret = devm_request_irq(&pdev->dev, irq, fec_enet_interrupt,
+                                      IRQF_DISABLED, pdev->name, ndev);
+               if (ret)
                        goto failed_irq;
-               }
        }
 
        ret = fec_enet_mii_init(pdev);
@@ -2168,19 +2199,19 @@ failed_register:
        fec_enet_mii_remove(fep);
 failed_mii_init:
 failed_irq:
-       for (i = 0; i < FEC_IRQ_NUM; i++) {
-               irq = platform_get_irq(pdev, i);
-               if (irq > 0)
-                       free_irq(irq, ndev);
-       }
 failed_init:
        if (fep->reg_phy)
                regulator_disable(fep->reg_phy);
 failed_regulator:
-       clk_disable_unprepare(fep->clk_ahb);
+       if (fep->clk_ptp)
+               clk_disable_unprepare(fep->clk_ptp);
+failed_clk_ptp:
+       if (fep->clk_enet_out)
+               clk_disable_unprepare(fep->clk_enet_out);
+failed_clk_enet_out:
        clk_disable_unprepare(fep->clk_ipg);
-       clk_disable_unprepare(fep->clk_enet_out);
-       clk_disable_unprepare(fep->clk_ptp);
+failed_clk_ipg:
+       clk_disable_unprepare(fep->clk_ahb);
 failed_clk:
 failed_ioremap:
        free_netdev(ndev);
@@ -2193,25 +2224,21 @@ fec_drv_remove(struct platform_device *pdev)
 {
        struct net_device *ndev = platform_get_drvdata(pdev);
        struct fec_enet_private *fep = netdev_priv(ndev);
-       int i;
 
        cancel_delayed_work_sync(&(fep->delay_work.delay_work));
        unregister_netdev(ndev);
        fec_enet_mii_remove(fep);
        del_timer_sync(&fep->time_keep);
-       for (i = 0; i < FEC_IRQ_NUM; i++) {
-               int irq = platform_get_irq(pdev, i);
-               if (irq > 0)
-                       free_irq(irq, ndev);
-       }
        if (fep->reg_phy)
                regulator_disable(fep->reg_phy);
-       clk_disable_unprepare(fep->clk_ptp);
+       if (fep->clk_ptp)
+               clk_disable_unprepare(fep->clk_ptp);
        if (fep->ptp_clock)
                ptp_clock_unregister(fep->ptp_clock);
-       clk_disable_unprepare(fep->clk_enet_out);
-       clk_disable_unprepare(fep->clk_ahb);
+       if (fep->clk_enet_out)
+               clk_disable_unprepare(fep->clk_enet_out);
        clk_disable_unprepare(fep->clk_ipg);
+       clk_disable_unprepare(fep->clk_ahb);
        free_netdev(ndev);
 
        return 0;
@@ -2228,9 +2255,12 @@ fec_suspend(struct device *dev)
                fec_stop(ndev);
                netif_device_detach(ndev);
        }
-       clk_disable_unprepare(fep->clk_enet_out);
-       clk_disable_unprepare(fep->clk_ahb);
+       if (fep->clk_ptp)
+               clk_disable_unprepare(fep->clk_ptp);
+       if (fep->clk_enet_out)
+               clk_disable_unprepare(fep->clk_enet_out);
        clk_disable_unprepare(fep->clk_ipg);
+       clk_disable_unprepare(fep->clk_ahb);
 
        if (fep->reg_phy)
                regulator_disable(fep->reg_phy);
@@ -2251,15 +2281,44 @@ fec_resume(struct device *dev)
                        return ret;
        }
 
-       clk_prepare_enable(fep->clk_enet_out);
-       clk_prepare_enable(fep->clk_ahb);
-       clk_prepare_enable(fep->clk_ipg);
+       ret = clk_prepare_enable(fep->clk_ahb);
+       if (ret)
+               goto failed_clk_ahb;
+
+       ret = clk_prepare_enable(fep->clk_ipg);
+       if (ret)
+               goto failed_clk_ipg;
+
+       if (fep->clk_enet_out) {
+               ret = clk_prepare_enable(fep->clk_enet_out);
+               if (ret)
+                       goto failed_clk_enet_out;
+       }
+
+       if (fep->clk_ptp) {
+               ret = clk_prepare_enable(fep->clk_ptp);
+               if (ret)
+                       goto failed_clk_ptp;
+       }
+
        if (netif_running(ndev)) {
                fec_restart(ndev, fep->full_duplex);
                netif_device_attach(ndev);
        }
 
        return 0;
+
+failed_clk_ptp:
+       if (fep->clk_enet_out)
+               clk_disable_unprepare(fep->clk_enet_out);
+failed_clk_enet_out:
+       clk_disable_unprepare(fep->clk_ipg);
+failed_clk_ipg:
+       clk_disable_unprepare(fep->clk_ahb);
+failed_clk_ahb:
+       if (fep->reg_phy)
+               regulator_disable(fep->reg_phy);
+       return ret;
 }
 #endif /* CONFIG_PM_SLEEP */
 
@@ -2279,4 +2338,5 @@ static struct platform_driver fec_driver = {
 
 module_platform_driver(fec_driver);
 
+MODULE_ALIAS("platform:"DRIVER_NAME);
 MODULE_LICENSE("GPL");
index 8d2db7b808b7cb4321dbc6edeb12ebab94b7b0f0..dbb34f7ce448fc0576adea06a9b6e8025c772c6f 100644 (file)
@@ -593,7 +593,6 @@ static int gfar_parse_group(struct device_node *np,
                        return -EINVAL;
        }
 
-       grp->grp_id = priv->num_grps;
        grp->priv = priv;
        spin_lock_init(&grp->grplock);
        if (priv->mode == MQ_MG_MODE) {
index 04b552cd419d5f2d8b1546c8371b5ebbe13bf8ff..ee19f2c138a60ae82003bcda1cfdae1695ca7b91 100644 (file)
@@ -1009,7 +1009,6 @@ struct gfar_irqinfo {
  *     @napi: the napi poll function
  *     @priv: back pointer to the priv structure
  *     @regs: the ioremapped register space for this group
- *     @grp_id: group id for this group
  *     @irqinfo: TX/RX/ER irq data for this group
  */
 
@@ -1018,11 +1017,10 @@ struct gfar_priv_grp {
        struct  napi_struct napi;
        struct gfar_private *priv;
        struct gfar __iomem *regs;
-       unsigned int grp_id;
+       unsigned int rstat;
        unsigned long num_rx_queues;
        unsigned long rx_bit_map;
        /* cacheline 3 */
-       unsigned int rstat;
        unsigned int tstat;
        unsigned long num_tx_queues;
        unsigned long tx_bit_map;
index 5115ae76a5d1c02f0788138e68fac4acdb551767..ada6e210279f3750e26ea5720ca3bbe5057abf2c 100644 (file)
@@ -1175,15 +1175,12 @@ static int e100_configure(struct nic *nic, struct cb *cb, struct sk_buff *skb)
                config->rx_discard_short_frames = 0x0;  /* 1=discard, 0=save */
        }
 
-       netif_printk(nic, hw, KERN_DEBUG, nic->netdev,
-                    "[00-07]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
-                    c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]);
-       netif_printk(nic, hw, KERN_DEBUG, nic->netdev,
-                    "[08-15]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
-                    c[8], c[9], c[10], c[11], c[12], c[13], c[14], c[15]);
-       netif_printk(nic, hw, KERN_DEBUG, nic->netdev,
-                    "[16-23]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
-                    c[16], c[17], c[18], c[19], c[20], c[21], c[22], c[23]);
+       netif_printk(nic, hw, KERN_DEBUG, nic->netdev, "[00-07]=%8ph\n",
+                    c + 0);
+       netif_printk(nic, hw, KERN_DEBUG, nic->netdev, "[08-15]=%8ph\n",
+                    c + 8);
+       netif_printk(nic, hw, KERN_DEBUG, nic->netdev, "[16-23]=%8ph\n",
+                    c + 16);
        return 0;
 }
 
index 4c303e2a7cb3f3aae1ed974d6a066168c7e82c4a..104fcec86af323dc6faab94d4581acb02d3e8729 100644 (file)
@@ -2057,6 +2057,7 @@ const struct e1000_info e1000_82583_info = {
                                  | FLAG_HAS_JUMBO_FRAMES
                                  | FLAG_HAS_CTRLEXT_ON_LOAD,
        .flags2                 = FLAG2_DISABLE_ASPM_L0S
+                                 | FLAG2_DISABLE_ASPM_L1
                                  | FLAG2_NO_DISABLE_RX,
        .pba                    = 32,
        .max_hw_frame_size      = DEFAULT_JUMBO,
index ffbc08f56c40cd9f55c2753b74d294b5caa540b4..ad0edd11015d7b40a14d79f06afdab8ecec76cef 100644 (file)
@@ -90,9 +90,6 @@ struct e1000_info;
 
 #define E1000_MNG_VLAN_NONE            (-1)
 
-/* Number of packet split data buffers (not including the header buffer) */
-#define PS_PAGE_BUFFERS                        (MAX_PS_BUFFERS - 1)
-
 #define DEFAULT_JUMBO                  9234
 
 /* Time to wait before putting the device into D3 if there's no link (in ms). */
index 59c22bf18701bf6505b13c0f16228a43694e2bb7..e4ebd7ddf5f2e42a7ea2e214022eabab8d95b114 100644 (file)
@@ -173,7 +173,7 @@ static int e1000_get_settings(struct net_device *netdev,
                        speed = adapter->link_speed;
                        ecmd->duplex = adapter->link_duplex - 1;
                }
-       } else {
+       } else if (!pm_runtime_suspended(netdev->dev.parent)) {
                u32 status = er32(STATUS);
                if (status & E1000_STATUS_LU) {
                        if (status & E1000_STATUS_SPEED_1000)
@@ -264,6 +264,9 @@ static int e1000_set_settings(struct net_device *netdev,
 {
        struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
+       int ret_val = 0;
+
+       pm_runtime_get_sync(netdev->dev.parent);
 
        /* When SoL/IDER sessions are active, autoneg/speed/duplex
         * cannot be changed
@@ -271,7 +274,8 @@ static int e1000_set_settings(struct net_device *netdev,
        if (hw->phy.ops.check_reset_block &&
            hw->phy.ops.check_reset_block(hw)) {
                e_err("Cannot change link characteristics when SoL/IDER is active.\n");
-               return -EINVAL;
+               ret_val = -EINVAL;
+               goto out;
        }
 
        /* MDI setting is only allowed when autoneg enabled because
@@ -279,13 +283,16 @@ static int e1000_set_settings(struct net_device *netdev,
         * duplex is forced.
         */
        if (ecmd->eth_tp_mdix_ctrl) {
-               if (hw->phy.media_type != e1000_media_type_copper)
-                       return -EOPNOTSUPP;
+               if (hw->phy.media_type != e1000_media_type_copper) {
+                       ret_val = -EOPNOTSUPP;
+                       goto out;
+               }
 
                if ((ecmd->eth_tp_mdix_ctrl != ETH_TP_MDI_AUTO) &&
                    (ecmd->autoneg != AUTONEG_ENABLE)) {
                        e_err("forcing MDI/MDI-X state is not supported when link speed and/or duplex are forced\n");
-                       return -EINVAL;
+                       ret_val = -EINVAL;
+                       goto out;
                }
        }
 
@@ -307,8 +314,8 @@ static int e1000_set_settings(struct net_device *netdev,
                u32 speed = ethtool_cmd_speed(ecmd);
                /* calling this overrides forced MDI setting */
                if (e1000_set_spd_dplx(adapter, speed, ecmd->duplex)) {
-                       clear_bit(__E1000_RESETTING, &adapter->state);
-                       return -EINVAL;
+                       ret_val = -EINVAL;
+                       goto out;
                }
        }
 
@@ -331,8 +338,10 @@ static int e1000_set_settings(struct net_device *netdev,
                e1000e_reset(adapter);
        }
 
+out:
+       pm_runtime_put_sync(netdev->dev.parent);
        clear_bit(__E1000_RESETTING, &adapter->state);
-       return 0;
+       return ret_val;
 }
 
 static void e1000_get_pauseparam(struct net_device *netdev,
@@ -366,6 +375,8 @@ static int e1000_set_pauseparam(struct net_device *netdev,
        while (test_and_set_bit(__E1000_RESETTING, &adapter->state))
                usleep_range(1000, 2000);
 
+       pm_runtime_get_sync(netdev->dev.parent);
+
        if (adapter->fc_autoneg == AUTONEG_ENABLE) {
                hw->fc.requested_mode = e1000_fc_default;
                if (netif_running(adapter->netdev)) {
@@ -398,6 +409,7 @@ static int e1000_set_pauseparam(struct net_device *netdev,
        }
 
 out:
+       pm_runtime_put_sync(netdev->dev.parent);
        clear_bit(__E1000_RESETTING, &adapter->state);
        return retval;
 }
@@ -428,6 +440,8 @@ static void e1000_get_regs(struct net_device *netdev,
        u32 *regs_buff = p;
        u16 phy_data;
 
+       pm_runtime_get_sync(netdev->dev.parent);
+
        memset(p, 0, E1000_REGS_LEN * sizeof(u32));
 
        regs->version = (1 << 24) | (adapter->pdev->revision << 16) |
@@ -472,6 +486,8 @@ static void e1000_get_regs(struct net_device *netdev,
        e1e_rphy(hw, MII_STAT1000, &phy_data);
        regs_buff[24] = (u32)phy_data;  /* phy local receiver status */
        regs_buff[25] = regs_buff[24];  /* phy remote receiver status */
+
+       pm_runtime_put_sync(netdev->dev.parent);
 }
 
 static int e1000_get_eeprom_len(struct net_device *netdev)
@@ -504,6 +520,8 @@ static int e1000_get_eeprom(struct net_device *netdev,
        if (!eeprom_buff)
                return -ENOMEM;
 
+       pm_runtime_get_sync(netdev->dev.parent);
+
        if (hw->nvm.type == e1000_nvm_eeprom_spi) {
                ret_val = e1000_read_nvm(hw, first_word,
                                         last_word - first_word + 1,
@@ -517,6 +535,8 @@ static int e1000_get_eeprom(struct net_device *netdev,
                }
        }
 
+       pm_runtime_put_sync(netdev->dev.parent);
+
        if (ret_val) {
                /* a read error occurred, throw away the result */
                memset(eeprom_buff, 0xff, sizeof(u16) *
@@ -566,6 +586,8 @@ static int e1000_set_eeprom(struct net_device *netdev,
 
        ptr = (void *)eeprom_buff;
 
+       pm_runtime_get_sync(netdev->dev.parent);
+
        if (eeprom->offset & 1) {
                /* need read/modify/write of first changed EEPROM word */
                /* only the second byte of the word is being modified */
@@ -606,6 +628,7 @@ static int e1000_set_eeprom(struct net_device *netdev,
                ret_val = e1000e_update_nvm_checksum(hw);
 
 out:
+       pm_runtime_put_sync(netdev->dev.parent);
        kfree(eeprom_buff);
        return ret_val;
 }
@@ -701,6 +724,8 @@ static int e1000_set_ringparam(struct net_device *netdev,
                }
        }
 
+       pm_runtime_get_sync(netdev->dev.parent);
+
        e1000e_down(adapter);
 
        /* We can't just free everything and then setup again, because the
@@ -739,6 +764,7 @@ err_setup_rx:
                e1000e_free_tx_resources(temp_tx);
 err_setup:
        e1000e_up(adapter);
+       pm_runtime_put_sync(netdev->dev.parent);
 free_temp:
        vfree(temp_tx);
        vfree(temp_rx);
@@ -1732,6 +1758,8 @@ static void e1000_diag_test(struct net_device *netdev,
        u8 autoneg;
        bool if_running = netif_running(netdev);
 
+       pm_runtime_get_sync(netdev->dev.parent);
+
        set_bit(__E1000_TESTING, &adapter->state);
 
        if (!if_running) {
@@ -1817,6 +1845,8 @@ static void e1000_diag_test(struct net_device *netdev,
        }
 
        msleep_interruptible(4 * 1000);
+
+       pm_runtime_put_sync(netdev->dev.parent);
 }
 
 static void e1000_get_wol(struct net_device *netdev,
@@ -1891,6 +1921,8 @@ static int e1000_set_phys_id(struct net_device *netdev,
 
        switch (state) {
        case ETHTOOL_ID_ACTIVE:
+               pm_runtime_get_sync(netdev->dev.parent);
+
                if (!hw->mac.ops.blink_led)
                        return 2;       /* cycle on/off twice per second */
 
@@ -1902,6 +1934,7 @@ static int e1000_set_phys_id(struct net_device *netdev,
                        e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED, 0);
                hw->mac.ops.led_off(hw);
                hw->mac.ops.cleanup_led(hw);
+               pm_runtime_put_sync(netdev->dev.parent);
                break;
 
        case ETHTOOL_ID_ON:
@@ -1912,6 +1945,7 @@ static int e1000_set_phys_id(struct net_device *netdev,
                hw->mac.ops.led_off(hw);
                break;
        }
+
        return 0;
 }
 
@@ -1950,11 +1984,15 @@ static int e1000_set_coalesce(struct net_device *netdev,
                adapter->itr_setting = adapter->itr & ~3;
        }
 
+       pm_runtime_get_sync(netdev->dev.parent);
+
        if (adapter->itr_setting != 0)
                e1000e_write_itr(adapter, adapter->itr);
        else
                e1000e_write_itr(adapter, 0);
 
+       pm_runtime_put_sync(netdev->dev.parent);
+
        return 0;
 }
 
@@ -1968,7 +2006,9 @@ static int e1000_nway_reset(struct net_device *netdev)
        if (!adapter->hw.mac.autoneg)
                return -EINVAL;
 
+       pm_runtime_get_sync(netdev->dev.parent);
        e1000e_reinit_locked(adapter);
+       pm_runtime_put_sync(netdev->dev.parent);
 
        return 0;
 }
@@ -1982,7 +2022,12 @@ static void e1000_get_ethtool_stats(struct net_device *netdev,
        int i;
        char *p = NULL;
 
+       pm_runtime_get_sync(netdev->dev.parent);
+
        e1000e_get_stats64(netdev, &net_stats);
+
+       pm_runtime_put_sync(netdev->dev.parent);
+
        for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) {
                switch (e1000_gstrings_stats[i].type) {
                case NETDEV_STATS:
@@ -2033,7 +2078,11 @@ static int e1000_get_rxnfc(struct net_device *netdev,
        case ETHTOOL_GRXFH: {
                struct e1000_adapter *adapter = netdev_priv(netdev);
                struct e1000_hw *hw = &adapter->hw;
-               u32 mrqc = er32(MRQC);
+               u32 mrqc;
+
+               pm_runtime_get_sync(netdev->dev.parent);
+               mrqc = er32(MRQC);
+               pm_runtime_put_sync(netdev->dev.parent);
 
                if (!(mrqc & E1000_MRQC_RSS_FIELD_MASK))
                        return 0;
@@ -2096,9 +2145,13 @@ static int e1000e_get_eee(struct net_device *netdev, struct ethtool_eee *edata)
                return -EOPNOTSUPP;
        }
 
+       pm_runtime_get_sync(netdev->dev.parent);
+
        ret_val = hw->phy.ops.acquire(hw);
-       if (ret_val)
+       if (ret_val) {
+               pm_runtime_put_sync(netdev->dev.parent);
                return -EBUSY;
+       }
 
        /* EEE Capability */
        ret_val = e1000_read_emi_reg_locked(hw, cap_addr, &phy_data);
@@ -2117,14 +2170,11 @@ static int e1000e_get_eee(struct net_device *netdev, struct ethtool_eee *edata)
 
        /* EEE PCS Status */
        ret_val = e1000_read_emi_reg_locked(hw, pcs_stat_addr, &phy_data);
+       if (ret_val)
+               goto release;
        if (hw->phy.type == e1000_phy_82579)
                phy_data <<= 8;
 
-release:
-       hw->phy.ops.release(hw);
-       if (ret_val)
-               return -ENODATA;
-
        /* Result of the EEE auto negotiation - there is no register that
         * has the status of the EEE negotiation so do a best-guess based
         * on whether Tx or Rx LPI indications have been received.
@@ -2136,7 +2186,14 @@ release:
        edata->tx_lpi_enabled = true;
        edata->tx_lpi_timer = er32(LPIC) >> E1000_LPIC_LPIET_SHIFT;
 
-       return 0;
+release:
+       hw->phy.ops.release(hw);
+       if (ret_val)
+               ret_val = -ENODATA;
+
+       pm_runtime_put_sync(netdev->dev.parent);
+
+       return ret_val;
 }
 
 static int e1000e_set_eee(struct net_device *netdev, struct ethtool_eee *edata)
@@ -2169,12 +2226,16 @@ static int e1000e_set_eee(struct net_device *netdev, struct ethtool_eee *edata)
 
        hw->dev_spec.ich8lan.eee_disable = !edata->eee_enabled;
 
+       pm_runtime_get_sync(netdev->dev.parent);
+
        /* reset the link */
        if (netif_running(netdev))
                e1000e_reinit_locked(adapter);
        else
                e1000e_reset(adapter);
 
+       pm_runtime_put_sync(netdev->dev.parent);
+
        return 0;
 }
 
@@ -2212,19 +2273,7 @@ static int e1000e_get_ts_info(struct net_device *netdev,
        return 0;
 }
 
-static int e1000e_ethtool_begin(struct net_device *netdev)
-{
-       return pm_runtime_get_sync(netdev->dev.parent);
-}
-
-static void e1000e_ethtool_complete(struct net_device *netdev)
-{
-       pm_runtime_put_sync(netdev->dev.parent);
-}
-
 static const struct ethtool_ops e1000_ethtool_ops = {
-       .begin                  = e1000e_ethtool_begin,
-       .complete               = e1000e_ethtool_complete,
        .get_settings           = e1000_get_settings,
        .set_settings           = e1000_set_settings,
        .get_drvinfo            = e1000_get_drvinfo,
index a6f903a9b7731cd3460d5337b98d3ae79a4d3661..b799fd9b6aa9e163f7a705bc6c6c2e35fc94ac8d 100644 (file)
@@ -90,6 +90,10 @@ struct e1000_hw;
 #define E1000_DEV_ID_PCH_LPT_I217_V            0x153B
 #define E1000_DEV_ID_PCH_LPTLP_I218_LM         0x155A
 #define E1000_DEV_ID_PCH_LPTLP_I218_V          0x1559
+#define E1000_DEV_ID_PCH_I218_LM2              0x15A0
+#define E1000_DEV_ID_PCH_I218_V2               0x15A1
+#define E1000_DEV_ID_PCH_I218_LM3              0x15A2  /* Wildcat Point PCH */
+#define E1000_DEV_ID_PCH_I218_V3               0x15A3  /* Wildcat Point PCH */
 
 #define E1000_REVISION_4       4
 
@@ -227,6 +231,9 @@ union e1000_rx_desc_extended {
 };
 
 #define MAX_PS_BUFFERS 4
+
+/* Number of packet split data buffers (not including the header buffer) */
+#define PS_PAGE_BUFFERS                        (MAX_PS_BUFFERS - 1)
 /* Receive Descriptor - Packet Split */
 union e1000_rx_desc_packet_split {
        struct {
@@ -251,7 +258,8 @@ union e1000_rx_desc_packet_split {
                } middle;
                struct {
                        __le16 header_status;
-                       __le16 length[3];       /* length of buffers 1-3 */
+                       /* length of buffers 1-3 */
+                       __le16 length[PS_PAGE_BUFFERS];
                } upper;
                __le64 reserved;
        } wb; /* writeback */
index 9dde390f7e71c34f327f1e1bc213dce5338b917c..af08188d7e624471ed3e8b87df7d39fd24ba3815 100644 (file)
@@ -185,6 +185,7 @@ static bool e1000_phy_is_accessible_pchlan(struct e1000_hw *hw)
        u32 phy_id = 0;
        s32 ret_val;
        u16 retry_count;
+       u32 mac_reg = 0;
 
        for (retry_count = 0; retry_count < 2; retry_count++) {
                ret_val = e1e_rphy_locked(hw, MII_PHYSID1, &phy_reg);
@@ -203,11 +204,11 @@ static bool e1000_phy_is_accessible_pchlan(struct e1000_hw *hw)
 
        if (hw->phy.id) {
                if (hw->phy.id == phy_id)
-                       return true;
+                       goto out;
        } else if (phy_id) {
                hw->phy.id = phy_id;
                hw->phy.revision = (u32)(phy_reg & ~PHY_REVISION_MASK);
-               return true;
+               goto out;
        }
 
        /* In case the PHY needs to be in mdio slow mode,
@@ -219,7 +220,22 @@ static bool e1000_phy_is_accessible_pchlan(struct e1000_hw *hw)
                ret_val = e1000e_get_phy_id(hw);
        hw->phy.ops.acquire(hw);
 
-       return !ret_val;
+       if (ret_val)
+               return false;
+out:
+       if (hw->mac.type == e1000_pch_lpt) {
+               /* Unforce SMBus mode in PHY */
+               e1e_rphy_locked(hw, CV_SMB_CTRL, &phy_reg);
+               phy_reg &= ~CV_SMB_CTRL_FORCE_SMBUS;
+               e1e_wphy_locked(hw, CV_SMB_CTRL, phy_reg);
+
+               /* Unforce SMBus mode in MAC */
+               mac_reg = er32(CTRL_EXT);
+               mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS;
+               ew32(CTRL_EXT, mac_reg);
+       }
+
+       return true;
 }
 
 /**
@@ -233,7 +249,6 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
 {
        u32 mac_reg, fwsm = er32(FWSM);
        s32 ret_val;
-       u16 phy_reg;
 
        /* Gate automatic PHY configuration by hardware on managed and
         * non-managed 82579 and newer adapters.
@@ -262,22 +277,16 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
                mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS;
                ew32(CTRL_EXT, mac_reg);
 
+               /* Wait 50 milliseconds for MAC to finish any retries
+                * that it might be trying to perform from previous
+                * attempts to acknowledge any phy read requests.
+                */
+               msleep(50);
+
                /* fall-through */
        case e1000_pch2lan:
-               if (e1000_phy_is_accessible_pchlan(hw)) {
-                       if (hw->mac.type == e1000_pch_lpt) {
-                               /* Unforce SMBus mode in PHY */
-                               e1e_rphy_locked(hw, CV_SMB_CTRL, &phy_reg);
-                               phy_reg &= ~CV_SMB_CTRL_FORCE_SMBUS;
-                               e1e_wphy_locked(hw, CV_SMB_CTRL, phy_reg);
-
-                               /* Unforce SMBus mode in MAC */
-                               mac_reg = er32(CTRL_EXT);
-                               mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS;
-                               ew32(CTRL_EXT, mac_reg);
-                       }
+               if (e1000_phy_is_accessible_pchlan(hw))
                        break;
-               }
 
                /* fall-through */
        case e1000_pchlan:
@@ -287,6 +296,7 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
 
                if (hw->phy.ops.check_reset_block(hw)) {
                        e_dbg("Required LANPHYPC toggle blocked by ME\n");
+                       ret_val = -E1000_ERR_PHY;
                        break;
                }
 
@@ -298,15 +308,6 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
                mac_reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC;
                ew32(FEXTNVM3, mac_reg);
 
-               if (hw->mac.type == e1000_pch_lpt) {
-                       /* Toggling LANPHYPC brings the PHY out of SMBus mode
-                        * So ensure that the MAC is also out of SMBus mode
-                        */
-                       mac_reg = er32(CTRL_EXT);
-                       mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS;
-                       ew32(CTRL_EXT, mac_reg);
-               }
-
                /* Toggle LANPHYPC Value bit */
                mac_reg = er32(CTRL);
                mac_reg |= E1000_CTRL_LANPHYPC_OVERRIDE;
@@ -325,6 +326,21 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
                                usleep_range(5000, 10000);
                        } while (!(er32(CTRL_EXT) &
                                   E1000_CTRL_EXT_LPCD) && count--);
+                       usleep_range(30000, 60000);
+                       if (e1000_phy_is_accessible_pchlan(hw))
+                               break;
+
+                       /* Toggling LANPHYPC brings the PHY out of SMBus mode
+                        * so ensure that the MAC is also out of SMBus mode
+                        */
+                       mac_reg = er32(CTRL_EXT);
+                       mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS;
+                       ew32(CTRL_EXT, mac_reg);
+
+                       if (e1000_phy_is_accessible_pchlan(hw))
+                               break;
+
+                       ret_val = -E1000_ERR_PHY;
                }
                break;
        default:
@@ -332,13 +348,14 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
        }
 
        hw->phy.ops.release(hw);
-
-       /* Reset the PHY before any access to it.  Doing so, ensures
-        * that the PHY is in a known good state before we read/write
-        * PHY registers.  The generic reset is sufficient here,
-        * because we haven't determined the PHY type yet.
-        */
-       ret_val = e1000e_phy_hw_reset_generic(hw);
+       if (!ret_val) {
+               /* Reset the PHY before any access to it.  Doing so, ensures
+                * that the PHY is in a known good state before we read/write
+                * PHY registers.  The generic reset is sufficient here,
+                * because we haven't determined the PHY type yet.
+                */
+               ret_val = e1000e_phy_hw_reset_generic(hw);
+       }
 
 out:
        /* Ungate automatic PHY configuration on non-managed 82579 */
@@ -793,29 +810,31 @@ release:
  *  When K1 is enabled for 1Gbps, the MAC can miss 2 DMA completion indications
  *  preventing further DMA write requests.  Workaround the issue by disabling
  *  the de-assertion of the clock request when in 1Gpbs mode.
+ *  Also, set appropriate Tx re-transmission timeouts for 10 and 100Half link
+ *  speeds in order to avoid Tx hangs.
  **/
 static s32 e1000_k1_workaround_lpt_lp(struct e1000_hw *hw, bool link)
 {
        u32 fextnvm6 = er32(FEXTNVM6);
+       u32 status = er32(STATUS);
        s32 ret_val = 0;
+       u16 reg;
 
-       if (link && (er32(STATUS) & E1000_STATUS_SPEED_1000)) {
-               u16 kmrn_reg;
-
+       if (link && (status & E1000_STATUS_SPEED_1000)) {
                ret_val = hw->phy.ops.acquire(hw);
                if (ret_val)
                        return ret_val;
 
                ret_val =
                    e1000e_read_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K1_CONFIG,
-                                               &kmrn_reg);
+                                               &reg);
                if (ret_val)
                        goto release;
 
                ret_val =
                    e1000e_write_kmrn_reg_locked(hw,
                                                 E1000_KMRNCTRLSTA_K1_CONFIG,
-                                                kmrn_reg &
+                                                reg &
                                                 ~E1000_KMRNCTRLSTA_K1_ENABLE);
                if (ret_val)
                        goto release;
@@ -827,12 +846,45 @@ static s32 e1000_k1_workaround_lpt_lp(struct e1000_hw *hw, bool link)
                ret_val =
                    e1000e_write_kmrn_reg_locked(hw,
                                                 E1000_KMRNCTRLSTA_K1_CONFIG,
-                                                kmrn_reg);
+                                                reg);
 release:
                hw->phy.ops.release(hw);
        } else {
                /* clear FEXTNVM6 bit 8 on link down or 10/100 */
-               ew32(FEXTNVM6, fextnvm6 & ~E1000_FEXTNVM6_REQ_PLL_CLK);
+               fextnvm6 &= ~E1000_FEXTNVM6_REQ_PLL_CLK;
+
+               if (!link || ((status & E1000_STATUS_SPEED_100) &&
+                             (status & E1000_STATUS_FD)))
+                       goto update_fextnvm6;
+
+               ret_val = e1e_rphy(hw, I217_INBAND_CTRL, &reg);
+               if (ret_val)
+                       return ret_val;
+
+               /* Clear link status transmit timeout */
+               reg &= ~I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_MASK;
+
+               if (status & E1000_STATUS_SPEED_100) {
+                       /* Set inband Tx timeout to 5x10us for 100Half */
+                       reg |= 5 << I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_SHIFT;
+
+                       /* Do not extend the K1 entry latency for 100Half */
+                       fextnvm6 &= ~E1000_FEXTNVM6_ENABLE_K1_ENTRY_CONDITION;
+               } else {
+                       /* Set inband Tx timeout to 50x10us for 10Full/Half */
+                       reg |= 50 <<
+                           I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_SHIFT;
+
+                       /* Extend the K1 entry latency for 10 Mbps */
+                       fextnvm6 |= E1000_FEXTNVM6_ENABLE_K1_ENTRY_CONDITION;
+               }
+
+               ret_val = e1e_wphy(hw, I217_INBAND_CTRL, reg);
+               if (ret_val)
+                       return ret_val;
+
+update_fextnvm6:
+               ew32(FEXTNVM6, fextnvm6);
        }
 
        return ret_val;
@@ -993,7 +1045,9 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
 
        /* Work-around I218 hang issue */
        if ((hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPTLP_I218_LM) ||
-           (hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPTLP_I218_V)) {
+           (hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPTLP_I218_V) ||
+           (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_LM3) ||
+           (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_V3)) {
                ret_val = e1000_k1_workaround_lpt_lp(hw, link);
                if (ret_val)
                        return ret_val;
@@ -4168,7 +4222,9 @@ void e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw)
                u16 phy_reg, device_id = hw->adapter->pdev->device;
 
                if ((device_id == E1000_DEV_ID_PCH_LPTLP_I218_LM) ||
-                   (device_id == E1000_DEV_ID_PCH_LPTLP_I218_V)) {
+                   (device_id == E1000_DEV_ID_PCH_LPTLP_I218_V) ||
+                   (device_id == E1000_DEV_ID_PCH_I218_LM3) ||
+                   (device_id == E1000_DEV_ID_PCH_I218_V3)) {
                        u32 fextnvm6 = er32(FEXTNVM6);
 
                        ew32(FEXTNVM6, fextnvm6 & ~E1000_FEXTNVM6_REQ_PLL_CLK);
index 80034a2b297c1c17f39f5f66d6dbacfab512e5eb..59865695b2826a388b721b2313253e25d86a7c94 100644 (file)
@@ -93,6 +93,7 @@
 #define E1000_FEXTNVM4_BEACON_DURATION_16USEC  0x3
 
 #define E1000_FEXTNVM6_REQ_PLL_CLK     0x00000100
+#define E1000_FEXTNVM6_ENABLE_K1_ENTRY_CONDITION       0x00000200
 
 #define PCIE_ICH8_SNOOP_ALL    PCIE_NO_SNOOP_ALL
 
 
 #define SW_FLAG_TIMEOUT                1000    /* SW Semaphore flag timeout in ms */
 
+/* Inband Control */
+#define I217_INBAND_CTRL                               PHY_REG(770, 18)
+#define I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_MASK     0x3F00
+#define I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_SHIFT    8
+
 /* PHY Low Power Idle Control */
 #define I82579_LPI_CTRL                                PHY_REG(772, 20)
 #define I82579_LPI_CTRL_100_ENABLE             0x2000
index 77f81cbb601a4b248f4018f76a3d6efbb94726bc..e6d2c0f8f76a8cf7f32fcbb9f0e7f8f126064bf4 100644 (file)
@@ -2979,17 +2979,10 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
        u32 pages = 0;
 
        /* Workaround Si errata on PCHx - configure jumbo frame flow */
-       if (hw->mac.type >= e1000_pch2lan) {
-               s32 ret_val;
-
-               if (adapter->netdev->mtu > ETH_DATA_LEN)
-                       ret_val = e1000_lv_jumbo_workaround_ich8lan(hw, true);
-               else
-                       ret_val = e1000_lv_jumbo_workaround_ich8lan(hw, false);
-
-               if (ret_val)
-                       e_dbg("failed to enable jumbo frame workaround mode\n");
-       }
+       if ((hw->mac.type >= e1000_pch2lan) &&
+           (adapter->netdev->mtu > ETH_DATA_LEN) &&
+           e1000_lv_jumbo_workaround_ich8lan(hw, true))
+               e_dbg("failed to enable jumbo frame workaround mode\n");
 
        /* Program MC offset vector base */
        rctl = er32(RCTL);
@@ -3826,6 +3819,8 @@ void e1000e_reset(struct e1000_adapter *adapter)
                        break;
                }
 
+               pba = 14;
+               ew32(PBA, pba);
                fc->high_water = ((pba << 10) * 9 / 10) & E1000_FCRTH_RTH;
                fc->low_water = ((pba << 10) * 8 / 10) & E1000_FCRTL_RTL;
                break;
@@ -4034,6 +4029,12 @@ void e1000e_down(struct e1000_adapter *adapter)
        adapter->link_speed = 0;
        adapter->link_duplex = 0;
 
+       /* Disable Si errata workaround on PCHx for jumbo frame flow */
+       if ((hw->mac.type >= e1000_pch2lan) &&
+           (adapter->netdev->mtu > ETH_DATA_LEN) &&
+           e1000_lv_jumbo_workaround_ich8lan(hw, false))
+               e_dbg("failed to disable jumbo frame workaround mode\n");
+
        if (!pci_channel_offline(adapter->pdev))
                e1000e_reset(adapter);
 
@@ -4683,11 +4684,11 @@ static void e1000_phy_read_status(struct e1000_adapter *adapter)
        struct e1000_hw *hw = &adapter->hw;
        struct e1000_phy_regs *phy = &adapter->phy_regs;
 
-       if ((er32(STATUS) & E1000_STATUS_LU) &&
+       if (!pm_runtime_suspended((&adapter->pdev->dev)->parent) &&
+           (er32(STATUS) & E1000_STATUS_LU) &&
            (adapter->hw.phy.media_type == e1000_media_type_copper)) {
                int ret_val;
 
-               pm_runtime_get_sync(&adapter->pdev->dev);
                ret_val = e1e_rphy(hw, MII_BMCR, &phy->bmcr);
                ret_val |= e1e_rphy(hw, MII_BMSR, &phy->bmsr);
                ret_val |= e1e_rphy(hw, MII_ADVERTISE, &phy->advertise);
@@ -4698,7 +4699,6 @@ static void e1000_phy_read_status(struct e1000_adapter *adapter)
                ret_val |= e1e_rphy(hw, MII_ESTATUS, &phy->estatus);
                if (ret_val)
                        e_warn("Error reading PHY register\n");
-               pm_runtime_put_sync(&adapter->pdev->dev);
        } else {
                /* Do not read PHY registers if link is not up
                 * Set values to typical power-on defaults
@@ -5995,6 +5995,8 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime)
         */
        e1000e_release_hw_control(adapter);
 
+       pci_clear_master(pdev);
+
        /* The pci-e switch on some quad port adapters will report a
         * correctable error when the MAC transitions from D0 to D3.  To
         * prevent this we need to mask off the correctable errors on the
@@ -6723,10 +6725,6 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        adapter->hw.fc.current_mode = e1000_fc_default;
        adapter->hw.phy.autoneg_advertised = 0x2f;
 
-       /* ring size defaults */
-       adapter->rx_ring->count = E1000_DEFAULT_RXD;
-       adapter->tx_ring->count = E1000_DEFAULT_TXD;
-
        /* Initial Wake on LAN setting - If APM wake is enabled in
         * the EEPROM, enable the ACPI Magic Packet filter
         */
@@ -6976,6 +6974,10 @@ static DEFINE_PCI_DEVICE_TABLE(e1000_pci_tbl) = {
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LPT_I217_V), board_pch_lpt },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LPTLP_I218_LM), board_pch_lpt },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LPTLP_I218_V), board_pch_lpt },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_I218_LM2), board_pch_lpt },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_I218_V2), board_pch_lpt },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_I218_LM3), board_pch_lpt },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_I218_V3), board_pch_lpt },
 
        { 0, 0, 0, 0, 0, 0, 0 } /* terminate list */
 };
index 6a0c1b66ce54116b88a8aaf33bcf0518a7ef7ca3..c1d72c03cb5932f83e9f8a397a55227fee981d9f 100644 (file)
@@ -3739,9 +3739,8 @@ static void igb_set_rx_mode(struct net_device *netdev)
        rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE | E1000_RCTL_VFE);
 
        if (netdev->flags & IFF_PROMISC) {
-               u32 mrqc = rd32(E1000_MRQC);
                /* retain VLAN HW filtering if in VT mode */
-               if (mrqc & E1000_MRQC_ENABLE_VMDQ)
+               if (adapter->vfs_allocated_count)
                        rctl |= E1000_RCTL_VFE;
                rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
                vmolr |= (E1000_VMOLR_ROPE | E1000_VMOLR_MPME);
index 7be725cdfea8d3b3c7f414a500dd83b965f24d99..0ac6b11c6e4ec323aaa50db976e2a996b1b02d19 100644 (file)
@@ -54,7 +54,7 @@
 
 #include <net/busy_poll.h>
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
 #define LL_EXTENDED_STATS
 #endif
 /* common prefix used by pr_<> macros */
@@ -366,7 +366,7 @@ struct ixgbe_q_vector {
        struct rcu_head rcu;    /* to avoid race with update stats on free */
        char name[IFNAMSIZ + 9];
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        unsigned int state;
 #define IXGBE_QV_STATE_IDLE        0
 #define IXGBE_QV_STATE_NAPI       1    /* NAPI owns this QV */
@@ -377,12 +377,12 @@ struct ixgbe_q_vector {
 #define IXGBE_QV_YIELD (IXGBE_QV_STATE_NAPI_YIELD | IXGBE_QV_STATE_POLL_YIELD)
 #define IXGBE_QV_USER_PEND (IXGBE_QV_STATE_POLL | IXGBE_QV_STATE_POLL_YIELD)
        spinlock_t lock;
-#endif  /* CONFIG_NET_LL_RX_POLL */
+#endif  /* CONFIG_NET_RX_BUSY_POLL */
 
        /* for dynamic allocation of rings associated with this q_vector */
        struct ixgbe_ring ring[0] ____cacheline_internodealigned_in_smp;
 };
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
 static inline void ixgbe_qv_init_lock(struct ixgbe_q_vector *q_vector)
 {
 
@@ -462,7 +462,7 @@ static inline bool ixgbe_qv_ll_polling(struct ixgbe_q_vector *q_vector)
        WARN_ON(!(q_vector->state & IXGBE_QV_LOCKED));
        return q_vector->state & IXGBE_QV_USER_PEND;
 }
-#else /* CONFIG_NET_LL_RX_POLL */
+#else /* CONFIG_NET_RX_BUSY_POLL */
 static inline void ixgbe_qv_init_lock(struct ixgbe_q_vector *q_vector)
 {
 }
@@ -491,7 +491,7 @@ static inline bool ixgbe_qv_ll_polling(struct ixgbe_q_vector *q_vector)
 {
        return false;
 }
-#endif /* CONFIG_NET_LL_RX_POLL */
+#endif /* CONFIG_NET_RX_BUSY_POLL */
 
 #ifdef CONFIG_IXGBE_HWMON
 
@@ -618,9 +618,8 @@ struct ixgbe_adapter {
 #define IXGBE_FLAG2_FDIR_REQUIRES_REINIT        (u32)(1 << 7)
 #define IXGBE_FLAG2_RSS_FIELD_IPV4_UDP         (u32)(1 << 8)
 #define IXGBE_FLAG2_RSS_FIELD_IPV6_UDP         (u32)(1 << 9)
-#define IXGBE_FLAG2_PTP_ENABLED                        (u32)(1 << 10)
-#define IXGBE_FLAG2_PTP_PPS_ENABLED            (u32)(1 << 11)
-#define IXGBE_FLAG2_BRIDGE_MODE_VEB            (u32)(1 << 12)
+#define IXGBE_FLAG2_PTP_PPS_ENABLED            (u32)(1 << 10)
+#define IXGBE_FLAG2_BRIDGE_MODE_VEB            (u32)(1 << 11)
 
        /* Tx fast path data */
        int num_tx_queues;
@@ -754,7 +753,7 @@ enum ixgbe_state_t {
        __IXGBE_DOWN,
        __IXGBE_SERVICE_SCHED,
        __IXGBE_IN_SFP_INIT,
-       __IXGBE_READ_I2C,
+       __IXGBE_PTP_RUNNING,
 };
 
 struct ixgbe_cb {
index 4a5bfb6b3af05b09e5d5895e0a2b82bf04e10d0b..a26f3fee4f359be56b4346b9a5d871efedc8ca1d 100644 (file)
@@ -1018,8 +1018,17 @@ static s32 ixgbe_read_i2c_phy_82598(struct ixgbe_hw *hw, u8 dev_addr,
        u16 sfp_addr = 0;
        u16 sfp_data = 0;
        u16 sfp_stat = 0;
+       u16 gssr;
        u32 i;
 
+       if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)
+               gssr = IXGBE_GSSR_PHY1_SM;
+       else
+               gssr = IXGBE_GSSR_PHY0_SM;
+
+       if (hw->mac.ops.acquire_swfw_sync(hw, gssr) != 0)
+               return IXGBE_ERR_SWFW_SYNC;
+
        if (hw->phy.type == ixgbe_phy_nl) {
                /*
                 * phy SDA/SCL registers are at addresses 0xC30A to
@@ -1028,17 +1037,17 @@ static s32 ixgbe_read_i2c_phy_82598(struct ixgbe_hw *hw, u8 dev_addr,
                 */
                sfp_addr = (dev_addr << 8) + byte_offset;
                sfp_addr = (sfp_addr | IXGBE_I2C_EEPROM_READ_MASK);
-               hw->phy.ops.write_reg(hw,
-                                     IXGBE_MDIO_PMA_PMD_SDA_SCL_ADDR,
-                                     MDIO_MMD_PMAPMD,
-                                     sfp_addr);
+               hw->phy.ops.write_reg_mdi(hw,
+                                         IXGBE_MDIO_PMA_PMD_SDA_SCL_ADDR,
+                                         MDIO_MMD_PMAPMD,
+                                         sfp_addr);
 
                /* Poll status */
                for (i = 0; i < 100; i++) {
-                       hw->phy.ops.read_reg(hw,
-                                            IXGBE_MDIO_PMA_PMD_SDA_SCL_STAT,
-                                            MDIO_MMD_PMAPMD,
-                                            &sfp_stat);
+                       hw->phy.ops.read_reg_mdi(hw,
+                                               IXGBE_MDIO_PMA_PMD_SDA_SCL_STAT,
+                                               MDIO_MMD_PMAPMD,
+                                               &sfp_stat);
                        sfp_stat = sfp_stat & IXGBE_I2C_EEPROM_STATUS_MASK;
                        if (sfp_stat != IXGBE_I2C_EEPROM_STATUS_IN_PROGRESS)
                                break;
@@ -1052,8 +1061,8 @@ static s32 ixgbe_read_i2c_phy_82598(struct ixgbe_hw *hw, u8 dev_addr,
                }
 
                /* Read data */
-               hw->phy.ops.read_reg(hw, IXGBE_MDIO_PMA_PMD_SDA_SCL_DATA,
-                                    MDIO_MMD_PMAPMD, &sfp_data);
+               hw->phy.ops.read_reg_mdi(hw, IXGBE_MDIO_PMA_PMD_SDA_SCL_DATA,
+                                       MDIO_MMD_PMAPMD, &sfp_data);
 
                *eeprom_data = (u8)(sfp_data >> 8);
        } else {
@@ -1061,6 +1070,7 @@ static s32 ixgbe_read_i2c_phy_82598(struct ixgbe_hw *hw, u8 dev_addr,
        }
 
 out:
+       hw->mac.ops.release_swfw_sync(hw, gssr);
        return status;
 }
 
@@ -1321,11 +1331,13 @@ static struct ixgbe_eeprom_operations eeprom_ops_82598 = {
 
 static struct ixgbe_phy_operations phy_ops_82598 = {
        .identify               = &ixgbe_identify_phy_generic,
-       .identify_sfp           = &ixgbe_identify_sfp_module_generic,
+       .identify_sfp           = &ixgbe_identify_module_generic,
        .init                   = &ixgbe_init_phy_ops_82598,
        .reset                  = &ixgbe_reset_phy_generic,
        .read_reg               = &ixgbe_read_phy_reg_generic,
        .write_reg              = &ixgbe_write_phy_reg_generic,
+       .read_reg_mdi           = &ixgbe_read_phy_reg_mdi,
+       .write_reg_mdi          = &ixgbe_write_phy_reg_mdi,
        .setup_link             = &ixgbe_setup_phy_link_generic,
        .setup_link_speed       = &ixgbe_setup_phy_link_speed_generic,
        .read_i2c_sff8472       = &ixgbe_read_i2c_sff8472_82598,
index 0b82d38bc97daf6e67c6cd7a0d65caafa70ccd11..207f68fbe3d3c3c01d9b842f06c377a891962a14 100644 (file)
@@ -58,6 +58,10 @@ static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw,
                                          ixgbe_link_speed speed,
                                          bool autoneg_wait_to_complete);
 static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw);
+static s32 ixgbe_read_i2c_byte_82599(struct ixgbe_hw *hw, u8 byte_offset,
+                                    u8 dev_addr, u8 *data);
+static s32 ixgbe_write_i2c_byte_82599(struct ixgbe_hw *hw, u8 byte_offset,
+                                     u8 dev_addr, u8 data);
 
 static bool ixgbe_mng_enabled(struct ixgbe_hw *hw)
 {
@@ -219,6 +223,25 @@ static s32 ixgbe_init_phy_ops_82599(struct ixgbe_hw *hw)
        struct ixgbe_mac_info *mac = &hw->mac;
        struct ixgbe_phy_info *phy = &hw->phy;
        s32 ret_val = 0;
+       u32 esdp;
+
+       if (hw->device_id == IXGBE_DEV_ID_82599_QSFP_SF_QP) {
+               /* Store flag indicating I2C bus access control unit. */
+               hw->phy.qsfp_shared_i2c_bus = true;
+
+               /* Initialize access to QSFP+ I2C bus */
+               esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
+               esdp |= IXGBE_ESDP_SDP0_DIR;
+               esdp &= ~IXGBE_ESDP_SDP1_DIR;
+               esdp &= ~IXGBE_ESDP_SDP0;
+               esdp &= ~IXGBE_ESDP_SDP0_NATIVE;
+               esdp &= ~IXGBE_ESDP_SDP1_NATIVE;
+               IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
+               IXGBE_WRITE_FLUSH(hw);
+
+               phy->ops.read_i2c_byte = &ixgbe_read_i2c_byte_82599;
+               phy->ops.write_i2c_byte = &ixgbe_write_i2c_byte_82599;
+       }
 
        /* Identify the PHY or SFP module */
        ret_val = phy->ops.identify(hw);
@@ -397,6 +420,9 @@ static enum ixgbe_media_type ixgbe_get_media_type_82599(struct ixgbe_hw *hw)
        case IXGBE_DEV_ID_82599_LS:
                media_type = ixgbe_media_type_fiber_lco;
                break;
+       case IXGBE_DEV_ID_82599_QSFP_SF_QP:
+               media_type = ixgbe_media_type_fiber_qsfp;
+               break;
        default:
                media_type = ixgbe_media_type_unknown;
                break;
@@ -526,6 +552,75 @@ static void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw)
        }
 }
 
+/**
+ *  ixgbe_set_fiber_fixed_speed - Set module link speed for fixed fiber
+ *  @hw: pointer to hardware structure
+ *  @speed: link speed to set
+ *
+ *  We set the module speed differently for fixed fiber.  For other
+ *  multi-speed devices we don't have an error value so here if we
+ *  detect an error we just log it and exit.
+ */
+static void ixgbe_set_fiber_fixed_speed(struct ixgbe_hw *hw,
+                                       ixgbe_link_speed speed)
+{
+       s32 status;
+       u8 rs, eeprom_data;
+
+       switch (speed) {
+       case IXGBE_LINK_SPEED_10GB_FULL:
+               /* one bit mask same as setting on */
+               rs = IXGBE_SFF_SOFT_RS_SELECT_10G;
+               break;
+       case IXGBE_LINK_SPEED_1GB_FULL:
+               rs = IXGBE_SFF_SOFT_RS_SELECT_1G;
+               break;
+       default:
+               hw_dbg(hw, "Invalid fixed module speed\n");
+               return;
+       }
+
+       /* Set RS0 */
+       status = hw->phy.ops.read_i2c_byte(hw, IXGBE_SFF_SFF_8472_OSCB,
+                                          IXGBE_I2C_EEPROM_DEV_ADDR2,
+                                          &eeprom_data);
+       if (status) {
+               hw_dbg(hw, "Failed to read Rx Rate Select RS0\n");
+               goto out;
+       }
+
+       eeprom_data = (eeprom_data & ~IXGBE_SFF_SOFT_RS_SELECT_MASK) & rs;
+
+       status = hw->phy.ops.write_i2c_byte(hw, IXGBE_SFF_SFF_8472_OSCB,
+                                           IXGBE_I2C_EEPROM_DEV_ADDR2,
+                                           eeprom_data);
+       if (status) {
+               hw_dbg(hw, "Failed to write Rx Rate Select RS0\n");
+               goto out;
+       }
+
+       /* Set RS1 */
+       status = hw->phy.ops.read_i2c_byte(hw, IXGBE_SFF_SFF_8472_ESCB,
+                                          IXGBE_I2C_EEPROM_DEV_ADDR2,
+                                          &eeprom_data);
+       if (status) {
+               hw_dbg(hw, "Failed to read Rx Rate Select RS1\n");
+               goto out;
+       }
+
+       eeprom_data = (eeprom_data & ~IXGBE_SFF_SOFT_RS_SELECT_MASK) & rs;
+
+       status = hw->phy.ops.write_i2c_byte(hw, IXGBE_SFF_SFF_8472_ESCB,
+                                           IXGBE_I2C_EEPROM_DEV_ADDR2,
+                                           eeprom_data);
+       if (status) {
+               hw_dbg(hw, "Failed to write Rx Rate Select RS1\n");
+               goto out;
+       }
+out:
+       return;
+}
+
 /**
  *  ixgbe_setup_mac_link_multispeed_fiber - Set MAC link speed
  *  @hw: pointer to hardware structure
@@ -573,9 +668,14 @@ static s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw,
                        goto out;
 
                /* Set the module link speed */
-               esdp_reg |= (IXGBE_ESDP_SDP5_DIR | IXGBE_ESDP_SDP5);
-               IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg);
-               IXGBE_WRITE_FLUSH(hw);
+               if (hw->phy.media_type == ixgbe_media_type_fiber_fixed) {
+                       ixgbe_set_fiber_fixed_speed(hw,
+                                       IXGBE_LINK_SPEED_10GB_FULL);
+               } else {
+                       esdp_reg |= (IXGBE_ESDP_SDP5_DIR | IXGBE_ESDP_SDP5);
+                       IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg);
+                       IXGBE_WRITE_FLUSH(hw);
+               }
 
                /* Allow module to change analog characteristics (1G->10G) */
                msleep(40);
@@ -625,10 +725,15 @@ static s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw,
                        goto out;
 
                /* Set the module link speed */
-               esdp_reg &= ~IXGBE_ESDP_SDP5;
-               esdp_reg |= IXGBE_ESDP_SDP5_DIR;
-               IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg);
-               IXGBE_WRITE_FLUSH(hw);
+               if (hw->phy.media_type == ixgbe_media_type_fiber_fixed) {
+                       ixgbe_set_fiber_fixed_speed(hw,
+                                               IXGBE_LINK_SPEED_1GB_FULL);
+               } else {
+                       esdp_reg &= ~IXGBE_ESDP_SDP5;
+                       esdp_reg |= IXGBE_ESDP_SDP5_DIR;
+                       IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg);
+                       IXGBE_WRITE_FLUSH(hw);
+               }
 
                /* Allow module to change analog characteristics (10G->1G) */
                msleep(40);
@@ -1872,7 +1977,7 @@ static s32 ixgbe_identify_phy_82599(struct ixgbe_hw *hw)
                if (hw->mac.ops.get_media_type(hw) == ixgbe_media_type_copper)
                        goto out;
                else
-                       status = ixgbe_identify_sfp_module_generic(hw);
+                       status = ixgbe_identify_module_generic(hw);
        }
 
        /* Set PHY type none if no PHY detected */
@@ -1978,10 +2083,12 @@ sfp_check:
        switch (hw->phy.type) {
        case ixgbe_phy_sfp_passive_tyco:
        case ixgbe_phy_sfp_passive_unknown:
+       case ixgbe_phy_qsfp_passive_unknown:
                physical_layer = IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU;
                break;
        case ixgbe_phy_sfp_ftl_active:
        case ixgbe_phy_sfp_active_unknown:
+       case ixgbe_phy_qsfp_active_unknown:
                physical_layer = IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA;
                break;
        case ixgbe_phy_sfp_avago:
@@ -1999,6 +2106,15 @@ sfp_check:
                else if (comp_codes_1g & IXGBE_SFF_1GBASET_CAPABLE)
                        physical_layer = IXGBE_PHYSICAL_LAYER_1000BASE_T;
                break;
+       case ixgbe_phy_qsfp_intel:
+       case ixgbe_phy_qsfp_unknown:
+               hw->phy.ops.read_i2c_eeprom(hw,
+                       IXGBE_SFF_QSFP_10GBE_COMP, &comp_codes_10g);
+               if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)
+                       physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR;
+               else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE)
+                       physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR;
+               break;
        default:
                break;
        }
@@ -2236,6 +2352,112 @@ reset_pipeline_out:
        return ret_val;
 }
 
+/**
+ *  ixgbe_read_i2c_byte_82599 - Reads 8 bit word over I2C
+ *  @hw: pointer to hardware structure
+ *  @byte_offset: byte offset to read
+ *  @data: value read
+ *
+ *  Performs byte read operation to SFP module's EEPROM over I2C interface at
+ *  a specified device address.
+ **/
+static s32 ixgbe_read_i2c_byte_82599(struct ixgbe_hw *hw, u8 byte_offset,
+                                    u8 dev_addr, u8 *data)
+{
+       u32 esdp;
+       s32 status;
+       s32 timeout = 200;
+
+       if (hw->phy.qsfp_shared_i2c_bus == true) {
+               /* Acquire I2C bus ownership. */
+               esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
+               esdp |= IXGBE_ESDP_SDP0;
+               IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
+               IXGBE_WRITE_FLUSH(hw);
+
+               while (timeout) {
+                       esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
+                       if (esdp & IXGBE_ESDP_SDP1)
+                               break;
+
+                       usleep_range(5000, 10000);
+                       timeout--;
+               }
+
+               if (!timeout) {
+                       hw_dbg(hw, "Driver can't access resource, acquiring I2C bus timeout.\n");
+                       status = IXGBE_ERR_I2C;
+                       goto release_i2c_access;
+               }
+       }
+
+       status = ixgbe_read_i2c_byte_generic(hw, byte_offset, dev_addr, data);
+
+release_i2c_access:
+       if (hw->phy.qsfp_shared_i2c_bus == true) {
+               /* Release I2C bus ownership. */
+               esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
+               esdp &= ~IXGBE_ESDP_SDP0;
+               IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
+               IXGBE_WRITE_FLUSH(hw);
+       }
+
+       return status;
+}
+
+/**
+ *  ixgbe_write_i2c_byte_82599 - Writes 8 bit word over I2C
+ *  @hw: pointer to hardware structure
+ *  @byte_offset: byte offset to write
+ *  @data: value to write
+ *
+ *  Performs byte write operation to SFP module's EEPROM over I2C interface at
+ *  a specified device address.
+ **/
+static s32 ixgbe_write_i2c_byte_82599(struct ixgbe_hw *hw, u8 byte_offset,
+                                     u8 dev_addr, u8 data)
+{
+       u32 esdp;
+       s32 status;
+       s32 timeout = 200;
+
+       if (hw->phy.qsfp_shared_i2c_bus == true) {
+               /* Acquire I2C bus ownership. */
+               esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
+               esdp |= IXGBE_ESDP_SDP0;
+               IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
+               IXGBE_WRITE_FLUSH(hw);
+
+               while (timeout) {
+                       esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
+                       if (esdp & IXGBE_ESDP_SDP1)
+                               break;
+
+                       usleep_range(5000, 10000);
+                       timeout--;
+               }
+
+               if (!timeout) {
+                       hw_dbg(hw, "Driver can't access resource, acquiring I2C bus timeout.\n");
+                       status = IXGBE_ERR_I2C;
+                       goto release_i2c_access;
+               }
+       }
+
+       status = ixgbe_write_i2c_byte_generic(hw, byte_offset, dev_addr, data);
+
+release_i2c_access:
+       if (hw->phy.qsfp_shared_i2c_bus == true) {
+               /* Release I2C bus ownership. */
+               esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
+               esdp &= ~IXGBE_ESDP_SDP0;
+               IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
+               IXGBE_WRITE_FLUSH(hw);
+       }
+
+       return status;
+}
+
 static struct ixgbe_mac_operations mac_ops_82599 = {
        .init_hw                = &ixgbe_init_hw_generic,
        .reset_hw               = &ixgbe_reset_hw_82599,
@@ -2300,7 +2522,7 @@ static struct ixgbe_eeprom_operations eeprom_ops_82599 = {
 
 static struct ixgbe_phy_operations phy_ops_82599 = {
        .identify               = &ixgbe_identify_phy_82599,
-       .identify_sfp           = &ixgbe_identify_sfp_module_generic,
+       .identify_sfp           = &ixgbe_identify_module_generic,
        .init                   = &ixgbe_init_phy_ops_82599,
        .reset                  = &ixgbe_reset_phy_generic,
        .read_reg               = &ixgbe_read_phy_reg_generic,
index 9bcdeb89af5a0a532689cb7b91b2b3b64fca380a..50e62a2b1a65f905709c9ffffdff66fa8273a296 100644 (file)
@@ -65,17 +65,42 @@ static s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw);
  *  function check the device id to see if the associated phy supports
  *  autoneg flow control.
  **/
-s32 ixgbe_device_supports_autoneg_fc(struct ixgbe_hw *hw)
+bool ixgbe_device_supports_autoneg_fc(struct ixgbe_hw *hw)
 {
+       bool supported = false;
+       ixgbe_link_speed speed;
+       bool link_up;
 
-       switch (hw->device_id) {
-       case IXGBE_DEV_ID_X540T:
-       case IXGBE_DEV_ID_X540T1:
-       case IXGBE_DEV_ID_82599_T3_LOM:
-               return 0;
+       switch (hw->phy.media_type) {
+       case ixgbe_media_type_fiber_fixed:
+       case ixgbe_media_type_fiber:
+               hw->mac.ops.check_link(hw, &speed, &link_up, false);
+               /* if link is down, assume supported */
+               if (link_up)
+                       supported = speed == IXGBE_LINK_SPEED_1GB_FULL ?
+                               true : false;
+               else
+                       supported = true;
+               break;
+       case ixgbe_media_type_backplane:
+               supported = true;
+               break;
+       case ixgbe_media_type_copper:
+               /* only some copper devices support flow control autoneg */
+               switch (hw->device_id) {
+               case IXGBE_DEV_ID_82599_T3_LOM:
+               case IXGBE_DEV_ID_X540T:
+               case IXGBE_DEV_ID_X540T1:
+                       supported = true;
+                       break;
+               default:
+                       break;
+               }
        default:
-               return IXGBE_ERR_FC_NOT_SUPPORTED;
+               break;
        }
+
+       return supported;
 }
 
 /**
@@ -114,6 +139,7 @@ static s32 ixgbe_setup_fc(struct ixgbe_hw *hw)
         * we link at 10G, the 1G advertisement is harmless and vice versa.
         */
        switch (hw->phy.media_type) {
+       case ixgbe_media_type_fiber_fixed:
        case ixgbe_media_type_fiber:
        case ixgbe_media_type_backplane:
                reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANA);
@@ -234,7 +260,7 @@ static s32 ixgbe_setup_fc(struct ixgbe_hw *hw)
                                                      IXGBE_GSSR_MAC_CSR_SM);
 
        } else if ((hw->phy.media_type == ixgbe_media_type_copper) &&
-                   (ixgbe_device_supports_autoneg_fc(hw) == 0)) {
+                   ixgbe_device_supports_autoneg_fc(hw)) {
                hw->phy.ops.write_reg(hw, MDIO_AN_ADVERTISE,
                                      MDIO_MMD_AN, reg_cu);
        }
@@ -2380,6 +2406,7 @@ void ixgbe_fc_autoneg(struct ixgbe_hw *hw)
 
        switch (hw->phy.media_type) {
        /* Autoneg flow control on fiber adapters */
+       case ixgbe_media_type_fiber_fixed:
        case ixgbe_media_type_fiber:
                if (speed == IXGBE_LINK_SPEED_1GB_FULL)
                        ret_val = ixgbe_fc_autoneg_fiber(hw);
@@ -2392,7 +2419,7 @@ void ixgbe_fc_autoneg(struct ixgbe_hw *hw)
 
        /* Autoneg flow control on copper adapters */
        case ixgbe_media_type_copper:
-               if (ixgbe_device_supports_autoneg_fc(hw) == 0)
+               if (ixgbe_device_supports_autoneg_fc(hw))
                        ret_val = ixgbe_fc_autoneg_copper(hw);
                break;
 
@@ -2479,42 +2506,39 @@ out:
  **/
 s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u16 mask)
 {
-       u32 gssr;
+       u32 gssr = 0;
        u32 swmask = mask;
        u32 fwmask = mask << 5;
-       s32 timeout = 200;
+       u32 timeout = 200;
+       u32 i;
 
-       while (timeout) {
+       for (i = 0; i < timeout; i++) {
                /*
-                * SW EEPROM semaphore bit is used for access to all
-                * SW_FW_SYNC/GSSR bits (not just EEPROM)
+                * SW NVM semaphore bit is used for access to all
+                * SW_FW_SYNC bits (not just NVM)
                 */
                if (ixgbe_get_eeprom_semaphore(hw))
                        return IXGBE_ERR_SWFW_SYNC;
 
                gssr = IXGBE_READ_REG(hw, IXGBE_GSSR);
-               if (!(gssr & (fwmask | swmask)))
-                       break;
-
-               /*
-                * Firmware currently using resource (fwmask) or other software
-                * thread currently using resource (swmask)
-                */
-               ixgbe_release_eeprom_semaphore(hw);
-               usleep_range(5000, 10000);
-               timeout--;
-       }
-
-       if (!timeout) {
-               hw_dbg(hw, "Driver can't access resource, SW_FW_SYNC timeout.\n");
-               return IXGBE_ERR_SWFW_SYNC;
+               if (!(gssr & (fwmask | swmask))) {
+                       gssr |= swmask;
+                       IXGBE_WRITE_REG(hw, IXGBE_GSSR, gssr);
+                       ixgbe_release_eeprom_semaphore(hw);
+                       return 0;
+               } else {
+                       /* Resource is currently in use by FW or SW */
+                       ixgbe_release_eeprom_semaphore(hw);
+                       usleep_range(5000, 10000);
+               }
        }
 
-       gssr |= swmask;
-       IXGBE_WRITE_REG(hw, IXGBE_GSSR, gssr);
+       /* If time expired clear the bits holding the lock and retry */
+       if (gssr & (fwmask | swmask))
+               ixgbe_release_swfw_sync(hw, gssr & (fwmask | swmask));
 
-       ixgbe_release_eeprom_semaphore(hw);
-       return 0;
+       usleep_range(5000, 10000);
+       return IXGBE_ERR_SWFW_SYNC;
 }
 
 /**
index 22eee38868f1aa2801137e3b26eb2131efe9ec56..1315b8ac7f586f9ef05b346aa070e847ac481f2a 100644 (file)
@@ -80,7 +80,7 @@ s32 ixgbe_disable_rx_buff_generic(struct ixgbe_hw *hw);
 s32 ixgbe_enable_rx_buff_generic(struct ixgbe_hw *hw);
 s32 ixgbe_enable_rx_dma_generic(struct ixgbe_hw *hw, u32 regval);
 s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw);
-s32 ixgbe_device_supports_autoneg_fc(struct ixgbe_hw *hw);
+bool ixgbe_device_supports_autoneg_fc(struct ixgbe_hw *hw);
 void ixgbe_fc_autoneg(struct ixgbe_hw *hw);
 
 s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u16 mask);
index ac780770863dfb3a338f3dfe4550f5bd87d2e66e..7a77f37a7cbcbd6b7b5b87dd78e9e50b677e778c 100644 (file)
@@ -108,9 +108,8 @@ s32 ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *hw,
 
        /* Enable arbiter */
        reg &= ~IXGBE_DPMCS_ARBDIS;
-       /* Enable DFP and Recycle mode */
-       reg |= (IXGBE_DPMCS_TDPAC | IXGBE_DPMCS_TRM);
        reg |= IXGBE_DPMCS_TSOEF;
+
        /* Configure Max TSO packet size 34KB including payload and headers */
        reg |= (0x4 << IXGBE_DPMCS_MTSOS_SHIFT);
 
index 24e2e7aafda2d42201541ef9ee855ee26e1661cb..50c1e9b2fd806584b69e650d9bf551093f7445d8 100644 (file)
@@ -355,10 +355,11 @@ static void ixgbe_get_pauseparam(struct net_device *netdev,
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
        struct ixgbe_hw *hw = &adapter->hw;
 
-       if (hw->fc.disable_fc_autoneg)
-               pause->autoneg = 0;
-       else
+       if (ixgbe_device_supports_autoneg_fc(hw) &&
+           !hw->fc.disable_fc_autoneg)
                pause->autoneg = 1;
+       else
+               pause->autoneg = 0;
 
        if (hw->fc.current_mode == ixgbe_fc_rx_pause) {
                pause->rx_pause = 1;
@@ -384,7 +385,7 @@ static int ixgbe_set_pauseparam(struct net_device *netdev,
 
        /* some devices do not support autoneg of link flow control */
        if ((pause->autoneg == AUTONEG_ENABLE) &&
-           (ixgbe_device_supports_autoneg_fc(hw) != 0))
+           !ixgbe_device_supports_autoneg_fc(hw))
                return -EINVAL;
 
        fc.disable_fc_autoneg = (pause->autoneg != AUTONEG_ENABLE);
@@ -1140,11 +1141,11 @@ static void ixgbe_get_strings(struct net_device *netdev, u32 stringset,
                        sprintf(p, "tx_queue_%u_bytes", i);
                        p += ETH_GSTRING_LEN;
 #ifdef LL_EXTENDED_STATS
-                       sprintf(p, "tx_q_%u_napi_yield", i);
+                       sprintf(p, "tx_queue_%u_ll_napi_yield", i);
                        p += ETH_GSTRING_LEN;
-                       sprintf(p, "tx_q_%u_misses", i);
+                       sprintf(p, "tx_queue_%u_ll_misses", i);
                        p += ETH_GSTRING_LEN;
-                       sprintf(p, "tx_q_%u_cleaned", i);
+                       sprintf(p, "tx_queue_%u_ll_cleaned", i);
                        p += ETH_GSTRING_LEN;
 #endif /* LL_EXTENDED_STATS */
                }
@@ -1154,11 +1155,11 @@ static void ixgbe_get_strings(struct net_device *netdev, u32 stringset,
                        sprintf(p, "rx_queue_%u_bytes", i);
                        p += ETH_GSTRING_LEN;
 #ifdef LL_EXTENDED_STATS
-                       sprintf(p, "rx_q_%u_ll_poll_yield", i);
+                       sprintf(p, "rx_queue_%u_ll_poll_yield", i);
                        p += ETH_GSTRING_LEN;
-                       sprintf(p, "rx_q_%u_misses", i);
+                       sprintf(p, "rx_queue_%u_ll_misses", i);
                        p += ETH_GSTRING_LEN;
-                       sprintf(p, "rx_q_%u_cleaned", i);
+                       sprintf(p, "rx_queue_%u_ll_cleaned", i);
                        p += ETH_GSTRING_LEN;
 #endif /* LL_EXTENDED_STATS */
                }
@@ -2909,33 +2910,21 @@ static int ixgbe_get_module_info(struct net_device *dev,
        struct ixgbe_hw *hw = &adapter->hw;
        u32 status;
        u8 sff8472_rev, addr_mode;
-       int ret_val = 0;
        bool page_swap = false;
 
-       /* avoid concurent i2c reads */
-       while (test_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
-               msleep(100);
-
-       /* used by the service task */
-       set_bit(__IXGBE_READ_I2C, &adapter->state);
-
        /* Check whether we support SFF-8472 or not */
        status = hw->phy.ops.read_i2c_eeprom(hw,
                                             IXGBE_SFF_SFF_8472_COMP,
                                             &sff8472_rev);
-       if (status != 0) {
-               ret_val = -EIO;
-               goto err_out;
-       }
+       if (status != 0)
+               return -EIO;
 
        /* addressing mode is not supported */
        status = hw->phy.ops.read_i2c_eeprom(hw,
                                             IXGBE_SFF_SFF_8472_SWAP,
                                             &addr_mode);
-       if (status != 0) {
-               ret_val = -EIO;
-               goto err_out;
-       }
+       if (status != 0)
+               return -EIO;
 
        if (addr_mode & IXGBE_SFF_ADDRESSING_MODE) {
                e_err(drv, "Address change required to access page 0xA2, but not supported. Please report the module type to the driver maintainers.\n");
@@ -2952,9 +2941,7 @@ static int ixgbe_get_module_info(struct net_device *dev,
                modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
        }
 
-err_out:
-       clear_bit(__IXGBE_READ_I2C, &adapter->state);
-       return ret_val;
+       return 0;
 }
 
 static int ixgbe_get_module_eeprom(struct net_device *dev,
@@ -2968,48 +2955,25 @@ static int ixgbe_get_module_eeprom(struct net_device *dev,
        int i = 0;
        int ret_val = 0;
 
-       /* ixgbe_get_module_info is called before this function in all
-        * cases, so we do not need any checks we already do above,
-        * and can trust ee->len to be a known value.
-        */
+       if (ee->len == 0)
+               return -EINVAL;
+
+       for (i = ee->offset; i < ee->len; i++) {
+               /* I2C reads can take long time */
+               if (test_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
+                       return -EBUSY;
 
-       while (test_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
-               msleep(100);
-       set_bit(__IXGBE_READ_I2C, &adapter->state);
+               if (i < ETH_MODULE_SFF_8079_LEN)
+                       status  = hw->phy.ops.read_i2c_eeprom(hw, i, &databyte);
+               else
+                       status = hw->phy.ops.read_i2c_sff8472(hw, i, &databyte);
 
-       /* Read the first block, SFF-8079 */
-       for (i = 0; i < ETH_MODULE_SFF_8079_LEN; i++) {
-               status = hw->phy.ops.read_i2c_eeprom(hw, i, &databyte);
-               if (status != 0) {
-                       /* Error occured while reading module */
+               if (status != 0)
                        ret_val = -EIO;
-                       goto err_out;
-               }
-               data[i] = databyte;
-       }
 
-       /* If the second block is requested, check if SFF-8472 is supported. */
-       if (ee->len == ETH_MODULE_SFF_8472_LEN) {
-               if (data[IXGBE_SFF_SFF_8472_COMP] == IXGBE_SFF_SFF_8472_UNSUP)
-                       return -EOPNOTSUPP;
-
-               /* Read the second block, SFF-8472 */
-               for (i = ETH_MODULE_SFF_8079_LEN;
-                    i < ETH_MODULE_SFF_8472_LEN; i++) {
-                       status = hw->phy.ops.read_i2c_sff8472(hw,
-                               i - ETH_MODULE_SFF_8079_LEN, &databyte);
-                       if (status != 0) {
-                               /* Error occured while reading module */
-                               ret_val = -EIO;
-                               goto err_out;
-                       }
-                       data[i] = databyte;
-               }
+               data[i - ee->offset] = databyte;
        }
 
-err_out:
-       clear_bit(__IXGBE_READ_I2C, &adapter->state);
-
        return ret_val;
 }
 
index bad8f14b194107b7d77ac5f89f194998c4c0f514..128d6b88532630693acc9f92ce99387140b2aec8 100644 (file)
@@ -63,7 +63,7 @@ char ixgbe_default_device_descr[] =
 static char ixgbe_default_device_descr[] =
                              "Intel(R) 10 Gigabit Network Connection";
 #endif
-#define DRV_VERSION "3.13.10-k"
+#define DRV_VERSION "3.15.1-k"
 const char ixgbe_driver_version[] = DRV_VERSION;
 static const char ixgbe_copyright[] =
                                "Copyright (c) 1999-2013 Intel Corporation.";
@@ -109,6 +109,7 @@ static DEFINE_PCI_DEVICE_TABLE(ixgbe_pci_tbl) = {
        {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X540T), board_X540 },
        {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_SF2), board_82599 },
        {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_LS), board_82599 },
+       {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_QSFP_SF_QP), board_82599 },
        {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599EN_SFP), board_82599 },
        {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_SF_QP), board_82599 },
        {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X540T1), board_X540 },
@@ -195,6 +196,86 @@ static s32 ixgbe_get_parent_bus_info(struct ixgbe_adapter *adapter)
        return 0;
 }
 
+/**
+ * ixgbe_check_from_parent - Determine whether PCIe info should come from parent
+ * @hw: hw specific details
+ *
+ * This function is used by probe to determine whether a device's PCI-Express
+ * bandwidth details should be gathered from the parent bus instead of from the
+ * device. Used to ensure that various locations all have the correct device ID
+ * checks.
+ */
+static inline bool ixgbe_pcie_from_parent(struct ixgbe_hw *hw)
+{
+       switch (hw->device_id) {
+       case IXGBE_DEV_ID_82599_SFP_SF_QP:
+       case IXGBE_DEV_ID_82599_QSFP_SF_QP:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static void ixgbe_check_minimum_link(struct ixgbe_adapter *adapter,
+                                    int expected_gts)
+{
+       int max_gts = 0;
+       enum pci_bus_speed speed = PCI_SPEED_UNKNOWN;
+       enum pcie_link_width width = PCIE_LNK_WIDTH_UNKNOWN;
+       struct pci_dev *pdev;
+
+       /* determine whether to use the the parent device
+        */
+       if (ixgbe_pcie_from_parent(&adapter->hw))
+               pdev = adapter->pdev->bus->parent->self;
+       else
+               pdev = adapter->pdev;
+
+       if (pcie_get_minimum_link(pdev, &speed, &width) ||
+           speed == PCI_SPEED_UNKNOWN || width == PCIE_LNK_WIDTH_UNKNOWN) {
+               e_dev_warn("Unable to determine PCI Express bandwidth.\n");
+               return;
+       }
+
+       switch (speed) {
+       case PCIE_SPEED_2_5GT:
+               /* 8b/10b encoding reduces max throughput by 20% */
+               max_gts = 2 * width;
+               break;
+       case PCIE_SPEED_5_0GT:
+               /* 8b/10b encoding reduces max throughput by 20% */
+               max_gts = 4 * width;
+               break;
+       case PCIE_SPEED_8_0GT:
+               /* 128b/130b encoding only reduces throughput by 1% */
+               max_gts = 8 * width;
+               break;
+       default:
+               e_dev_warn("Unable to determine PCI Express bandwidth.\n");
+               return;
+       }
+
+       e_dev_info("PCI Express bandwidth of %dGT/s available\n",
+                  max_gts);
+       e_dev_info("(Speed:%s, Width: x%d, Encoding Loss:%s)\n",
+                  (speed == PCIE_SPEED_8_0GT ? "8.0GT/s" :
+                   speed == PCIE_SPEED_5_0GT ? "5.0GT/s" :
+                   speed == PCIE_SPEED_2_5GT ? "2.5GT/s" :
+                   "Unknown"),
+                  width,
+                  (speed == PCIE_SPEED_2_5GT ? "20%" :
+                   speed == PCIE_SPEED_5_0GT ? "20%" :
+                   speed == PCIE_SPEED_8_0GT ? "N/a" :
+                   "Unknown"));
+
+       if (max_gts < expected_gts) {
+               e_dev_warn("This is not sufficient for optimal performance of this card.\n");
+               e_dev_warn("For optimal performance, at least %dGT/s of bandwidth is required.\n",
+                       expected_gts);
+               e_dev_warn("A slot with more lanes and/or higher speed is suggested.\n");
+       }
+}
+
 static void ixgbe_service_event_schedule(struct ixgbe_adapter *adapter)
 {
        if (!test_bit(__IXGBE_DOWN, &adapter->state) &&
@@ -1998,7 +2079,7 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
        return total_rx_packets;
 }
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
 /* must be called with local_bh_disable()d */
 static int ixgbe_low_latency_recv(struct napi_struct *napi)
 {
@@ -2030,7 +2111,7 @@ static int ixgbe_low_latency_recv(struct napi_struct *napi)
 
        return found;
 }
-#endif /* CONFIG_NET_LL_RX_POLL */
+#endif /* CONFIG_NET_RX_BUSY_POLL */
 
 /**
  * ixgbe_configure_msix - Configure MSI-X hardware
@@ -3724,8 +3805,15 @@ void ixgbe_set_rx_mode(struct net_device *netdev)
                hw->addr_ctrl.user_set_promisc = true;
                fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
                vmolr |= (IXGBE_VMOLR_ROPE | IXGBE_VMOLR_MPE);
-               /* don't hardware filter vlans in promisc mode */
-               ixgbe_vlan_filter_disable(adapter);
+               /* Only disable hardware filter vlans in promiscuous mode
+                * if SR-IOV and VMDQ are disabled - otherwise ensure
+                * that hardware VLAN filters remain enabled.
+                */
+               if (!(adapter->flags & (IXGBE_FLAG_VMDQ_ENABLED |
+                                       IXGBE_FLAG_SRIOV_ENABLED)))
+                       ixgbe_vlan_filter_disable(adapter);
+               else
+                       ixgbe_vlan_filter_enable(adapter);
        } else {
                if (netdev->flags & IFF_ALLMULTI) {
                        fctrl |= IXGBE_FCTRL_MPE;
@@ -4352,7 +4440,7 @@ void ixgbe_reset(struct ixgbe_adapter *adapter)
        if (hw->mac.san_mac_rar_index)
                hw->mac.ops.set_vmdq_san_mac(hw, VMDQ_P(0));
 
-       if (adapter->flags2 & IXGBE_FLAG2_PTP_ENABLED)
+       if (test_bit(__IXGBE_PTP_RUNNING, &adapter->state))
                ixgbe_ptp_reset(adapter);
 }
 
@@ -4714,8 +4802,7 @@ static int ixgbe_sw_init(struct ixgbe_adapter *adapter)
        ixgbe_pbthresh_setup(adapter);
        hw->fc.pause_time = IXGBE_DEFAULT_FCPAUSE;
        hw->fc.send_xon = true;
-       hw->fc.disable_fc_autoneg =
-               (ixgbe_device_supports_autoneg_fc(hw) == 0) ? false : true;
+       hw->fc.disable_fc_autoneg = ixgbe_device_supports_autoneg_fc(hw);
 
 #ifdef CONFIG_PCI_IOV
        /* assign number of SR-IOV VFs */
@@ -5681,7 +5768,7 @@ static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *adapter)
 
        adapter->last_rx_ptp_check = jiffies;
 
-       if (adapter->flags2 & IXGBE_FLAG2_PTP_ENABLED)
+       if (test_bit(__IXGBE_PTP_RUNNING, &adapter->state))
                ixgbe_ptp_start_cyclecounter(adapter);
 
        e_info(drv, "NIC Link is Up %s, Flow Control: %s\n",
@@ -5727,7 +5814,7 @@ static void ixgbe_watchdog_link_is_down(struct ixgbe_adapter *adapter)
        if (ixgbe_is_sfp(hw) && hw->mac.type == ixgbe_mac_82598EB)
                adapter->flags2 |= IXGBE_FLAG2_SEARCH_FOR_SFP;
 
-       if (adapter->flags2 & IXGBE_FLAG2_PTP_ENABLED)
+       if (test_bit(__IXGBE_PTP_RUNNING, &adapter->state))
                ixgbe_ptp_start_cyclecounter(adapter);
 
        e_info(drv, "NIC Link is Down\n");
@@ -5826,10 +5913,6 @@ static void ixgbe_sfp_detection_subtask(struct ixgbe_adapter *adapter)
            !(adapter->flags2 & IXGBE_FLAG2_SFP_NEEDS_RESET))
                return;
 
-       /* concurent i2c reads are not supported */
-       if (test_bit(__IXGBE_READ_I2C, &adapter->state))
-               return;
-
        /* someone else is in init, wait until next service event */
        if (test_and_set_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
                return;
@@ -6038,7 +6121,7 @@ static void ixgbe_service_task(struct work_struct *work)
        ixgbe_fdir_reinit_subtask(adapter);
        ixgbe_check_hang_subtask(adapter);
 
-       if (adapter->flags2 & IXGBE_FLAG2_PTP_ENABLED) {
+       if (test_bit(__IXGBE_PTP_RUNNING, &adapter->state)) {
                ixgbe_ptp_overflow_check(adapter);
                ixgbe_ptp_rx_hang(adapter);
        }
@@ -7227,7 +7310,7 @@ static const struct net_device_ops ixgbe_netdev_ops = {
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = ixgbe_netpoll,
 #endif
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        .ndo_busy_poll          = ixgbe_low_latency_recv,
 #endif
 #ifdef IXGBE_FCOE
@@ -7246,6 +7329,42 @@ static const struct net_device_ops ixgbe_netdev_ops = {
        .ndo_bridge_getlink     = ixgbe_ndo_bridge_getlink,
 };
 
+/**
+ * ixgbe_enumerate_functions - Get the number of ports this device has
+ * @adapter: adapter structure
+ *
+ * This function enumerates the phsyical functions co-located on a single slot,
+ * in order to determine how many ports a device has. This is most useful in
+ * determining the required GT/s of PCIe bandwidth necessary for optimal
+ * performance.
+ **/
+static inline int ixgbe_enumerate_functions(struct ixgbe_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       struct list_head *entry;
+       int physfns = 0;
+
+       /* Some cards can not use the generic count PCIe functions method, and
+        * so must be hardcoded to the correct value.
+        */
+       switch (hw->device_id) {
+       case IXGBE_DEV_ID_82599_SFP_SF_QP:
+       case IXGBE_DEV_ID_82599_QSFP_SF_QP:
+               physfns = 4;
+               break;
+       default:
+               list_for_each(entry, &adapter->pdev->bus_list) {
+                       struct pci_dev *pdev =
+                               list_entry(entry, struct pci_dev, bus_list);
+                       /* don't count virtual functions */
+                       if (!pdev->is_virtfn)
+                               physfns++;
+               }
+       }
+
+       return physfns;
+}
+
 /**
  * ixgbe_wol_supported - Check whether device supports WoL
  * @hw: hw specific details
@@ -7328,7 +7447,7 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        struct ixgbe_hw *hw;
        const struct ixgbe_info *ii = ixgbe_info_tbl[ent->driver_data];
        static int cards_found;
-       int i, err, pci_using_dac;
+       int i, err, pci_using_dac, expected_gts;
        unsigned int indices = MAX_TX_QUEUES;
        u8 part_str[IXGBE_PBANUM_LENGTH];
 #ifdef IXGBE_FCOE
@@ -7617,7 +7736,7 @@ skip_sriov:
 
        /* pick up the PCI bus settings for reporting later */
        hw->mac.ops.get_bus_info(hw);
-       if (hw->device_id == IXGBE_DEV_ID_82599_SFP_SF_QP)
+       if (ixgbe_pcie_from_parent(hw))
                ixgbe_get_parent_bus_info(adapter);
 
        /* print bus type/speed/width info */
@@ -7643,12 +7762,20 @@ skip_sriov:
                e_dev_info("MAC: %d, PHY: %d, PBA No: %s\n",
                           hw->mac.type, hw->phy.type, part_str);
 
-       if (hw->bus.width <= ixgbe_bus_width_pcie_x4) {
-               e_dev_warn("PCI-Express bandwidth available for this card is "
-                          "not sufficient for optimal performance.\n");
-               e_dev_warn("For optimal performance a x8 PCI-Express slot "
-                          "is required.\n");
+       /* calculate the expected PCIe bandwidth required for optimal
+        * performance. Note that some older parts will never have enough
+        * bandwidth due to being older generation PCIe parts. We clamp these
+        * parts to ensure no warning is displayed if it can't be fixed.
+        */
+       switch (hw->mac.type) {
+       case ixgbe_mac_82598EB:
+               expected_gts = min(ixgbe_enumerate_functions(adapter) * 10, 16);
+               break;
+       default:
+               expected_gts = ixgbe_enumerate_functions(adapter) * 10;
+               break;
        }
+       ixgbe_check_minimum_link(adapter, expected_gts);
 
        /* reset the hardware with the new settings */
        err = hw->mac.ops.start_hw(hw);
index e5691ccbce9dd09eac8caa20120531b5e3ad1a2a..369eef526bc19f3d9e15809e9821ef13ae46afe9 100644 (file)
@@ -203,8 +203,84 @@ out:
        return status;
 }
 
+/**
+ *  ixgbe_read_phy_mdi - Reads a value from a specified PHY register without
+ *  the SWFW lock
+ *  @hw: pointer to hardware structure
+ *  @reg_addr: 32 bit address of PHY register to read
+ *  @phy_data: Pointer to read data from PHY register
+ **/
+s32 ixgbe_read_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type,
+                      u16 *phy_data)
+{
+       u32 i, data, command;
+
+       /* Setup and write the address cycle command */
+       command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT)  |
+                  (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
+                  (hw->phy.mdio.prtad << IXGBE_MSCA_PHY_ADDR_SHIFT) |
+                  (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND));
+
+       IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
+
+       /* Check every 10 usec to see if the address cycle completed.
+        * The MDI Command bit will clear when the operation is
+        * complete
+        */
+       for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
+               udelay(10);
+
+               command = IXGBE_READ_REG(hw, IXGBE_MSCA);
+               if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
+                               break;
+       }
+
+
+       if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
+               hw_dbg(hw, "PHY address command did not complete.\n");
+               return IXGBE_ERR_PHY;
+       }
+
+       /* Address cycle complete, setup and write the read
+        * command
+        */
+       command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT)  |
+                  (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
+                  (hw->phy.mdio.prtad << IXGBE_MSCA_PHY_ADDR_SHIFT) |
+                  (IXGBE_MSCA_READ | IXGBE_MSCA_MDI_COMMAND));
+
+       IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
+
+       /* Check every 10 usec to see if the address cycle
+        * completed. The MDI Command bit will clear when the
+        * operation is complete
+        */
+       for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
+               udelay(10);
+
+               command = IXGBE_READ_REG(hw, IXGBE_MSCA);
+               if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
+                       break;
+       }
+
+       if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
+               hw_dbg(hw, "PHY read command didn't complete\n");
+               return IXGBE_ERR_PHY;
+       }
+
+       /* Read operation is complete.  Get the data
+        * from MSRWD
+        */
+       data = IXGBE_READ_REG(hw, IXGBE_MSRWD);
+       data >>= IXGBE_MSRWD_READ_DATA_SHIFT;
+       *phy_data = (u16)(data);
+
+       return 0;
+}
+
 /**
  *  ixgbe_read_phy_reg_generic - Reads a value from a specified PHY register
+ *  using the SWFW lock - this function is needed in most cases
  *  @hw: pointer to hardware structure
  *  @reg_addr: 32 bit address of PHY register to read
  *  @phy_data: Pointer to read data from PHY register
@@ -212,10 +288,7 @@ out:
 s32 ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr,
                                u32 device_type, u16 *phy_data)
 {
-       u32 command;
-       u32 i;
-       u32 data;
-       s32 status = 0;
+       s32 status;
        u16 gssr;
 
        if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)
@@ -223,86 +296,93 @@ s32 ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr,
        else
                gssr = IXGBE_GSSR_PHY0_SM;
 
-       if (hw->mac.ops.acquire_swfw_sync(hw, gssr) != 0)
+       if (hw->mac.ops.acquire_swfw_sync(hw, gssr) == 0) {
+               status = ixgbe_read_phy_reg_mdi(hw, reg_addr, device_type,
+                                               phy_data);
+               hw->mac.ops.release_swfw_sync(hw, gssr);
+       } else {
                status = IXGBE_ERR_SWFW_SYNC;
+       }
 
-       if (status == 0) {
-               /* Setup and write the address cycle command */
-               command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT)  |
-                          (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
-                          (hw->phy.mdio.prtad << IXGBE_MSCA_PHY_ADDR_SHIFT) |
-                          (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND));
+       return status;
+}
 
-               IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
+/**
+ *  ixgbe_write_phy_reg_mdi - Writes a value to specified PHY register
+ *  without SWFW lock
+ *  @hw: pointer to hardware structure
+ *  @reg_addr: 32 bit PHY register to write
+ *  @device_type: 5 bit device type
+ *  @phy_data: Data to write to the PHY register
+ **/
+s32 ixgbe_write_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr,
+                               u32 device_type, u16 phy_data)
+{
+       u32 i, command;
 
-               /*
-                * Check every 10 usec to see if the address cycle completed.
-                * The MDI Command bit will clear when the operation is
-                * complete
-                */
-               for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
-                       udelay(10);
+       /* Put the data in the MDI single read and write data register*/
+       IXGBE_WRITE_REG(hw, IXGBE_MSRWD, (u32)phy_data);
 
-                       command = IXGBE_READ_REG(hw, IXGBE_MSCA);
+       /* Setup and write the address cycle command */
+       command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT)  |
+                  (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
+                  (hw->phy.mdio.prtad << IXGBE_MSCA_PHY_ADDR_SHIFT) |
+                  (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND));
 
-                       if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
-                               break;
-               }
+       IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
 
-               if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
-                       hw_dbg(hw, "PHY address command did not complete.\n");
-                       status = IXGBE_ERR_PHY;
-               }
+       /*
+        * Check every 10 usec to see if the address cycle completed.
+        * The MDI Command bit will clear when the operation is
+        * complete
+        */
+       for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
+               udelay(10);
 
-               if (status == 0) {
-                       /*
-                        * Address cycle complete, setup and write the read
-                        * command
-                        */
-                       command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT)  |
-                                  (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
-                                  (hw->phy.mdio.prtad <<
-                                   IXGBE_MSCA_PHY_ADDR_SHIFT) |
-                                  (IXGBE_MSCA_READ | IXGBE_MSCA_MDI_COMMAND));
-
-                       IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
-
-                       /*
-                        * Check every 10 usec to see if the address cycle
-                        * completed. The MDI Command bit will clear when the
-                        * operation is complete
-                        */
-                       for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
-                               udelay(10);
-
-                               command = IXGBE_READ_REG(hw, IXGBE_MSCA);
-
-                               if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
-                                       break;
-                       }
+               command = IXGBE_READ_REG(hw, IXGBE_MSCA);
+               if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
+                       break;
+       }
 
-                       if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
-                               hw_dbg(hw, "PHY read command didn't complete\n");
-                               status = IXGBE_ERR_PHY;
-                       } else {
-                               /*
-                                * Read operation is complete.  Get the data
-                                * from MSRWD
-                                */
-                               data = IXGBE_READ_REG(hw, IXGBE_MSRWD);
-                               data >>= IXGBE_MSRWD_READ_DATA_SHIFT;
-                               *phy_data = (u16)(data);
-                       }
-               }
+       if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
+               hw_dbg(hw, "PHY address cmd didn't complete\n");
+               return IXGBE_ERR_PHY;
+       }
 
-               hw->mac.ops.release_swfw_sync(hw, gssr);
+       /*
+        * Address cycle complete, setup and write the write
+        * command
+        */
+       command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT)  |
+                  (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
+                  (hw->phy.mdio.prtad << IXGBE_MSCA_PHY_ADDR_SHIFT) |
+                  (IXGBE_MSCA_WRITE | IXGBE_MSCA_MDI_COMMAND));
+
+       IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
+
+       /* Check every 10 usec to see if the address cycle
+        * completed. The MDI Command bit will clear when the
+        * operation is complete
+        */
+       for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
+               udelay(10);
+
+               command = IXGBE_READ_REG(hw, IXGBE_MSCA);
+               if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
+                       break;
        }
 
-       return status;
+       if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
+               hw_dbg(hw, "PHY write cmd didn't complete\n");
+               return IXGBE_ERR_PHY;
+       }
+
+       return 0;
 }
 
 /**
  *  ixgbe_write_phy_reg_generic - Writes a value to specified PHY register
+ *  using SWFW lock- this function is needed in most cases
  *  @hw: pointer to hardware structure
  *  @reg_addr: 32 bit PHY register to write
  *  @device_type: 5 bit device type
@@ -311,9 +391,7 @@ s32 ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr,
 s32 ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr,
                                 u32 device_type, u16 phy_data)
 {
-       u32 command;
-       u32 i;
-       s32 status = 0;
+       s32 status;
        u16 gssr;
 
        if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)
@@ -321,74 +399,12 @@ s32 ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr,
        else
                gssr = IXGBE_GSSR_PHY0_SM;
 
-       if (hw->mac.ops.acquire_swfw_sync(hw, gssr) != 0)
-               status = IXGBE_ERR_SWFW_SYNC;
-
-       if (status == 0) {
-               /* Put the data in the MDI single read and write data register*/
-               IXGBE_WRITE_REG(hw, IXGBE_MSRWD, (u32)phy_data);
-
-               /* Setup and write the address cycle command */
-               command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT)  |
-                          (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
-                          (hw->phy.mdio.prtad << IXGBE_MSCA_PHY_ADDR_SHIFT) |
-                          (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND));
-
-               IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
-
-               /*
-                * Check every 10 usec to see if the address cycle completed.
-                * The MDI Command bit will clear when the operation is
-                * complete
-                */
-               for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
-                       udelay(10);
-
-                       command = IXGBE_READ_REG(hw, IXGBE_MSCA);
-
-                       if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
-                               break;
-               }
-
-               if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
-                       hw_dbg(hw, "PHY address cmd didn't complete\n");
-                       status = IXGBE_ERR_PHY;
-               }
-
-               if (status == 0) {
-                       /*
-                        * Address cycle complete, setup and write the write
-                        * command
-                        */
-                       command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT)  |
-                                  (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
-                                  (hw->phy.mdio.prtad <<
-                                   IXGBE_MSCA_PHY_ADDR_SHIFT) |
-                                  (IXGBE_MSCA_WRITE | IXGBE_MSCA_MDI_COMMAND));
-
-                       IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
-
-                       /*
-                        * Check every 10 usec to see if the address cycle
-                        * completed. The MDI Command bit will clear when the
-                        * operation is complete
-                        */
-                       for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
-                               udelay(10);
-
-                               command = IXGBE_READ_REG(hw, IXGBE_MSCA);
-
-                               if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
-                                       break;
-                       }
-
-                       if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
-                               hw_dbg(hw, "PHY address cmd didn't complete\n");
-                               status = IXGBE_ERR_PHY;
-                       }
-               }
-
+       if (hw->mac.ops.acquire_swfw_sync(hw, gssr) == 0) {
+               status = ixgbe_write_phy_reg_mdi(hw, reg_addr, device_type,
+                                                phy_data);
                hw->mac.ops.release_swfw_sync(hw, gssr);
+       } else {
+               status = IXGBE_ERR_SWFW_SYNC;
        }
 
        return status;
@@ -825,9 +841,35 @@ out:
 }
 
 /**
- *  ixgbe_identify_sfp_module_generic - Identifies SFP modules
+ *  ixgbe_identify_module_generic - Identifies module type
  *  @hw: pointer to hardware structure
  *
+ *  Determines HW type and calls appropriate function.
+ **/
+s32 ixgbe_identify_module_generic(struct ixgbe_hw *hw)
+{
+       s32 status = IXGBE_ERR_SFP_NOT_PRESENT;
+
+       switch (hw->mac.ops.get_media_type(hw)) {
+       case ixgbe_media_type_fiber:
+               status = ixgbe_identify_sfp_module_generic(hw);
+               break;
+       case ixgbe_media_type_fiber_qsfp:
+               status = ixgbe_identify_qsfp_module_generic(hw);
+               break;
+       default:
+               hw->phy.sfp_type = ixgbe_sfp_type_not_present;
+               status = IXGBE_ERR_SFP_NOT_PRESENT;
+               break;
+       }
+
+       return status;
+}
+
+/**
+ *  ixgbe_identify_sfp_module_generic - Identifies SFP modules
+ *  @hw: pointer to hardware structure
+*
  *  Searches for and identifies the SFP module and assigns appropriate PHY type.
  **/
 s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
@@ -1105,6 +1147,156 @@ err_read_i2c_eeprom:
        return IXGBE_ERR_SFP_NOT_PRESENT;
 }
 
+/**
+ * ixgbe_identify_qsfp_module_generic - Identifies QSFP modules
+ * @hw: pointer to hardware structure
+ *
+ * Searches for and identifies the QSFP module and assigns appropriate PHY type
+ **/
+s32 ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw)
+{
+       struct ixgbe_adapter *adapter = hw->back;
+       s32 status = IXGBE_ERR_PHY_ADDR_INVALID;
+       u32 vendor_oui = 0;
+       enum ixgbe_sfp_type stored_sfp_type = hw->phy.sfp_type;
+       u8 identifier = 0;
+       u8 comp_codes_1g = 0;
+       u8 comp_codes_10g = 0;
+       u8 oui_bytes[3] = {0, 0, 0};
+       u16 enforce_sfp = 0;
+
+       if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_fiber_qsfp) {
+               hw->phy.sfp_type = ixgbe_sfp_type_not_present;
+               status = IXGBE_ERR_SFP_NOT_PRESENT;
+               goto out;
+       }
+
+       status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_IDENTIFIER,
+                                            &identifier);
+
+       if (status != 0)
+               goto err_read_i2c_eeprom;
+
+       if (identifier != IXGBE_SFF_IDENTIFIER_QSFP_PLUS) {
+               hw->phy.type = ixgbe_phy_sfp_unsupported;
+               status = IXGBE_ERR_SFP_NOT_SUPPORTED;
+               goto out;
+       }
+
+       hw->phy.id = identifier;
+
+       /* LAN ID is needed for sfp_type determination */
+       hw->mac.ops.set_lan_id(hw);
+
+       status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_QSFP_10GBE_COMP,
+                                            &comp_codes_10g);
+
+       if (status != 0)
+               goto err_read_i2c_eeprom;
+
+       if (comp_codes_10g & IXGBE_SFF_QSFP_DA_PASSIVE_CABLE) {
+               hw->phy.type = ixgbe_phy_qsfp_passive_unknown;
+               if (hw->bus.lan_id == 0)
+                       hw->phy.sfp_type = ixgbe_sfp_type_da_cu_core0;
+               else
+                       hw->phy.sfp_type = ixgbe_sfp_type_da_cu_core1;
+       } else if (comp_codes_10g & IXGBE_SFF_QSFP_DA_ACTIVE_CABLE) {
+               hw->phy.type = ixgbe_phy_qsfp_active_unknown;
+               if (hw->bus.lan_id == 0)
+                       hw->phy.sfp_type = ixgbe_sfp_type_da_act_lmt_core0;
+               else
+                       hw->phy.sfp_type = ixgbe_sfp_type_da_act_lmt_core1;
+       } else if (comp_codes_10g & (IXGBE_SFF_10GBASESR_CAPABLE |
+                                    IXGBE_SFF_10GBASELR_CAPABLE)) {
+               if (hw->bus.lan_id == 0)
+                       hw->phy.sfp_type = ixgbe_sfp_type_srlr_core0;
+               else
+                       hw->phy.sfp_type = ixgbe_sfp_type_srlr_core1;
+       } else {
+               /* unsupported module type */
+               hw->phy.type = ixgbe_phy_sfp_unsupported;
+               status = IXGBE_ERR_SFP_NOT_SUPPORTED;
+               goto out;
+       }
+
+       if (hw->phy.sfp_type != stored_sfp_type)
+               hw->phy.sfp_setup_needed = true;
+
+       /* Determine if the QSFP+ PHY is dual speed or not. */
+       hw->phy.multispeed_fiber = false;
+       if (((comp_codes_1g & IXGBE_SFF_1GBASESX_CAPABLE) &&
+            (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)) ||
+           ((comp_codes_1g & IXGBE_SFF_1GBASELX_CAPABLE) &&
+            (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE)))
+               hw->phy.multispeed_fiber = true;
+
+       /* Determine PHY vendor for optical modules */
+       if (comp_codes_10g & (IXGBE_SFF_10GBASESR_CAPABLE |
+                             IXGBE_SFF_10GBASELR_CAPABLE)) {
+               status = hw->phy.ops.read_i2c_eeprom(hw,
+                                       IXGBE_SFF_QSFP_VENDOR_OUI_BYTE0,
+                                       &oui_bytes[0]);
+
+               if (status != 0)
+                       goto err_read_i2c_eeprom;
+
+               status = hw->phy.ops.read_i2c_eeprom(hw,
+                                       IXGBE_SFF_QSFP_VENDOR_OUI_BYTE1,
+                                       &oui_bytes[1]);
+
+               if (status != 0)
+                       goto err_read_i2c_eeprom;
+
+               status = hw->phy.ops.read_i2c_eeprom(hw,
+                                       IXGBE_SFF_QSFP_VENDOR_OUI_BYTE2,
+                                       &oui_bytes[2]);
+
+               if (status != 0)
+                       goto err_read_i2c_eeprom;
+
+               vendor_oui =
+                       ((oui_bytes[0] << IXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT) |
+                        (oui_bytes[1] << IXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT) |
+                        (oui_bytes[2] << IXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT));
+
+               if (vendor_oui == IXGBE_SFF_VENDOR_OUI_INTEL)
+                       hw->phy.type = ixgbe_phy_qsfp_intel;
+               else
+                       hw->phy.type = ixgbe_phy_qsfp_unknown;
+
+               hw->mac.ops.get_device_caps(hw, &enforce_sfp);
+               if (!(enforce_sfp & IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP)) {
+                       /* Make sure we're a supported PHY type */
+                       if (hw->phy.type == ixgbe_phy_qsfp_intel) {
+                               status = 0;
+                       } else {
+                               if (hw->allow_unsupported_sfp == true) {
+                                       e_warn(hw, "WARNING: Intel (R) Network Connections are quality tested using Intel (R) Ethernet Optics. Using untested modules is not supported and may cause unstable operation or damage to the module or the adapter. Intel Corporation is not responsible for any harm caused by using untested modules.\n");
+                                       status = 0;
+                               } else {
+                                       hw_dbg(hw,
+                                              "QSFP module not supported\n");
+                                       hw->phy.type =
+                                               ixgbe_phy_sfp_unsupported;
+                                       status = IXGBE_ERR_SFP_NOT_SUPPORTED;
+                               }
+                       }
+               } else {
+                       status = 0;
+               }
+       }
+
+out:
+       return status;
+
+err_read_i2c_eeprom:
+       hw->phy.sfp_type = ixgbe_sfp_type_not_present;
+       hw->phy.id = 0;
+       hw->phy.type = ixgbe_phy_unknown;
+
+       return IXGBE_ERR_SFP_NOT_PRESENT;
+}
+
 /**
  *  ixgbe_get_sfp_init_sequence_offsets - Provides offset of PHY init sequence
  *  @hw: pointer to hardware structure
index 886a3431cf5bc36e3c38a22b5964fb4488b8ed66..138dadd7cf336e94ae84254653052d351cb3258b 100644 (file)
 #define IXGBE_I2C_EEPROM_DEV_ADDR2   0xA2
 
 /* EEPROM byte offsets */
-#define IXGBE_SFF_IDENTIFIER         0x0
-#define IXGBE_SFF_IDENTIFIER_SFP     0x3
-#define IXGBE_SFF_VENDOR_OUI_BYTE0   0x25
-#define IXGBE_SFF_VENDOR_OUI_BYTE1   0x26
-#define IXGBE_SFF_VENDOR_OUI_BYTE2   0x27
-#define IXGBE_SFF_1GBE_COMP_CODES    0x6
-#define IXGBE_SFF_10GBE_COMP_CODES   0x3
-#define IXGBE_SFF_CABLE_TECHNOLOGY   0x8
-#define IXGBE_SFF_CABLE_SPEC_COMP    0x3C
-#define IXGBE_SFF_SFF_8472_SWAP      0x5C
-#define IXGBE_SFF_SFF_8472_COMP      0x5E
+#define IXGBE_SFF_IDENTIFIER           0x0
+#define IXGBE_SFF_IDENTIFIER_SFP       0x3
+#define IXGBE_SFF_VENDOR_OUI_BYTE0     0x25
+#define IXGBE_SFF_VENDOR_OUI_BYTE1     0x26
+#define IXGBE_SFF_VENDOR_OUI_BYTE2     0x27
+#define IXGBE_SFF_1GBE_COMP_CODES      0x6
+#define IXGBE_SFF_10GBE_COMP_CODES     0x3
+#define IXGBE_SFF_CABLE_TECHNOLOGY     0x8
+#define IXGBE_SFF_CABLE_SPEC_COMP      0x3C
+#define IXGBE_SFF_SFF_8472_SWAP                0x5C
+#define IXGBE_SFF_SFF_8472_COMP                0x5E
+#define IXGBE_SFF_SFF_8472_OSCB                0x6E
+#define IXGBE_SFF_SFF_8472_ESCB                0x76
+#define IXGBE_SFF_IDENTIFIER_QSFP_PLUS 0xD
+#define IXGBE_SFF_QSFP_VENDOR_OUI_BYTE0        0xA5
+#define IXGBE_SFF_QSFP_VENDOR_OUI_BYTE1        0xA6
+#define IXGBE_SFF_QSFP_VENDOR_OUI_BYTE2        0xA7
+#define IXGBE_SFF_QSFP_10GBE_COMP      0x83
+#define IXGBE_SFF_QSFP_1GBE_COMP       0x86
 
 /* Bitmasks */
 #define IXGBE_SFF_DA_PASSIVE_CABLE           0x4
 #define IXGBE_SFF_1GBASET_CAPABLE            0x8
 #define IXGBE_SFF_10GBASESR_CAPABLE          0x10
 #define IXGBE_SFF_10GBASELR_CAPABLE          0x20
+#define IXGBE_SFF_SOFT_RS_SELECT_MASK  0x8
+#define IXGBE_SFF_SOFT_RS_SELECT_10G   0x8
+#define IXGBE_SFF_SOFT_RS_SELECT_1G    0x0
 #define IXGBE_SFF_ADDRESSING_MODE           0x4
+#define IXGBE_SFF_QSFP_DA_ACTIVE_CABLE       0x1
+#define IXGBE_SFF_QSFP_DA_PASSIVE_CABLE      0x8
 #define IXGBE_I2C_EEPROM_READ_MASK           0x100
 #define IXGBE_I2C_EEPROM_STATUS_MASK         0x3
 #define IXGBE_I2C_EEPROM_STATUS_NO_OPERATION 0x0
@@ -102,6 +115,10 @@ s32 ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr,
                                u32 device_type, u16 *phy_data);
 s32 ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr,
                                 u32 device_type, u16 phy_data);
+s32 ixgbe_read_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr,
+                          u32 device_type, u16 *phy_data);
+s32 ixgbe_write_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr,
+                           u32 device_type, u16 phy_data);
 s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw);
 s32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw,
                                        ixgbe_link_speed speed,
@@ -121,7 +138,9 @@ s32 ixgbe_get_phy_firmware_version_generic(struct ixgbe_hw *hw,
                                            u16 *firmware_version);
 
 s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw);
+s32 ixgbe_identify_module_generic(struct ixgbe_hw *hw);
 s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw);
+s32 ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw);
 s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw,
                                         u16 *list_offset,
                                         u16 *data_offset);
index 331987d6815c91ef7f6296c1d3062821c3268a1b..5184e2a1a7d8249bc746ce6496e55f5789a0e949 100644 (file)
@@ -885,8 +885,8 @@ void ixgbe_ptp_init(struct ixgbe_adapter *adapter)
 
        ixgbe_ptp_reset(adapter);
 
-       /* set the flag that PTP has been enabled */
-       adapter->flags2 |= IXGBE_FLAG2_PTP_ENABLED;
+       /* enter the IXGBE_PTP_RUNNING state */
+       set_bit(__IXGBE_PTP_RUNNING, &adapter->state);
 
        return;
 }
@@ -899,10 +899,12 @@ void ixgbe_ptp_init(struct ixgbe_adapter *adapter)
  */
 void ixgbe_ptp_stop(struct ixgbe_adapter *adapter)
 {
-       /* stop the overflow check task */
-       adapter->flags2 &= ~(IXGBE_FLAG2_PTP_ENABLED |
-                            IXGBE_FLAG2_PTP_PPS_ENABLED);
+       /* Leave the IXGBE_PTP_RUNNING state. */
+       if (!test_and_clear_bit(__IXGBE_PTP_RUNNING, &adapter->state))
+               return;
 
+       /* stop the PPS signal */
+       adapter->flags2 &= ~IXGBE_FLAG2_PTP_PPS_ENABLED;
        ixgbe_ptp_setup_sdp(adapter);
 
        cancel_work_sync(&adapter->ptp_tx_work);
index 1e7d587c4e572f9efdd3f876b98e906cb3963561..73c8e73bb6e74754b36e2637c07ada9510e1fe4c 100644 (file)
@@ -173,39 +173,6 @@ void ixgbe_enable_sriov(struct ixgbe_adapter *adapter)
        ixgbe_disable_sriov(adapter);
 }
 
-static bool ixgbe_vfs_are_assigned(struct ixgbe_adapter *adapter)
-{
-       struct pci_dev *pdev = adapter->pdev;
-       struct pci_dev *vfdev;
-       int dev_id;
-
-       switch (adapter->hw.mac.type) {
-       case ixgbe_mac_82599EB:
-               dev_id = IXGBE_DEV_ID_82599_VF;
-               break;
-       case ixgbe_mac_X540:
-               dev_id = IXGBE_DEV_ID_X540_VF;
-               break;
-       default:
-               return false;
-       }
-
-       /* loop through all the VFs to see if we own any that are assigned */
-       vfdev = pci_get_device(PCI_VENDOR_ID_INTEL, dev_id, NULL);
-       while (vfdev) {
-               /* if we don't own it we don't care */
-               if (vfdev->is_virtfn && vfdev->physfn == pdev) {
-                       /* if it is assigned we cannot release it */
-                       if (vfdev->dev_flags & PCI_DEV_FLAGS_ASSIGNED)
-                               return true;
-               }
-
-               vfdev = pci_get_device(PCI_VENDOR_ID_INTEL, dev_id, vfdev);
-       }
-
-       return false;
-}
-
 #endif /* #ifdef CONFIG_PCI_IOV */
 int ixgbe_disable_sriov(struct ixgbe_adapter *adapter)
 {
@@ -235,7 +202,7 @@ int ixgbe_disable_sriov(struct ixgbe_adapter *adapter)
         * without causing issues, so just leave the hardware
         * available but disabled
         */
-       if (ixgbe_vfs_are_assigned(adapter)) {
+       if (pci_vfs_assigned(adapter->pdev)) {
                e_dev_warn("Unloading driver while VFs are assigned - VFs will not be deallocated\n");
                return -EPERM;
        }
@@ -768,6 +735,29 @@ static int ixgbe_set_vf_mac_addr(struct ixgbe_adapter *adapter,
        return ixgbe_set_vf_mac(adapter, vf, new_mac) < 0;
 }
 
+static int ixgbe_find_vlvf_entry(struct ixgbe_hw *hw, u32 vlan)
+{
+       u32 vlvf;
+       s32 regindex;
+
+       /* short cut the special case */
+       if (vlan == 0)
+               return 0;
+
+       /* Search for the vlan id in the VLVF entries */
+       for (regindex = 1; regindex < IXGBE_VLVF_ENTRIES; regindex++) {
+               vlvf = IXGBE_READ_REG(hw, IXGBE_VLVF(regindex));
+               if ((vlvf & VLAN_VID_MASK) == vlan)
+                       break;
+       }
+
+       /* Return a negative value if not found */
+       if (regindex >= IXGBE_VLVF_ENTRIES)
+               regindex = -1;
+
+       return regindex;
+}
+
 static int ixgbe_set_vf_vlan_msg(struct ixgbe_adapter *adapter,
                                 u32 *msgbuf, u32 vf)
 {
@@ -775,6 +765,9 @@ static int ixgbe_set_vf_vlan_msg(struct ixgbe_adapter *adapter,
        int add = (msgbuf[0] & IXGBE_VT_MSGINFO_MASK) >> IXGBE_VT_MSGINFO_SHIFT;
        int vid = (msgbuf[1] & IXGBE_VLVF_VLANID_MASK);
        int err;
+       s32 reg_ndx;
+       u32 vlvf;
+       u32 bits;
        u8 tcs = netdev_get_num_tc(adapter->netdev);
 
        if (adapter->vfinfo[vf].pf_vlan || tcs) {
@@ -790,10 +783,50 @@ static int ixgbe_set_vf_vlan_msg(struct ixgbe_adapter *adapter,
        else if (adapter->vfinfo[vf].vlan_count)
                adapter->vfinfo[vf].vlan_count--;
 
+       /* in case of promiscuous mode any VLAN filter set for a VF must
+        * also have the PF pool added to it.
+        */
+       if (add && adapter->netdev->flags & IFF_PROMISC)
+               err = ixgbe_set_vf_vlan(adapter, add, vid, VMDQ_P(0));
+
        err = ixgbe_set_vf_vlan(adapter, add, vid, vf);
        if (!err && adapter->vfinfo[vf].spoofchk_enabled)
                hw->mac.ops.set_vlan_anti_spoofing(hw, true, vf);
 
+       /* Go through all the checks to see if the VLAN filter should
+        * be wiped completely.
+        */
+       if (!add && adapter->netdev->flags & IFF_PROMISC) {
+               reg_ndx = ixgbe_find_vlvf_entry(hw, vid);
+               if (reg_ndx < 0)
+                       goto out;
+               vlvf = IXGBE_READ_REG(hw, IXGBE_VLVF(reg_ndx));
+               /* See if any other pools are set for this VLAN filter
+                * entry other than the PF.
+                */
+               if (VMDQ_P(0) < 32) {
+                       bits = IXGBE_READ_REG(hw, IXGBE_VLVFB(reg_ndx * 2));
+                       bits &= ~(1 << VMDQ_P(0));
+                       bits |= IXGBE_READ_REG(hw,
+                                              IXGBE_VLVFB(reg_ndx * 2) + 1);
+               } else {
+                       bits = IXGBE_READ_REG(hw,
+                                             IXGBE_VLVFB(reg_ndx * 2) + 1);
+                       bits &= ~(1 << (VMDQ_P(0) - 32));
+                       bits |= IXGBE_READ_REG(hw, IXGBE_VLVFB(reg_ndx * 2));
+               }
+
+               /* If the filter was removed then ensure PF pool bit
+                * is cleared if the PF only added itself to the pool
+                * because the PF is in promiscuous mode.
+                */
+               if ((vlvf & VLAN_VID_MASK) == vid &&
+                   !test_bit(vid, adapter->active_vlans) && !bits)
+                       ixgbe_set_vf_vlan(adapter, add, vid, VMDQ_P(0));
+       }
+
+out:
+
        return err;
 }
 
index 70c6aa3d3f959fc6f86fa032fc874376f714efe9..161ff18be77550bd71386b2d05fd5ec16ee7c4f3 100644 (file)
@@ -69,6 +69,7 @@
 #define IXGBE_DEV_ID_82599_LS            0x154F
 #define IXGBE_DEV_ID_X540T               0x1528
 #define IXGBE_DEV_ID_82599_SFP_SF_QP     0x154A
+#define IXGBE_DEV_ID_82599_QSFP_SF_QP    0x1558
 #define IXGBE_DEV_ID_X540T1              0x1560
 
 /* VF Device IDs */
@@ -1520,9 +1521,11 @@ enum {
 #define IXGBE_ESDP_SDP5 0x00000020 /* SDP5 Data Value */
 #define IXGBE_ESDP_SDP6 0x00000040 /* SDP6 Data Value */
 #define IXGBE_ESDP_SDP0_DIR     0x00000100 /* SDP0 IO direction */
+#define IXGBE_ESDP_SDP1_DIR     0x00000200 /* SDP1 IO direction */
 #define IXGBE_ESDP_SDP4_DIR     0x00000004 /* SDP4 IO direction */
 #define IXGBE_ESDP_SDP5_DIR     0x00002000 /* SDP5 IO direction */
 #define IXGBE_ESDP_SDP0_NATIVE  0x00010000 /* SDP0 Native Function */
+#define IXGBE_ESDP_SDP1_NATIVE  0x00020000 /* SDP1 IO mode */
 
 /* LEDCTL Bit Masks */
 #define IXGBE_LED_IVRT_BASE      0x00000040
@@ -2582,6 +2585,10 @@ enum ixgbe_phy_type {
        ixgbe_phy_sfp_ftl_active,
        ixgbe_phy_sfp_unknown,
        ixgbe_phy_sfp_intel,
+       ixgbe_phy_qsfp_passive_unknown,
+       ixgbe_phy_qsfp_active_unknown,
+       ixgbe_phy_qsfp_intel,
+       ixgbe_phy_qsfp_unknown,
        ixgbe_phy_sfp_unsupported,
        ixgbe_phy_generic
 };
@@ -2622,6 +2629,8 @@ enum ixgbe_sfp_type {
 enum ixgbe_media_type {
        ixgbe_media_type_unknown = 0,
        ixgbe_media_type_fiber,
+       ixgbe_media_type_fiber_fixed,
+       ixgbe_media_type_fiber_qsfp,
        ixgbe_media_type_fiber_lco,
        ixgbe_media_type_copper,
        ixgbe_media_type_backplane,
@@ -2885,6 +2894,8 @@ struct ixgbe_phy_operations {
        s32 (*reset)(struct ixgbe_hw *);
        s32 (*read_reg)(struct ixgbe_hw *, u32, u32, u16 *);
        s32 (*write_reg)(struct ixgbe_hw *, u32, u32, u16);
+       s32 (*read_reg_mdi)(struct ixgbe_hw *, u32, u32, u16 *);
+       s32 (*write_reg_mdi)(struct ixgbe_hw *, u32, u32, u16);
        s32 (*setup_link)(struct ixgbe_hw *);
        s32 (*setup_link_speed)(struct ixgbe_hw *, ixgbe_link_speed, bool);
        s32 (*check_link)(struct ixgbe_hw *, ixgbe_link_speed *, bool *);
@@ -2953,6 +2964,7 @@ struct ixgbe_phy_info {
        bool                            smart_speed_active;
        bool                            multispeed_fiber;
        bool                            reset_if_overtemp;
+       bool                            qsfp_shared_i2c_bus;
 };
 
 #include "ixgbe_mbx.h"
index 712779fb12b7d80416db0a4349257f046ae0d11d..2777c70c603b550676b77027fd96e7b9a79fbe6b 100644 (file)
 #define MVNETA_MAC_ADDR_HIGH                     0x2418
 #define MVNETA_SDMA_CONFIG                       0x241c
 #define      MVNETA_SDMA_BRST_SIZE_16            4
-#define      MVNETA_NO_DESC_SWAP                 0x0
 #define      MVNETA_RX_BRST_SZ_MASK(burst)       ((burst) << 1)
 #define      MVNETA_RX_NO_DATA_SWAP              BIT(4)
 #define      MVNETA_TX_NO_DATA_SWAP              BIT(5)
+#define      MVNETA_DESC_SWAP                    BIT(6)
 #define      MVNETA_TX_BRST_SZ_MASK(burst)       ((burst) << 22)
 #define MVNETA_PORT_STATUS                       0x2444
 #define      MVNETA_TX_IN_PRGRS                  BIT(1)
 #define      MVNETA_TX_FIFO_EMPTY                BIT(8)
 #define MVNETA_RX_MIN_FRAME_SIZE                 0x247c
+#define MVNETA_SGMII_SERDES_CFG                         0x24A0
+#define      MVNETA_SGMII_SERDES_PROTO          0x0cc7
 #define MVNETA_TYPE_PRIO                         0x24bc
 #define      MVNETA_FORCE_UNI                    BIT(21)
 #define MVNETA_TXQ_CMD_1                         0x24e4
@@ -262,8 +264,7 @@ struct mvneta_port {
  * layout of the transmit and reception DMA descriptors, and their
  * layout is therefore defined by the hardware design
  */
-struct mvneta_tx_desc {
-       u32  command;           /* Options used by HW for packet transmitting.*/
+
 #define MVNETA_TX_L3_OFF_SHIFT 0
 #define MVNETA_TX_IP_HLEN_SHIFT        8
 #define MVNETA_TX_L4_UDP       BIT(16)
@@ -278,15 +279,6 @@ struct mvneta_tx_desc {
 #define MVNETA_TX_L4_CSUM_FULL BIT(30)
 #define MVNETA_TX_L4_CSUM_NOT  BIT(31)
 
-       u16  reserverd1;        /* csum_l4 (for future use)             */
-       u16  data_size;         /* Data size of transmitted packet in bytes */
-       u32  buf_phys_addr;     /* Physical addr of transmitted buffer  */
-       u32  reserved2;         /* hw_cmd - (for future use, PMT)       */
-       u32  reserved3[4];      /* Reserved - (for future use)          */
-};
-
-struct mvneta_rx_desc {
-       u32  status;            /* Info about received packet           */
 #define MVNETA_RXD_ERR_CRC             0x0
 #define MVNETA_RXD_ERR_SUMMARY         BIT(16)
 #define MVNETA_RXD_ERR_OVERRUN         BIT(17)
@@ -297,16 +289,57 @@ struct mvneta_rx_desc {
 #define MVNETA_RXD_FIRST_LAST_DESC     (BIT(26) | BIT(27))
 #define MVNETA_RXD_L4_CSUM_OK          BIT(30)
 
+#if defined(__LITTLE_ENDIAN)
+struct mvneta_tx_desc {
+       u32  command;           /* Options used by HW for packet transmitting.*/
+       u16  reserverd1;        /* csum_l4 (for future use)             */
+       u16  data_size;         /* Data size of transmitted packet in bytes */
+       u32  buf_phys_addr;     /* Physical addr of transmitted buffer  */
+       u32  reserved2;         /* hw_cmd - (for future use, PMT)       */
+       u32  reserved3[4];      /* Reserved - (for future use)          */
+};
+
+struct mvneta_rx_desc {
+       u32  status;            /* Info about received packet           */
        u16  reserved1;         /* pnc_info - (for future use, PnC)     */
        u16  data_size;         /* Size of received packet in bytes     */
+
        u32  buf_phys_addr;     /* Physical address of the buffer       */
        u32  reserved2;         /* pnc_flow_id  (for future use, PnC)   */
+
        u32  buf_cookie;        /* cookie for access to RX buffer in rx path */
        u16  reserved3;         /* prefetch_cmd, for future use         */
        u16  reserved4;         /* csum_l4 - (for future use, PnC)      */
+
+       u32  reserved5;         /* pnc_extra PnC (for future use, PnC)  */
+       u32  reserved6;         /* hw_cmd (for future use, PnC and HWF) */
+};
+#else
+struct mvneta_tx_desc {
+       u16  data_size;         /* Data size of transmitted packet in bytes */
+       u16  reserverd1;        /* csum_l4 (for future use)             */
+       u32  command;           /* Options used by HW for packet transmitting.*/
+       u32  reserved2;         /* hw_cmd - (for future use, PMT)       */
+       u32  buf_phys_addr;     /* Physical addr of transmitted buffer  */
+       u32  reserved3[4];      /* Reserved - (for future use)          */
+};
+
+struct mvneta_rx_desc {
+       u16  data_size;         /* Size of received packet in bytes     */
+       u16  reserved1;         /* pnc_info - (for future use, PnC)     */
+       u32  status;            /* Info about received packet           */
+
+       u32  reserved2;         /* pnc_flow_id  (for future use, PnC)   */
+       u32  buf_phys_addr;     /* Physical address of the buffer       */
+
+       u16  reserved4;         /* csum_l4 - (for future use, PnC)      */
+       u16  reserved3;         /* prefetch_cmd, for future use         */
+       u32  buf_cookie;        /* cookie for access to RX buffer in rx path */
+
        u32  reserved5;         /* pnc_extra PnC (for future use, PnC)  */
        u32  reserved6;         /* hw_cmd (for future use, PnC and HWF) */
 };
+#endif
 
 struct mvneta_tx_queue {
        /* Number of this TX queue, in the range 0-7 */
@@ -655,6 +688,8 @@ static void mvneta_port_sgmii_config(struct mvneta_port *pp)
        val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
        val |= MVNETA_GMAC2_PSC_ENABLE;
        mvreg_write(pp, MVNETA_GMAC_CTRL_2, val);
+
+       mvreg_write(pp, MVNETA_SGMII_SERDES_CFG, MVNETA_SGMII_SERDES_PROTO);
 }
 
 /* Start the Ethernet port RX and TX activity */
@@ -904,9 +939,11 @@ static void mvneta_defaults_set(struct mvneta_port *pp)
        /* Default burst size */
        val |= MVNETA_TX_BRST_SZ_MASK(MVNETA_SDMA_BRST_SIZE_16);
        val |= MVNETA_RX_BRST_SZ_MASK(MVNETA_SDMA_BRST_SIZE_16);
+       val |= MVNETA_RX_NO_DATA_SWAP | MVNETA_TX_NO_DATA_SWAP;
 
-       val |= (MVNETA_RX_NO_DATA_SWAP | MVNETA_TX_NO_DATA_SWAP |
-               MVNETA_NO_DESC_SWAP);
+#if defined(__BIG_ENDIAN)
+       val |= MVNETA_DESC_SWAP;
+#endif
 
        /* Assign port SDMA configuration */
        mvreg_write(pp, MVNETA_SDMA_CONFIG, val);
@@ -2728,28 +2765,24 @@ static int mvneta_probe(struct platform_device *pdev)
 
        pp = netdev_priv(dev);
 
-       pp->tx_done_timer.function = mvneta_tx_done_timer_callback;
-       init_timer(&pp->tx_done_timer);
-       clear_bit(MVNETA_F_TX_DONE_TIMER_BIT, &pp->flags);
-
        pp->weight = MVNETA_RX_POLL_WEIGHT;
        pp->phy_node = phy_node;
        pp->phy_interface = phy_mode;
 
-       pp->base = of_iomap(dn, 0);
-       if (pp->base == NULL) {
-               err = -ENOMEM;
-               goto err_free_irq;
-       }
-
        pp->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(pp->clk)) {
                err = PTR_ERR(pp->clk);
-               goto err_unmap;
+               goto err_free_irq;
        }
 
        clk_prepare_enable(pp->clk);
 
+       pp->base = of_iomap(dn, 0);
+       if (pp->base == NULL) {
+               err = -ENOMEM;
+               goto err_clk;
+       }
+
        dt_mac_addr = of_get_mac_address(dn);
        if (dt_mac_addr && is_valid_ether_addr(dt_mac_addr)) {
                mac_from = "device tree";
@@ -2766,6 +2799,9 @@ static int mvneta_probe(struct platform_device *pdev)
        }
 
        pp->tx_done_timer.data = (unsigned long)dev;
+       pp->tx_done_timer.function = mvneta_tx_done_timer_callback;
+       init_timer(&pp->tx_done_timer);
+       clear_bit(MVNETA_F_TX_DONE_TIMER_BIT, &pp->flags);
 
        pp->tx_ring_size = MVNETA_MAX_TXD;
        pp->rx_ring_size = MVNETA_MAX_RXD;
@@ -2776,7 +2812,7 @@ static int mvneta_probe(struct platform_device *pdev)
        err = mvneta_init(pp, phy_addr);
        if (err < 0) {
                dev_err(&pdev->dev, "can't init eth hal\n");
-               goto err_clk;
+               goto err_unmap;
        }
        mvneta_port_power_up(pp, phy_mode);
 
@@ -2806,10 +2842,10 @@ static int mvneta_probe(struct platform_device *pdev)
 
 err_deinit:
        mvneta_deinit(pp);
-err_clk:
-       clk_disable_unprepare(pp->clk);
 err_unmap:
        iounmap(pp->base);
+err_clk:
+       clk_disable_unprepare(pp->clk);
 err_free_irq:
        irq_dispose_mapping(dev->irq);
 err_free_netdev:
index 299d0184f983c95c1b68d043b1f5d28f0fe329f8..141322c31ae9e28317d71339bc39984eecfa464d 100644 (file)
@@ -809,6 +809,15 @@ int MLX4_CMD_UPDATE_QP_wrapper(struct mlx4_dev *dev, int slave,
        return -EPERM;
 }
 
+int MLX4_CMD_GET_OP_REQ_wrapper(struct mlx4_dev *dev, int slave,
+                    struct mlx4_vhcr *vhcr,
+                    struct mlx4_cmd_mailbox *inbox,
+                    struct mlx4_cmd_mailbox *outbox,
+                    struct mlx4_cmd_info *cmd)
+{
+       return -EPERM;
+}
+
 int mlx4_DMA_wrapper(struct mlx4_dev *dev, int slave,
                     struct mlx4_vhcr *vhcr,
                     struct mlx4_cmd_mailbox *inbox,
@@ -1251,6 +1260,15 @@ static struct mlx4_cmd_info cmd_info[] = {
                .verify = NULL,
                .wrapper = MLX4_CMD_UPDATE_QP_wrapper
        },
+       {
+               .opcode = MLX4_CMD_GET_OP_REQ,
+               .has_inbox = false,
+               .has_outbox = false,
+               .out_is_imm = false,
+               .encode_slave_id = false,
+               .verify = NULL,
+               .wrapper = MLX4_CMD_GET_OP_REQ_wrapper,
+       },
        {
                .opcode = MLX4_CMD_CONF_SPECIAL_QP,
                .has_inbox = false,
index 727874f575cedc80e65d52d4918007151feb3c09..a28cd801a236e5a674de67009a5b872ed29e9e71 100644 (file)
@@ -223,7 +223,7 @@ static int mlx4_en_get_sset_count(struct net_device *dev, int sset)
        case ETH_SS_STATS:
                return (priv->stats_bitmap ? bit_count : NUM_ALL_STATS) +
                        (priv->tx_ring_num * 2) +
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
                        (priv->rx_ring_num * 5);
 #else
                        (priv->rx_ring_num * 2);
@@ -276,7 +276,7 @@ static void mlx4_en_get_ethtool_stats(struct net_device *dev,
        for (i = 0; i < priv->rx_ring_num; i++) {
                data[index++] = priv->rx_ring[i].packets;
                data[index++] = priv->rx_ring[i].bytes;
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
                data[index++] = priv->rx_ring[i].yields;
                data[index++] = priv->rx_ring[i].misses;
                data[index++] = priv->rx_ring[i].cleaned;
@@ -344,7 +344,7 @@ static void mlx4_en_get_strings(struct net_device *dev,
                                "rx%d_packets", i);
                        sprintf(data + (index++) * ETH_GSTRING_LEN,
                                "rx%d_bytes", i);
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
                        sprintf(data + (index++) * ETH_GSTRING_LEN,
                                "rx%d_napi_yield", i);
                        sprintf(data + (index++) * ETH_GSTRING_LEN,
index 5eac871399d8ecedf4fcffff06ed4372753df77f..fa37b7a612133c739263346a5d6f372af0fd9dda 100644 (file)
@@ -68,7 +68,7 @@ int mlx4_en_setup_tc(struct net_device *dev, u8 up)
        return 0;
 }
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
 /* must be called with local_bh_disable()d */
 static int mlx4_en_low_latency_recv(struct napi_struct *napi)
 {
@@ -94,7 +94,7 @@ static int mlx4_en_low_latency_recv(struct napi_struct *napi)
 
        return done;
 }
-#endif /* CONFIG_NET_LL_RX_POLL */
+#endif /* CONFIG_NET_RX_BUSY_POLL */
 
 #ifdef CONFIG_RFS_ACCEL
 
@@ -2140,7 +2140,7 @@ static const struct net_device_ops mlx4_netdev_ops = {
 #ifdef CONFIG_RFS_ACCEL
        .ndo_rx_flow_steer      = mlx4_en_filter_rfs,
 #endif
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        .ndo_busy_poll          = mlx4_en_low_latency_recv,
 #endif
 };
index 7c492382da09937764e8c6bb9a835d1c05771021..6dcca98178884aeca0ec49e222218a27f9eee8a7 100644 (file)
@@ -191,6 +191,39 @@ void mlx4_en_deactivate_tx_ring(struct mlx4_en_priv *priv,
                       MLX4_QP_STATE_RST, NULL, 0, 0, &ring->qp);
 }
 
+static void mlx4_en_stamp_wqe(struct mlx4_en_priv *priv,
+                             struct mlx4_en_tx_ring *ring, int index,
+                             u8 owner)
+{
+       __be32 stamp = cpu_to_be32(STAMP_VAL | (!!owner << STAMP_SHIFT));
+       struct mlx4_en_tx_desc *tx_desc = ring->buf + index * TXBB_SIZE;
+       struct mlx4_en_tx_info *tx_info = &ring->tx_info[index];
+       void *end = ring->buf + ring->buf_size;
+       __be32 *ptr = (__be32 *)tx_desc;
+       int i;
+
+       /* Optimize the common case when there are no wraparounds */
+       if (likely((void *)tx_desc + tx_info->nr_txbb * TXBB_SIZE <= end)) {
+               /* Stamp the freed descriptor */
+               for (i = 0; i < tx_info->nr_txbb * TXBB_SIZE;
+                    i += STAMP_STRIDE) {
+                       *ptr = stamp;
+                       ptr += STAMP_DWORDS;
+               }
+       } else {
+               /* Stamp the freed descriptor */
+               for (i = 0; i < tx_info->nr_txbb * TXBB_SIZE;
+                    i += STAMP_STRIDE) {
+                       *ptr = stamp;
+                       ptr += STAMP_DWORDS;
+                       if ((void *)ptr >= end) {
+                               ptr = ring->buf;
+                               stamp ^= cpu_to_be32(0x80000000);
+                       }
+               }
+       }
+}
+
 
 static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
                                struct mlx4_en_tx_ring *ring,
@@ -205,8 +238,6 @@ static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
        void *end = ring->buf + ring->buf_size;
        int frags = skb_shinfo(skb)->nr_frags;
        int i;
-       __be32 *ptr = (__be32 *)tx_desc;
-       __be32 stamp = cpu_to_be32(STAMP_VAL | (!!owner << STAMP_SHIFT));
        struct skb_shared_hwtstamps hwts;
 
        if (timestamp) {
@@ -232,12 +263,6 @@ static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
                                        skb_frag_size(frag), PCI_DMA_TODEVICE);
                        }
                }
-               /* Stamp the freed descriptor */
-               for (i = 0; i < tx_info->nr_txbb * TXBB_SIZE; i += STAMP_STRIDE) {
-                       *ptr = stamp;
-                       ptr += STAMP_DWORDS;
-               }
-
        } else {
                if (!tx_info->inl) {
                        if ((void *) data >= end) {
@@ -263,16 +288,6 @@ static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
                                ++data;
                        }
                }
-               /* Stamp the freed descriptor */
-               for (i = 0; i < tx_info->nr_txbb * TXBB_SIZE; i += STAMP_STRIDE) {
-                       *ptr = stamp;
-                       ptr += STAMP_DWORDS;
-                       if ((void *) ptr >= end) {
-                               ptr = ring->buf;
-                               stamp ^= cpu_to_be32(0x80000000);
-                       }
-               }
-
        }
        dev_kfree_skb_any(skb);
        return tx_info->nr_txbb;
@@ -318,8 +333,9 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq)
        struct mlx4_en_tx_ring *ring = &priv->tx_ring[cq->ring];
        struct mlx4_cqe *cqe;
        u16 index;
-       u16 new_index, ring_index;
+       u16 new_index, ring_index, stamp_index;
        u32 txbbs_skipped = 0;
+       u32 txbbs_stamp = 0;
        u32 cons_index = mcq->cons_index;
        int size = cq->size;
        u32 size_mask = ring->size_mask;
@@ -335,6 +351,7 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq)
        index = cons_index & size_mask;
        cqe = &buf[(index << factor) + factor];
        ring_index = ring->cons & size_mask;
+       stamp_index = ring_index;
 
        /* Process all completed CQEs */
        while (XNOR(cqe->owner_sr_opcode & MLX4_CQE_OWNER_MASK,
@@ -359,6 +376,12 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq)
                                        priv, ring, ring_index,
                                        !!((ring->cons + txbbs_skipped) &
                                        ring->size), timestamp);
+
+                       mlx4_en_stamp_wqe(priv, ring, stamp_index,
+                                         !!((ring->cons + txbbs_stamp) &
+                                               ring->size));
+                       stamp_index = ring_index;
+                       txbbs_stamp = txbbs_skipped;
                        packets++;
                        bytes += ring->tx_info[ring_index].nr_bytes;
                } while (ring_index != new_index);
index 7e042869ef0cd2d9c5884147edd7b1c7d582b868..0416c5b3b35cc721c9e312e6b7b2ca0c0917cbf7 100644 (file)
@@ -79,6 +79,7 @@ enum {
                               (1ull << MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE)    | \
                               (1ull << MLX4_EVENT_TYPE_SRQ_LIMIT)          | \
                               (1ull << MLX4_EVENT_TYPE_CMD)                | \
+                              (1ull << MLX4_EVENT_TYPE_OP_REQUIRED)        | \
                               (1ull << MLX4_EVENT_TYPE_COMM_CHANNEL)       | \
                               (1ull << MLX4_EVENT_TYPE_FLR_EVENT)          | \
                               (1ull << MLX4_EVENT_TYPE_FATAL_WARNING))
@@ -629,6 +630,14 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
                        mlx4_warn(dev, "EQ overrun on EQN %d\n", eq->eqn);
                        break;
 
+               case MLX4_EVENT_TYPE_OP_REQUIRED:
+                       atomic_inc(&priv->opreq_count);
+                       /* FW commands can't be executed from interrupt context
+                        * working in deferred task
+                        */
+                       queue_work(mlx4_wq, &priv->opreq_task);
+                       break;
+
                case MLX4_EVENT_TYPE_COMM_CHANNEL:
                        if (!mlx4_is_master(dev)) {
                                mlx4_warn(dev, "Received comm channel event "
index 8873d6802c80dd8c5359f7c1e19834236f2c9ae6..0d63daa2f422e082d85fd627a892c9fb5f5c1945 100644 (file)
@@ -845,16 +845,7 @@ int mlx4_QUERY_PORT_wrapper(struct mlx4_dev *dev, int slave,
                           MLX4_CMD_NATIVE);
 
        if (!err && dev->caps.function != slave) {
-               /* if config MAC in DB use it */
-               if (priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.mac)
-                       def_mac = priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.mac;
-               else {
-                       /* set slave default_mac address */
-                       MLX4_GET(def_mac, outbox->buf, QUERY_PORT_MAC_OFFSET);
-                       def_mac += slave << 8;
-                       priv->mfunc.master.vf_admin[slave].vport[vhcr->in_modifier].mac = def_mac;
-               }
-
+               def_mac = priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.mac;
                MLX4_PUT(outbox->buf, def_mac, QUERY_PORT_MAC_OFFSET);
 
                /* get port type - currently only eth is enabled */
@@ -1705,3 +1696,107 @@ int mlx4_wol_write(struct mlx4_dev *dev, u64 config, int port)
                        MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
 }
 EXPORT_SYMBOL_GPL(mlx4_wol_write);
+
+enum {
+       ADD_TO_MCG = 0x26,
+};
+
+
+void mlx4_opreq_action(struct work_struct *work)
+{
+       struct mlx4_priv *priv = container_of(work, struct mlx4_priv,
+                                             opreq_task);
+       struct mlx4_dev *dev = &priv->dev;
+       int num_tasks = atomic_read(&priv->opreq_count);
+       struct mlx4_cmd_mailbox *mailbox;
+       struct mlx4_mgm *mgm;
+       u32 *outbox;
+       u32 modifier;
+       u16 token;
+       u16 type_m;
+       u16 type;
+       int err;
+       u32 num_qps;
+       struct mlx4_qp qp;
+       int i;
+       u8 rem_mcg;
+       u8 prot;
+
+#define GET_OP_REQ_MODIFIER_OFFSET     0x08
+#define GET_OP_REQ_TOKEN_OFFSET                0x14
+#define GET_OP_REQ_TYPE_OFFSET         0x1a
+#define GET_OP_REQ_DATA_OFFSET         0x20
+
+       mailbox = mlx4_alloc_cmd_mailbox(dev);
+       if (IS_ERR(mailbox)) {
+               mlx4_err(dev, "Failed to allocate mailbox for GET_OP_REQ\n");
+               return;
+       }
+       outbox = mailbox->buf;
+
+       while (num_tasks) {
+               err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0,
+                                  MLX4_CMD_GET_OP_REQ, MLX4_CMD_TIME_CLASS_A,
+                                  MLX4_CMD_NATIVE);
+               if (err) {
+                       mlx4_err(dev, "Failed to retreive required operation: %d\n",
+                                err);
+                       return;
+               }
+               MLX4_GET(modifier, outbox, GET_OP_REQ_MODIFIER_OFFSET);
+               MLX4_GET(token, outbox, GET_OP_REQ_TOKEN_OFFSET);
+               MLX4_GET(type, outbox, GET_OP_REQ_TYPE_OFFSET);
+               type_m = type >> 12;
+               type &= 0xfff;
+
+               switch (type) {
+               case ADD_TO_MCG:
+                       if (dev->caps.steering_mode ==
+                           MLX4_STEERING_MODE_DEVICE_MANAGED) {
+                               mlx4_warn(dev, "ADD MCG operation is not supported in DEVICE_MANAGED steering mode\n");
+                               err = EPERM;
+                               break;
+                       }
+                       mgm = (struct mlx4_mgm *)((u8 *)(outbox) +
+                                                 GET_OP_REQ_DATA_OFFSET);
+                       num_qps = be32_to_cpu(mgm->members_count) &
+                                 MGM_QPN_MASK;
+                       rem_mcg = ((u8 *)(&mgm->members_count))[0] & 1;
+                       prot = ((u8 *)(&mgm->members_count))[0] >> 6;
+
+                       for (i = 0; i < num_qps; i++) {
+                               qp.qpn = be32_to_cpu(mgm->qp[i]);
+                               if (rem_mcg)
+                                       err = mlx4_multicast_detach(dev, &qp,
+                                                                   mgm->gid,
+                                                                   prot, 0);
+                               else
+                                       err = mlx4_multicast_attach(dev, &qp,
+                                                                   mgm->gid,
+                                                                   mgm->gid[5]
+                                                                   , 0, prot,
+                                                                   NULL);
+                               if (err)
+                                       break;
+                       }
+                       break;
+               default:
+                       mlx4_warn(dev, "Bad type for required operation\n");
+                       err = EINVAL;
+                       break;
+               }
+               err = mlx4_cmd(dev, 0, ((u32) err | cpu_to_be32(token) << 16),
+                              1, MLX4_CMD_GET_OP_REQ, MLX4_CMD_TIME_CLASS_A,
+                              MLX4_CMD_NATIVE);
+               if (err) {
+                       mlx4_err(dev, "Failed to acknowledge required request: %d\n",
+                                err);
+                       goto out;
+               }
+               memset(outbox, 0, 0xffc);
+               num_tasks = atomic_dec_return(&priv->opreq_count);
+       }
+
+out:
+       mlx4_free_cmd_mailbox(dev, mailbox);
+}
index fdf41665a05931d3574a2dd7f3d53467d0e4d3f6..a0a368b7c93996724f49f8c5ece01ff3d5a86bc3 100644 (file)
@@ -220,5 +220,6 @@ int mlx4_MAP_ICM_AUX(struct mlx4_dev *dev, struct mlx4_icm *icm);
 int mlx4_UNMAP_ICM_AUX(struct mlx4_dev *dev);
 int mlx4_NOP(struct mlx4_dev *dev);
 int mlx4_MOD_STAT_CFG(struct mlx4_dev *dev, struct mlx4_mod_stat_cfg *cfg);
+void mlx4_opreq_action(struct work_struct *work);
 
 #endif /* MLX4_FW_H */
index e85af922dcdcc237ea5e7c7f227088fe77e90802..60c9f4f103fce1a2c7d815ccc303b7b94805068c 100644 (file)
@@ -371,7 +371,7 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
 
        dev->caps.sqp_demux = (mlx4_is_master(dev)) ? MLX4_MAX_NUM_SLAVES : 0;
 
-       if (!enable_64b_cqe_eqe) {
+       if (!enable_64b_cqe_eqe && !mlx4_is_slave(dev)) {
                if (dev_cap->flags &
                    (MLX4_DEV_CAP_FLAG_64B_CQE | MLX4_DEV_CAP_FLAG_64B_EQE)) {
                        mlx4_warn(dev, "64B EQEs/CQEs supported by the device but not enabled\n");
@@ -1692,11 +1692,19 @@ static int mlx4_setup_hca(struct mlx4_dev *dev)
                goto err_xrcd_table_free;
        }
 
+       if (!mlx4_is_slave(dev)) {
+               err = mlx4_init_mcg_table(dev);
+               if (err) {
+                       mlx4_err(dev, "Failed to initialize multicast group table, aborting.\n");
+                       goto err_mr_table_free;
+               }
+       }
+
        err = mlx4_init_eq_table(dev);
        if (err) {
                mlx4_err(dev, "Failed to initialize "
                         "event queue table, aborting.\n");
-               goto err_mr_table_free;
+               goto err_mcg_table_free;
        }
 
        err = mlx4_cmd_use_events(dev);
@@ -1746,19 +1754,10 @@ static int mlx4_setup_hca(struct mlx4_dev *dev)
                goto err_srq_table_free;
        }
 
-       if (!mlx4_is_slave(dev)) {
-               err = mlx4_init_mcg_table(dev);
-               if (err) {
-                       mlx4_err(dev, "Failed to initialize "
-                                "multicast group table, aborting.\n");
-                       goto err_qp_table_free;
-               }
-       }
-
        err = mlx4_init_counters_table(dev);
        if (err && err != -ENOENT) {
                mlx4_err(dev, "Failed to initialize counters table, aborting.\n");
-               goto err_mcg_table_free;
+               goto err_qp_table_free;
        }
 
        if (!mlx4_is_slave(dev)) {
@@ -1803,9 +1802,6 @@ static int mlx4_setup_hca(struct mlx4_dev *dev)
 err_counters_table_free:
        mlx4_cleanup_counters_table(dev);
 
-err_mcg_table_free:
-       mlx4_cleanup_mcg_table(dev);
-
 err_qp_table_free:
        mlx4_cleanup_qp_table(dev);
 
@@ -1821,6 +1817,10 @@ err_cmd_poll:
 err_eq_table_free:
        mlx4_cleanup_eq_table(dev);
 
+err_mcg_table_free:
+       if (!mlx4_is_slave(dev))
+               mlx4_cleanup_mcg_table(dev);
+
 err_mr_table_free:
        mlx4_cleanup_mr_table(dev);
 
@@ -2197,6 +2197,9 @@ static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data)
                        }
                }
 
+               atomic_set(&priv->opreq_count, 0);
+               INIT_WORK(&priv->opreq_task, mlx4_opreq_action);
+
                /*
                 * Now reset the HCA before we touch the PCI capabilities or
                 * attempt a firmware command, since a boot ROM may have left
@@ -2315,12 +2318,12 @@ err_port:
                mlx4_cleanup_port_info(&priv->port[port]);
 
        mlx4_cleanup_counters_table(dev);
-       mlx4_cleanup_mcg_table(dev);
        mlx4_cleanup_qp_table(dev);
        mlx4_cleanup_srq_table(dev);
        mlx4_cleanup_cq_table(dev);
        mlx4_cmd_use_polling(dev);
        mlx4_cleanup_eq_table(dev);
+       mlx4_cleanup_mcg_table(dev);
        mlx4_cleanup_mr_table(dev);
        mlx4_cleanup_xrcd_table(dev);
        mlx4_cleanup_pd_table(dev);
@@ -2403,12 +2406,12 @@ static void mlx4_remove_one(struct pci_dev *pdev)
                                                   RES_TR_FREE_SLAVES_ONLY);
 
                mlx4_cleanup_counters_table(dev);
-               mlx4_cleanup_mcg_table(dev);
                mlx4_cleanup_qp_table(dev);
                mlx4_cleanup_srq_table(dev);
                mlx4_cleanup_cq_table(dev);
                mlx4_cmd_use_polling(dev);
                mlx4_cleanup_eq_table(dev);
+               mlx4_cleanup_mcg_table(dev);
                mlx4_cleanup_mr_table(dev);
                mlx4_cleanup_xrcd_table(dev);
                mlx4_cleanup_pd_table(dev);
index f3e804f2a35f0bd2a9be0e32b7b577bed5518cfa..55f6245efb6cd250f2efda4e6941bdb81b1fd9f3 100644 (file)
 
 #include "mlx4.h"
 
-#define MGM_QPN_MASK       0x00FFFFFF
-#define MGM_BLCK_LB_BIT    30
-
 static const u8 zero_gid[16];  /* automatically initialized to 0 */
 
-struct mlx4_mgm {
-       __be32                  next_gid_index;
-       __be32                  members_count;
-       u32                     reserved[2];
-       u8                      gid[16];
-       __be32                  qp[MLX4_MAX_QP_PER_MGM];
-};
-
 int mlx4_get_mgm_entry_size(struct mlx4_dev *dev)
 {
        return 1 << dev->oper_log_mgm_entry_size;
index 17d9277e33ef978f89828a83e44642986383e06a..348bb8c7d9a70bc58d1c51c4e7aca6ec495dcb8f 100644 (file)
@@ -554,6 +554,17 @@ struct mlx4_mfunc {
        struct mlx4_mfunc_master_ctx    master;
 };
 
+#define MGM_QPN_MASK       0x00FFFFFF
+#define MGM_BLCK_LB_BIT    30
+
+struct mlx4_mgm {
+       __be32                  next_gid_index;
+       __be32                  members_count;
+       u32                     reserved[2];
+       u8                      gid[16];
+       __be32                  qp[MLX4_MAX_QP_PER_MGM];
+};
+
 struct mlx4_cmd {
        struct pci_pool        *pool;
        void __iomem           *hcr;
@@ -802,6 +813,8 @@ struct mlx4_priv {
        u8 virt2phys_pkey[MLX4_MFUNC_MAX][MLX4_MAX_PORTS][MLX4_MAX_PORT_PKEYS];
        __be64                  slave_node_guids[MLX4_MFUNC_MAX];
 
+       atomic_t                opreq_count;
+       struct work_struct      opreq_task;
 };
 
 static inline struct mlx4_priv *mlx4_priv(struct mlx4_dev *dev)
index 35fb60e2320c2a896e8b241c2c9dbbe575a2dd02..5e0aa569306aab2f6c8185cd1574cdd4abeb4aab 100644 (file)
@@ -292,7 +292,7 @@ struct mlx4_en_rx_ring {
        void *rx_info;
        unsigned long bytes;
        unsigned long packets;
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        unsigned long yields;
        unsigned long misses;
        unsigned long cleaned;
@@ -318,7 +318,7 @@ struct mlx4_en_cq {
        struct mlx4_cqe *buf;
 #define MLX4_EN_OPCODE_ERROR   0x1e
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        unsigned int state;
 #define MLX4_EN_CQ_STATE_IDLE        0
 #define MLX4_EN_CQ_STATE_NAPI     1    /* NAPI owns this CQ */
@@ -329,7 +329,7 @@ struct mlx4_en_cq {
 #define CQ_YIELD (MLX4_EN_CQ_STATE_NAPI_YIELD | MLX4_EN_CQ_STATE_POLL_YIELD)
 #define CQ_USER_PEND (MLX4_EN_CQ_STATE_POLL | MLX4_EN_CQ_STATE_POLL_YIELD)
        spinlock_t poll_lock; /* protects from LLS/napi conflicts */
-#endif  /* CONFIG_NET_LL_RX_POLL */
+#endif  /* CONFIG_NET_RX_BUSY_POLL */
 };
 
 struct mlx4_en_port_profile {
@@ -580,7 +580,7 @@ struct mlx4_mac_entry {
        struct rcu_head rcu;
 };
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
 static inline void mlx4_en_cq_init_lock(struct mlx4_en_cq *cq)
 {
        spin_lock_init(&cq->poll_lock);
@@ -687,7 +687,7 @@ static inline bool mlx4_en_cq_ll_polling(struct mlx4_en_cq *cq)
 {
        return false;
 }
-#endif /* CONFIG_NET_LL_RX_POLL */
+#endif /* CONFIG_NET_RX_BUSY_POLL */
 
 #define MLX4_EN_WOL_DO_MODIFY (1ULL << 63)
 
index 205753a04cfcb22e8904dbe2e3e203d82df32552..c571de85d0f995bb2c302210cfbd979b9e1bec9e 100644 (file)
@@ -46,7 +46,7 @@
 #include "mlx5_core.h"
 
 enum {
-       CMD_IF_REV = 3,
+       CMD_IF_REV = 4,
 };
 
 enum {
@@ -282,6 +282,12 @@ const char *mlx5_command_str(int command)
        case MLX5_CMD_OP_TEARDOWN_HCA:
                return "TEARDOWN_HCA";
 
+       case MLX5_CMD_OP_ENABLE_HCA:
+               return "MLX5_CMD_OP_ENABLE_HCA";
+
+       case MLX5_CMD_OP_DISABLE_HCA:
+               return "MLX5_CMD_OP_DISABLE_HCA";
+
        case MLX5_CMD_OP_QUERY_PAGES:
                return "QUERY_PAGES";
 
@@ -1113,7 +1119,13 @@ void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, unsigned long vector)
 
        for (i = 0; i < (1 << cmd->log_sz); i++) {
                if (test_bit(i, &vector)) {
+                       struct semaphore *sem;
+
                        ent = cmd->ent_arr[i];
+                       if (ent->page_queue)
+                               sem = &cmd->pages_sem;
+                       else
+                               sem = &cmd->sem;
                        ktime_get_ts(&ent->ts2);
                        memcpy(ent->out->first.data, ent->lay->out, sizeof(ent->lay->out));
                        dump_command(dev, ent, 0);
@@ -1136,10 +1148,7 @@ void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, unsigned long vector)
                        } else {
                                complete(&ent->done);
                        }
-                       if (ent->page_queue)
-                               up(&cmd->pages_sem);
-                       else
-                               up(&cmd->sem);
+                       up(sem);
                }
        }
 }
index 12242de2b0e3ec7950a01f966def239e4b1ce74f..b47739b0b5f6dfb34139ad74e02ac10db1d4fbbd 100644 (file)
@@ -249,6 +249,44 @@ static int set_hca_ctrl(struct mlx5_core_dev *dev)
        return err;
 }
 
+static int mlx5_core_enable_hca(struct mlx5_core_dev *dev)
+{
+       int err;
+       struct mlx5_enable_hca_mbox_in in;
+       struct mlx5_enable_hca_mbox_out out;
+
+       memset(&in, 0, sizeof(in));
+       memset(&out, 0, sizeof(out));
+       in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_ENABLE_HCA);
+       err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+       if (err)
+               return err;
+
+       if (out.hdr.status)
+               return mlx5_cmd_status_to_err(&out.hdr);
+
+       return 0;
+}
+
+static int mlx5_core_disable_hca(struct mlx5_core_dev *dev)
+{
+       int err;
+       struct mlx5_disable_hca_mbox_in in;
+       struct mlx5_disable_hca_mbox_out out;
+
+       memset(&in, 0, sizeof(in));
+       memset(&out, 0, sizeof(out));
+       in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DISABLE_HCA);
+       err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+       if (err)
+               return err;
+
+       if (out.hdr.status)
+               return mlx5_cmd_status_to_err(&out.hdr);
+
+       return 0;
+}
+
 int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev)
 {
        struct mlx5_priv *priv = &dev->priv;
@@ -304,28 +342,41 @@ int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev)
        }
 
        mlx5_pagealloc_init(dev);
+
+       err = mlx5_core_enable_hca(dev);
+       if (err) {
+               dev_err(&pdev->dev, "enable hca failed\n");
+               goto err_pagealloc_cleanup;
+       }
+
+       err = mlx5_satisfy_startup_pages(dev, 1);
+       if (err) {
+               dev_err(&pdev->dev, "failed to allocate boot pages\n");
+               goto err_disable_hca;
+       }
+
        err = set_hca_ctrl(dev);
        if (err) {
                dev_err(&pdev->dev, "set_hca_ctrl failed\n");
-               goto err_pagealloc_cleanup;
+               goto reclaim_boot_pages;
        }
 
        err = handle_hca_cap(dev);
        if (err) {
                dev_err(&pdev->dev, "handle_hca_cap failed\n");
-               goto err_pagealloc_cleanup;
+               goto reclaim_boot_pages;
        }
 
-       err = mlx5_satisfy_startup_pages(dev);
+       err = mlx5_satisfy_startup_pages(dev, 0);
        if (err) {
-               dev_err(&pdev->dev, "failed to allocate startup pages\n");
-               goto err_pagealloc_cleanup;
+               dev_err(&pdev->dev, "failed to allocate init pages\n");
+               goto reclaim_boot_pages;
        }
 
        err = mlx5_pagealloc_start(dev);
        if (err) {
                dev_err(&pdev->dev, "mlx5_pagealloc_start failed\n");
-               goto err_reclaim_pages;
+               goto reclaim_boot_pages;
        }
 
        err = mlx5_cmd_init_hca(dev);
@@ -396,9 +447,12 @@ err_stop_poll:
 err_pagealloc_stop:
        mlx5_pagealloc_stop(dev);
 
-err_reclaim_pages:
+reclaim_boot_pages:
        mlx5_reclaim_startup_pages(dev);
 
+err_disable_hca:
+       mlx5_core_disable_hca(dev);
+
 err_pagealloc_cleanup:
        mlx5_pagealloc_cleanup(dev);
        mlx5_cmd_cleanup(dev);
@@ -434,6 +488,7 @@ void mlx5_dev_cleanup(struct mlx5_core_dev *dev)
        mlx5_cmd_teardown_hca(dev);
        mlx5_pagealloc_stop(dev);
        mlx5_reclaim_startup_pages(dev);
+       mlx5_core_disable_hca(dev);
        mlx5_pagealloc_cleanup(dev);
        mlx5_cmd_cleanup(dev);
        iounmap(dev->iseg);
index f0bf46339b2805d745c89eca8a413a5cd002efb8..4a3e137931a38b898468061ae8334016e4e2f23e 100644 (file)
@@ -64,7 +64,7 @@ struct mlx5_query_pages_inbox {
 
 struct mlx5_query_pages_outbox {
        struct mlx5_outbox_hdr  hdr;
-       u8                      reserved[2];
+       __be16                  num_boot_pages;
        __be16                  func_id;
        __be16                  init_pages;
        __be16                  num_pages;
@@ -146,7 +146,7 @@ static struct page *remove_page(struct mlx5_core_dev *dev, u64 addr)
 }
 
 static int mlx5_cmd_query_pages(struct mlx5_core_dev *dev, u16 *func_id,
-                               s16 *pages, s16 *init_pages)
+                               s16 *pages, s16 *init_pages, u16 *boot_pages)
 {
        struct mlx5_query_pages_inbox   in;
        struct mlx5_query_pages_outbox  out;
@@ -164,8 +164,13 @@ static int mlx5_cmd_query_pages(struct mlx5_core_dev *dev, u16 *func_id,
 
        if (pages)
                *pages = be16_to_cpu(out.num_pages);
+
        if (init_pages)
                *init_pages = be16_to_cpu(out.init_pages);
+
+       if (boot_pages)
+               *boot_pages = be16_to_cpu(out.num_boot_pages);
+
        *func_id = be16_to_cpu(out.func_id);
 
        return err;
@@ -357,19 +362,22 @@ void mlx5_core_req_pages_handler(struct mlx5_core_dev *dev, u16 func_id,
        queue_work(dev->priv.pg_wq, &req->work);
 }
 
-int mlx5_satisfy_startup_pages(struct mlx5_core_dev *dev)
+int mlx5_satisfy_startup_pages(struct mlx5_core_dev *dev, int boot)
 {
+       u16 uninitialized_var(boot_pages);
        s16 uninitialized_var(init_pages);
        u16 uninitialized_var(func_id);
        int err;
 
-       err = mlx5_cmd_query_pages(dev, &func_id, NULL, &init_pages);
+       err = mlx5_cmd_query_pages(dev, &func_id, NULL, &init_pages,
+                                  &boot_pages);
        if (err)
                return err;
 
-       mlx5_core_dbg(dev, "requested %d init pages for func_id 0x%x\n", init_pages, func_id);
 
-       return give_pages(dev, func_id, init_pages, 0);
+       mlx5_core_dbg(dev, "requested %d init pages and %d boot pages for func_id 0x%x\n",
+                     init_pages, boot_pages, func_id);
+       return give_pages(dev, func_id, boot ? boot_pages : init_pages, 0);
 }
 
 static int optimal_reclaimed_pages(void)
index 71d4a39372009847b7d03b11c58e8ccf695e61b3..68f5d9c77c7b13b9038cf5bc4e920e09ac3c33a9 100644 (file)
@@ -164,6 +164,7 @@ int mlx5_alloc_uuars(struct mlx5_core_dev *dev, struct mlx5_uuar_info *uuari)
                uuari->uars[i].map = ioremap(addr, PAGE_SIZE);
                if (!uuari->uars[i].map) {
                        mlx5_cmd_free_uar(dev, uuari->uars[i].index);
+                       err = -ENOMEM;
                        goto out_count;
                }
                mlx5_core_dbg(dev, "allocated uar index 0x%x, mmaped at %p\n",
index cb22341a14a8c03fd7627c0d2d2a31f9f68ce126..a588ffde970041def37cae92b215011d88b6eea6 100644 (file)
@@ -4,7 +4,7 @@
 
 config PCH_GBE
        tristate "OKI SEMICONDUCTOR IOH(ML7223/ML7831) GbE"
-       depends on PCI
+       depends on PCI && (X86 || COMPILE_TEST)
        select MII
        select PTP_1588_CLOCK_PCH
        ---help---
index 7779036690cca239265ddbe27eeac8076a546933..6797b1075874ae26cca6756bf450559ed7c7e6be 100644 (file)
@@ -581,6 +581,19 @@ struct pch_gbe_hw_stats {
        u32 intr_tcpip_err_count;
 };
 
+/**
+ * struct pch_gbe_privdata - PCI Device ID driver data
+ * @phy_tx_clk_delay:          Bool, configure the PHY TX delay in software
+ * @phy_disable_hibernate:     Bool, disable PHY hibernation
+ * @platform_init:             Platform initialization callback, called from
+ *                             probe, prior to PHY initialization.
+ */
+struct pch_gbe_privdata {
+       bool phy_tx_clk_delay;
+       bool phy_disable_hibernate;
+       int (*platform_init)(struct pci_dev *pdev);
+};
+
 /**
  * struct pch_gbe_adapter - board specific private data structure
  * @stats_lock:        Spinlock structure for status
@@ -604,6 +617,7 @@ struct pch_gbe_hw_stats {
  * @rx_buffer_len:     Receive buffer length
  * @tx_queue_len:      Transmit queue length
  * @have_msi:          PCI MSI mode flag
+ * @pch_gbe_privdata:  PCI Device ID driver_data
  */
 
 struct pch_gbe_adapter {
@@ -631,6 +645,7 @@ struct pch_gbe_adapter {
        int hwts_tx_en;
        int hwts_rx_en;
        struct pci_dev *ptp_pdev;
+       struct pch_gbe_privdata *pdata;
 };
 
 #define pch_gbe_hw_to_adapter(hw)      container_of(hw, struct pch_gbe_adapter, hw)
index ab1039a95bf9e3ed883862515bc59a6f921df946..e19f1be60d5e40fc8428a766825f6815f9ce7e29 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/module.h>
 #include <linux/net_tstamp.h>
 #include <linux/ptp_classify.h>
+#include <linux/gpio.h>
 
 #define DRV_VERSION     "1.01"
 const char pch_driver_version[] = DRV_VERSION;
@@ -111,6 +112,8 @@ const char pch_driver_version[] = DRV_VERSION;
 #define PTP_L4_MULTICAST_SA "01:00:5e:00:01:81"
 #define PTP_L2_MULTICAST_SA "01:1b:19:00:00:00"
 
+#define MINNOW_PHY_RESET_GPIO          13
+
 static unsigned int copybreak __read_mostly = PCH_GBE_COPYBREAK_DEFAULT;
 
 static int pch_gbe_mdio_read(struct net_device *netdev, int addr, int reg);
@@ -682,7 +685,7 @@ static int pch_gbe_init_phy(struct pch_gbe_adapter *adapter)
        }
        adapter->hw.phy.addr = adapter->mii.phy_id;
        netdev_dbg(netdev, "phy_addr = %d\n", adapter->mii.phy_id);
-       if (addr == 32)
+       if (addr == PCH_GBE_PHY_REGS_LEN)
                return -EAGAIN;
        /* Selected the phy and isolate the rest */
        for (addr = 0; addr < PCH_GBE_PHY_REGS_LEN; addr++) {
@@ -2635,6 +2638,9 @@ static int pch_gbe_probe(struct pci_dev *pdev,
        adapter->pdev = pdev;
        adapter->hw.back = adapter;
        adapter->hw.reg = pcim_iomap_table(pdev)[PCH_GBE_PCI_BAR];
+       adapter->pdata = (struct pch_gbe_privdata *)pci_id->driver_data;
+       if (adapter->pdata && adapter->pdata->platform_init)
+               adapter->pdata->platform_init(pdev);
 
        adapter->ptp_pdev = pci_get_bus_and_slot(adapter->pdev->bus->number,
                                               PCI_DEVFN(12, 4));
@@ -2710,6 +2716,10 @@ static int pch_gbe_probe(struct pci_dev *pdev,
 
        dev_dbg(&pdev->dev, "PCH Network Connection\n");
 
+       /* Disable hibernation on certain platforms */
+       if (adapter->pdata && adapter->pdata->phy_disable_hibernate)
+               pch_gbe_phy_disable_hibernate(&adapter->hw);
+
        device_set_wakeup_enable(&pdev->dev, 1);
        return 0;
 
@@ -2720,7 +2730,46 @@ err_free_netdev:
        return ret;
 }
 
+/* The AR803X PHY on the MinnowBoard requires a physical pin to be toggled to
+ * ensure it is awake for probe and init. Request the line and reset the PHY.
+ */
+static int pch_gbe_minnow_platform_init(struct pci_dev *pdev)
+{
+       unsigned long flags = GPIOF_DIR_OUT | GPIOF_INIT_HIGH | GPIOF_EXPORT;
+       unsigned gpio = MINNOW_PHY_RESET_GPIO;
+       int ret;
+
+       ret = devm_gpio_request_one(&pdev->dev, gpio, flags,
+                                   "minnow_phy_reset");
+       if (ret) {
+               dev_err(&pdev->dev,
+                       "ERR: Can't request PHY reset GPIO line '%d'\n", gpio);
+               return ret;
+       }
+
+       gpio_set_value(gpio, 0);
+       usleep_range(1250, 1500);
+       gpio_set_value(gpio, 1);
+       usleep_range(1250, 1500);
+
+       return ret;
+}
+
+static struct pch_gbe_privdata pch_gbe_minnow_privdata = {
+       .phy_tx_clk_delay = true,
+       .phy_disable_hibernate = true,
+       .platform_init = pch_gbe_minnow_platform_init,
+};
+
 static DEFINE_PCI_DEVICE_TABLE(pch_gbe_pcidev_id) = {
+       {.vendor = PCI_VENDOR_ID_INTEL,
+        .device = PCI_DEVICE_ID_INTEL_IOH1_GBE,
+        .subvendor = PCI_VENDOR_ID_CIRCUITCO,
+        .subdevice = PCI_SUBSYSTEM_ID_CIRCUITCO_MINNOWBOARD,
+        .class = (PCI_CLASS_NETWORK_ETHERNET << 8),
+        .class_mask = (0xFFFF00),
+        .driver_data = (kernel_ulong_t)&pch_gbe_minnow_privdata
+        },
        {.vendor = PCI_VENDOR_ID_INTEL,
         .device = PCI_DEVICE_ID_INTEL_IOH1_GBE,
         .subvendor = PCI_ANY_ID,
index da079073a6c63e18528f51e359793b43bd001af2..8b7ff75fc8e0d5201c94a014c64781b632a896cc 100644 (file)
 #define MII_SR_100X_FD_CAPS      0x4000        /* 100X  Full Duplex Capable */
 #define MII_SR_100T4_CAPS        0x8000        /* 100T4 Capable */
 
+/* AR8031 PHY Debug Registers */
+#define PHY_AR803X_ID           0x00001374
+#define PHY_AR8031_DBG_OFF      0x1D
+#define PHY_AR8031_DBG_DAT      0x1E
+#define PHY_AR8031_SERDES       0x05
+#define PHY_AR8031_HIBERNATE    0x0B
+#define PHY_AR8031_SERDES_TX_CLK_DLY   0x0100 /* TX clock delay of 2.0ns */
+#define PHY_AR8031_PS_HIB_EN           0x8000 /* Hibernate enable */
+
 /* Phy Id Register (word 2) */
 #define PHY_REVISION_MASK        0x000F
 
@@ -248,6 +257,51 @@ void pch_gbe_phy_set_rgmii(struct pch_gbe_hw *hw)
        pch_gbe_phy_sw_reset(hw);
 }
 
+/**
+ * pch_gbe_phy_tx_clk_delay - Setup TX clock delay via the PHY
+ * @hw:                    Pointer to the HW structure
+ * Returns
+ *     0:              Successful.
+ *     -EINVAL:        Invalid argument.
+ */
+static int pch_gbe_phy_tx_clk_delay(struct pch_gbe_hw *hw)
+{
+       /* The RGMII interface requires a ~2ns TX clock delay. This is typically
+        * done in layout with a longer trace or via PHY strapping, but can also
+        * be done via PHY configuration registers.
+        */
+       struct pch_gbe_adapter *adapter = pch_gbe_hw_to_adapter(hw);
+       u16 mii_reg;
+       int ret = 0;
+
+       switch (hw->phy.id) {
+       case PHY_AR803X_ID:
+               netdev_dbg(adapter->netdev,
+                          "Configuring AR803X PHY for 2ns TX clock delay\n");
+               pch_gbe_phy_read_reg_miic(hw, PHY_AR8031_DBG_OFF, &mii_reg);
+               ret = pch_gbe_phy_write_reg_miic(hw, PHY_AR8031_DBG_OFF,
+                                                PHY_AR8031_SERDES);
+               if (ret)
+                       break;
+
+               pch_gbe_phy_read_reg_miic(hw, PHY_AR8031_DBG_DAT, &mii_reg);
+               mii_reg |= PHY_AR8031_SERDES_TX_CLK_DLY;
+               ret = pch_gbe_phy_write_reg_miic(hw, PHY_AR8031_DBG_DAT,
+                                                mii_reg);
+               break;
+       default:
+               netdev_err(adapter->netdev,
+                          "Unknown PHY (%x), could not set TX clock delay\n",
+                          hw->phy.id);
+               return -EINVAL;
+       }
+
+       if (ret)
+               netdev_err(adapter->netdev,
+                          "Could not configure tx clock delay for PHY\n");
+       return ret;
+}
+
 /**
  * pch_gbe_phy_init_setting - PHY initial setting
  * @hw:                    Pointer to the HW structure
@@ -277,4 +331,48 @@ void pch_gbe_phy_init_setting(struct pch_gbe_hw *hw)
        pch_gbe_phy_read_reg_miic(hw, PHY_PHYSP_CONTROL, &mii_reg);
        mii_reg |= PHYSP_CTRL_ASSERT_CRS_TX;
        pch_gbe_phy_write_reg_miic(hw, PHY_PHYSP_CONTROL, mii_reg);
+
+       /* Setup a TX clock delay on certain platforms */
+       if (adapter->pdata && adapter->pdata->phy_tx_clk_delay)
+               pch_gbe_phy_tx_clk_delay(hw);
+}
+
+/**
+ * pch_gbe_phy_disable_hibernate - Disable the PHY low power state
+ * @hw:                    Pointer to the HW structure
+ * Returns
+ *     0:              Successful.
+ *     -EINVAL:        Invalid argument.
+ */
+int pch_gbe_phy_disable_hibernate(struct pch_gbe_hw *hw)
+{
+       struct pch_gbe_adapter *adapter = pch_gbe_hw_to_adapter(hw);
+       u16 mii_reg;
+       int ret = 0;
+
+       switch (hw->phy.id) {
+       case PHY_AR803X_ID:
+               netdev_dbg(adapter->netdev,
+                          "Disabling hibernation for AR803X PHY\n");
+               ret = pch_gbe_phy_write_reg_miic(hw, PHY_AR8031_DBG_OFF,
+                                                PHY_AR8031_HIBERNATE);
+               if (ret)
+                       break;
+
+               pch_gbe_phy_read_reg_miic(hw, PHY_AR8031_DBG_DAT, &mii_reg);
+               mii_reg &= ~PHY_AR8031_PS_HIB_EN;
+               ret = pch_gbe_phy_write_reg_miic(hw, PHY_AR8031_DBG_DAT,
+                                                mii_reg);
+               break;
+       default:
+               netdev_err(adapter->netdev,
+                          "Unknown PHY (%x), could not disable hibernation\n",
+                          hw->phy.id);
+               return -EINVAL;
+       }
+
+       if (ret)
+               netdev_err(adapter->netdev,
+                          "Could not disable PHY hibernation\n");
+       return ret;
 }
index 03264dc7b5ec8a294da8c4e662f348ca74230d32..0cbe69206e04db47eb77956d7466937e6c357144 100644 (file)
@@ -33,5 +33,6 @@ void pch_gbe_phy_power_up(struct pch_gbe_hw *hw);
 void pch_gbe_phy_power_down(struct pch_gbe_hw *hw);
 void pch_gbe_phy_set_rgmii(struct pch_gbe_hw *hw);
 void pch_gbe_phy_init_setting(struct pch_gbe_hw *hw);
+int pch_gbe_phy_disable_hibernate(struct pch_gbe_hw *hw);
 
 #endif /* _PCH_GBE_PHY_H_ */
index b00cf5665eabee735b1e218e6aeda7111380fe69..f4bb8f5d74538a2698ca016801920b0bf1745e19 100644 (file)
@@ -1869,7 +1869,8 @@ static inline void qlcnic_free_mac_list(struct qlcnic_adapter *adapter)
 
 static inline void qlcnic_set_mac_filter_count(struct qlcnic_adapter *adapter)
 {
-       adapter->ahw->hw_ops->set_mac_filter_count(adapter);
+       if (adapter->ahw->hw_ops->set_mac_filter_count)
+               adapter->ahw->hw_ops->set_mac_filter_count(adapter);
 }
 
 static inline void qlcnic_dev_request_reset(struct qlcnic_adapter *adapter,
index 0913c623a67efd238e7d989d50cb2b1c7238cefa..bc483e1881a35998712628b625bda0cf2e4da768 100644 (file)
@@ -3014,8 +3014,8 @@ int qlcnic_83xx_get_settings(struct qlcnic_adapter *adapter,
        }
 
        if (ahw->port_type == QLCNIC_XGBE) {
-               ecmd->supported = SUPPORTED_1000baseT_Full;
-               ecmd->advertising = ADVERTISED_1000baseT_Full;
+               ecmd->supported = SUPPORTED_10000baseT_Full;
+               ecmd->advertising = ADVERTISED_10000baseT_Full;
        } else {
                ecmd->supported = (SUPPORTED_10baseT_Half |
                                   SUPPORTED_10baseT_Full |
index f41dfab1e9a35d3fc4b3d72c820b2d5db84f59e0..51ab4b56fc918bdc109c896610503c5a86647723 100644 (file)
@@ -2123,6 +2123,8 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac)
        set_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status);
        qlcnic_83xx_clear_function_resources(adapter);
 
+       INIT_DELAYED_WORK(&adapter->idc_aen_work, qlcnic_83xx_idc_aen_work);
+
        /* register for NIC IDC AEN Events */
        qlcnic_83xx_register_nic_idc_func(adapter, 1);
 
@@ -2140,8 +2142,6 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac)
        if (adapter->nic_ops->init_driver(adapter))
                return -EIO;
 
-       INIT_DELAYED_WORK(&adapter->idc_aen_work, qlcnic_83xx_idc_aen_work);
-
        /* Periodically monitor device status */
        qlcnic_83xx_idc_poll_dev_state(&adapter->fw_work.work);
 
index 700a46324d09230b8d8ba6e6fc820bc0e56b9526..05a847e599c673fdc16d7492de6c50738596f5f9 100644 (file)
@@ -1540,7 +1540,7 @@ qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
                return 0;
        case QLCNIC_SET_QUIESCENT:
        case QLCNIC_RESET_QUIESCENT:
-               state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+               state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
                if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD))
                        netdev_info(netdev, "Device in FAILED state\n");
                return 0;
index 5b5d2edf125d9f93920b13d83fbfa802c96140fc..4ed7e73d88d36566fdc6e53178ebef8bdb00d17f 100644 (file)
@@ -516,20 +516,18 @@ void __qlcnic_set_multi(struct net_device *netdev, u16 vlan)
        if (netdev->flags & IFF_PROMISC) {
                if (!(adapter->flags & QLCNIC_PROMISC_DISABLED))
                        mode = VPORT_MISS_MODE_ACCEPT_ALL;
-       } else if (netdev->flags & IFF_ALLMULTI) {
-               if (netdev_mc_count(netdev) > ahw->max_mc_count) {
-                       mode = VPORT_MISS_MODE_ACCEPT_MULTI;
-               } else if (!netdev_mc_empty(netdev) &&
-                          !qlcnic_sriov_vf_check(adapter)) {
-                               netdev_for_each_mc_addr(ha, netdev)
-                                       qlcnic_nic_add_mac(adapter, ha->addr,
-                                                          vlan);
-               }
-               if (mode != VPORT_MISS_MODE_ACCEPT_MULTI &&
-                   qlcnic_sriov_vf_check(adapter))
-                       qlcnic_vf_add_mc_list(netdev, vlan);
+       } else if ((netdev->flags & IFF_ALLMULTI) ||
+                  (netdev_mc_count(netdev) > ahw->max_mc_count)) {
+               mode = VPORT_MISS_MODE_ACCEPT_MULTI;
+       } else if (!netdev_mc_empty(netdev) &&
+                  !qlcnic_sriov_vf_check(adapter)) {
+               netdev_for_each_mc_addr(ha, netdev)
+                       qlcnic_nic_add_mac(adapter, ha->addr, vlan);
        }
 
+       if (qlcnic_sriov_vf_check(adapter))
+               qlcnic_vf_add_mc_list(netdev, vlan);
+
        /* configure unicast MAC address, if there is not sufficient space
         * to store all the unicast addresses then enable promiscuous mode
         */
index d28336fc65abe5752f4a295ae54708edf9d3b0ae..a2023090e8666a4227d257e91f5dbf5b51c76f0c 100644 (file)
@@ -142,7 +142,7 @@ void qlcnic_release_tx_buffers(struct qlcnic_adapter *adapter)
                                         buffrag->length, PCI_DMA_TODEVICE);
                        buffrag->dma = 0ULL;
                }
-               for (j = 0; j < cmd_buf->frag_count; j++) {
+               for (j = 1; j < cmd_buf->frag_count; j++) {
                        buffrag++;
                        if (buffrag->dma) {
                                pci_unmap_page(adapter->pdev, buffrag->dma,
index 4528f8ec333bb50d01c116958cb1a86c7392ef7c..cc78d3924c6a3ccec99c42d550d99eb1e64f5aa3 100644 (file)
@@ -1383,6 +1383,8 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter)
        if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) {
                if (qlcnic_82xx_check(adapter))
                        handler = qlcnic_tmp_intr;
+               else
+                       handler = qlcnic_83xx_tmp_intr;
                if (!QLCNIC_IS_MSI_FAMILY(adapter))
                        flags |= IRQF_SHARED;
 
@@ -1531,12 +1533,12 @@ int __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
        if (netdev->features & NETIF_F_LRO)
                qlcnic_config_hw_lro(adapter, QLCNIC_LRO_ENABLED);
 
+       set_bit(__QLCNIC_DEV_UP, &adapter->state);
        qlcnic_napi_enable(adapter);
 
        qlcnic_linkevent_request(adapter, 1);
 
        adapter->ahw->reset_context = 0;
-       set_bit(__QLCNIC_DEV_UP, &adapter->state);
        return 0;
 }
 
index ab8a6744d402f43e794007db16ee218916051675..79e54efe07b921cc2d7e1986c7d45e16ee9e7ecb 100644 (file)
@@ -1084,7 +1084,7 @@ flash_temp:
        tmpl_hdr = ahw->fw_dump.tmpl_hdr;
        tmpl_hdr->drv_cap_mask = QLCNIC_DUMP_MASK_DEF;
 
-       if ((tmpl_hdr->version & 0xffffff) >= 0x20001)
+       if ((tmpl_hdr->version & 0xfffff) >= 0x20001)
                ahw->fw_dump.use_pex_dma = true;
        else
                ahw->fw_dump.use_pex_dma = false;
index 62380ce8990555a2b120fd768cae0f2192508a8e..56e85f98117f3f968606836882c880e2d6df2166 100644 (file)
@@ -762,6 +762,7 @@ static int qlcnic_sriov_alloc_bc_mbx_args(struct qlcnic_cmd_args *mbx, u32 type)
                        memset(mbx->rsp.arg, 0, sizeof(u32) * mbx->rsp.num);
                        mbx->req.arg[0] = (type | (mbx->req.num << 16) |
                                           (3 << 29));
+                       mbx->rsp.arg[0] = (type & 0xffff) | mbx->rsp.num << 16;
                        return 0;
                }
        }
@@ -813,6 +814,7 @@ static int qlcnic_sriov_prepare_bc_hdr(struct qlcnic_bc_trans *trans,
                cmd->req.num = trans->req_pay_size / 4;
                cmd->rsp.num = trans->rsp_pay_size / 4;
                hdr = trans->rsp_hdr;
+               cmd->op_type = trans->req_hdr->op_type;
        }
 
        trans->trans_id = seq;
index ee0c1d307966d842d824c3ed64449690946b7d76..eb49cd65378cdcf5feec210a2812d3d09ef8f0cb 100644 (file)
@@ -635,12 +635,12 @@ static int qlcnic_sriov_pf_channel_cfg_cmd(struct qlcnic_bc_trans *trans,
                                           struct qlcnic_cmd_args *cmd)
 {
        struct qlcnic_vf_info *vf = trans->vf;
-       struct qlcnic_adapter *adapter = vf->adapter;
-       int err;
+       struct qlcnic_vport *vp = vf->vp;
+       struct qlcnic_adapter *adapter;
        u16 func = vf->pci_func;
+       int err;
 
-       cmd->rsp.arg[0] = trans->req_hdr->cmd_op;
-       cmd->rsp.arg[0] |= (1 << 16);
+       adapter = vf->adapter;
 
        if (trans->req_hdr->cmd_op == QLCNIC_BC_CMD_CHANNEL_INIT) {
                err = qlcnic_sriov_pf_config_vport(adapter, 1, func);
@@ -650,6 +650,8 @@ static int qlcnic_sriov_pf_channel_cfg_cmd(struct qlcnic_bc_trans *trans,
                                qlcnic_sriov_pf_config_vport(adapter, 0, func);
                }
        } else {
+               if (vp->vlan_mode == QLC_GUEST_VLAN_MODE)
+                       vp->vlan = 0;
                err = qlcnic_sriov_pf_config_vport(adapter, 0, func);
        }
 
@@ -1183,7 +1185,7 @@ static int qlcnic_sriov_pf_get_acl_cmd(struct qlcnic_bc_trans *trans,
        u8 cmd_op, mode = vp->vlan_mode;
 
        cmd_op = trans->req_hdr->cmd_op;
-       cmd->rsp.arg[0] = (cmd_op & 0xffff) | 14 << 16 | 1 << 25;
+       cmd->rsp.arg[0] |= 1 << 25;
 
        switch (mode) {
        case QLC_GUEST_VLAN_MODE:
@@ -1561,6 +1563,7 @@ void qlcnic_sriov_pf_handle_flr(struct qlcnic_sriov *sriov,
                                struct qlcnic_vf_info *vf)
 {
        struct net_device *dev = vf->adapter->netdev;
+       struct qlcnic_vport *vp = vf->vp;
 
        if (!test_and_clear_bit(QLC_BC_VF_STATE, &vf->state)) {
                clear_bit(QLC_BC_VF_FLR, &vf->state);
@@ -1573,6 +1576,9 @@ void qlcnic_sriov_pf_handle_flr(struct qlcnic_sriov *sriov,
                return;
        }
 
+       if (vp->vlan_mode == QLC_GUEST_VLAN_MODE)
+               vp->vlan = 0;
+
        qlcnic_sriov_schedule_flr(sriov, vf, qlcnic_sriov_pf_process_flr);
        netdev_info(dev, "FLR received for PCI func %d\n", vf->pci_func);
 }
@@ -1621,13 +1627,15 @@ int qlcnic_sriov_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
 {
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
        struct qlcnic_sriov *sriov = adapter->ahw->sriov;
-       int i, num_vfs = sriov->num_vfs;
+       int i, num_vfs;
        struct qlcnic_vf_info *vf_info;
        u8 *curr_mac;
 
        if (!qlcnic_sriov_pf_check(adapter))
                return -EOPNOTSUPP;
 
+       num_vfs = sriov->num_vfs;
+
        if (!is_valid_ether_addr(mac) || vf >= num_vfs)
                return -EINVAL;
 
@@ -1741,6 +1749,7 @@ int qlcnic_sriov_set_vf_vlan(struct net_device *netdev, int vf,
 
        switch (vlan) {
        case 4095:
+               vp->vlan = 0;
                vp->vlan_mode = QLC_GUEST_VLAN_MODE;
                break;
        case 0:
@@ -1759,6 +1768,29 @@ int qlcnic_sriov_set_vf_vlan(struct net_device *netdev, int vf,
        return 0;
 }
 
+static inline __u32 qlcnic_sriov_get_vf_vlan(struct qlcnic_adapter *adapter,
+                                            struct qlcnic_vport *vp, int vf)
+{
+       __u32 vlan = 0;
+
+       switch (vp->vlan_mode) {
+       case QLC_PVID_MODE:
+               vlan = vp->vlan;
+               break;
+       case QLC_GUEST_VLAN_MODE:
+               vlan = MAX_VLAN_ID;
+               break;
+       case QLC_NO_VLAN_MODE:
+               vlan = 0;
+               break;
+       default:
+               netdev_info(adapter->netdev, "Invalid VLAN mode = %d for VF %d\n",
+                           vp->vlan_mode, vf);
+       }
+
+       return vlan;
+}
+
 int qlcnic_sriov_get_vf_config(struct net_device *netdev,
                               int vf, struct ifla_vf_info *ivi)
 {
@@ -1774,7 +1806,7 @@ int qlcnic_sriov_get_vf_config(struct net_device *netdev,
 
        vp = sriov->vf_info[vf].vp;
        memcpy(&ivi->mac, vp->mac, ETH_ALEN);
-       ivi->vlan = vp->vlan;
+       ivi->vlan = qlcnic_sriov_get_vf_vlan(adapter, vp, vf);
        ivi->qos = vp->qos;
        ivi->spoofchk = vp->spoofchk;
        if (vp->max_tx_bw == MAX_BW)
index e6acb9fa5767687d8565596adc11328f55e2a12b..6f35f8404d68adeffa84e9adbdbe4927176db74e 100644 (file)
@@ -478,7 +478,7 @@ rx_status_loop:
 
        while (1) {
                u32 status, len;
-               dma_addr_t mapping;
+               dma_addr_t mapping, new_mapping;
                struct sk_buff *skb, *new_skb;
                struct cp_desc *desc;
                const unsigned buflen = cp->rx_buf_sz;
@@ -520,6 +520,13 @@ rx_status_loop:
                        goto rx_next;
                }
 
+               new_mapping = dma_map_single(&cp->pdev->dev, new_skb->data, buflen,
+                                        PCI_DMA_FROMDEVICE);
+               if (dma_mapping_error(&cp->pdev->dev, new_mapping)) {
+                       dev->stats.rx_dropped++;
+                       goto rx_next;
+               }
+
                dma_unmap_single(&cp->pdev->dev, mapping,
                                 buflen, PCI_DMA_FROMDEVICE);
 
@@ -531,12 +538,11 @@ rx_status_loop:
 
                skb_put(skb, len);
 
-               mapping = dma_map_single(&cp->pdev->dev, new_skb->data, buflen,
-                                        PCI_DMA_FROMDEVICE);
                cp->rx_skb[rx_tail] = new_skb;
 
                cp_rx_skb(cp, skb, desc);
                rx++;
+               mapping = new_mapping;
 
 rx_next:
                cp->rx_ring[rx_tail].opts2 = 0;
@@ -716,6 +722,22 @@ static inline u32 cp_tx_vlan_tag(struct sk_buff *skb)
                TxVlanTag | swab16(vlan_tx_tag_get(skb)) : 0x00;
 }
 
+static void unwind_tx_frag_mapping(struct cp_private *cp, struct sk_buff *skb,
+                                  int first, int entry_last)
+{
+       int frag, index;
+       struct cp_desc *txd;
+       skb_frag_t *this_frag;
+       for (frag = 0; frag+first < entry_last; frag++) {
+               index = first+frag;
+               cp->tx_skb[index] = NULL;
+               txd = &cp->tx_ring[index];
+               this_frag = &skb_shinfo(skb)->frags[frag];
+               dma_unmap_single(&cp->pdev->dev, le64_to_cpu(txd->addr),
+                                skb_frag_size(this_frag), PCI_DMA_TODEVICE);
+       }
+}
+
 static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
                                        struct net_device *dev)
 {
@@ -749,6 +771,9 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
 
                len = skb->len;
                mapping = dma_map_single(&cp->pdev->dev, skb->data, len, PCI_DMA_TODEVICE);
+               if (dma_mapping_error(&cp->pdev->dev, mapping))
+                       goto out_dma_error;
+
                txd->opts2 = opts2;
                txd->addr = cpu_to_le64(mapping);
                wmb();
@@ -786,6 +811,9 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
                first_len = skb_headlen(skb);
                first_mapping = dma_map_single(&cp->pdev->dev, skb->data,
                                               first_len, PCI_DMA_TODEVICE);
+               if (dma_mapping_error(&cp->pdev->dev, first_mapping))
+                       goto out_dma_error;
+
                cp->tx_skb[entry] = skb;
                entry = NEXT_TX(entry);
 
@@ -799,6 +827,11 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
                        mapping = dma_map_single(&cp->pdev->dev,
                                                 skb_frag_address(this_frag),
                                                 len, PCI_DMA_TODEVICE);
+                       if (dma_mapping_error(&cp->pdev->dev, mapping)) {
+                               unwind_tx_frag_mapping(cp, skb, first_entry, entry);
+                               goto out_dma_error;
+                       }
+
                        eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
 
                        ctrl = eor | len | DescOwn;
@@ -859,11 +892,16 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
        if (TX_BUFFS_AVAIL(cp) <= (MAX_SKB_FRAGS + 1))
                netif_stop_queue(dev);
 
+out_unlock:
        spin_unlock_irqrestore(&cp->lock, intr_flags);
 
        cpw8(TxPoll, NormalTxPoll);
 
        return NETDEV_TX_OK;
+out_dma_error:
+       kfree_skb(skb);
+       cp->dev->stats.tx_dropped++;
+       goto out_unlock;
 }
 
 /* Set or clear the multicast filter for this adaptor.
@@ -1054,6 +1092,10 @@ static int cp_refill_rx(struct cp_private *cp)
 
                mapping = dma_map_single(&cp->pdev->dev, skb->data,
                                         cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+               if (dma_mapping_error(&cp->pdev->dev, mapping)) {
+                       kfree_skb(skb);
+                       goto err_out;
+               }
                cp->rx_skb[i] = skb;
 
                cp->rx_ring[i].opts2 = 0;
index 4106a743ca74c16e0dcf02b1d9b9bc10b76e79a9..880015cae6a3d170e67d51ba21a895688603f761 100644 (file)
@@ -6468,6 +6468,8 @@ static int rtl8169_close(struct net_device *dev)
        rtl8169_down(dev);
        rtl_unlock_work(tp);
 
+       cancel_work_sync(&tp->wk.work);
+
        free_irq(pdev->irq, dev);
 
        dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray,
@@ -6793,8 +6795,6 @@ static void rtl_remove_one(struct pci_dev *pdev)
                rtl8168_driver_stop(tp);
        }
 
-       cancel_work_sync(&tp->wk.work);
-
        netif_napi_del(&tp->napi);
 
        unregister_netdev(dev);
index 19a8a045e07728868cbe3a6e08b841865068e3e3..a30c4395b23220902d4b785333b31b53abfb24c7 100644 (file)
@@ -13,4 +13,4 @@ config SH_ETH
          Renesas SuperH Ethernet device driver.
          This driver supporting CPUs are:
                - SH7619, SH7710, SH7712, SH7724, SH7734, SH7763, SH7757,
-                 R8A7740 and R8A7779.
+                 R8A7740, R8A777x and R8A7790.
index a753928bab9c683d54036f92350e6db466eaa7b9..9e2afe8e0c9fb283ccd9d2508b076ac36419c960 100644 (file)
@@ -189,6 +189,7 @@ static const u16 sh_eth_offset_fast_rcar[SH_ETH_MAX_REGISTER_OFFSET] = {
        [RMCR]          = 0x0258,
        [TFUCR]         = 0x0264,
        [RFOCR]         = 0x0268,
+       [RMIIMODE]      = 0x026c,
        [FCFTR]         = 0x0270,
        [TRIMD]         = 0x027c,
 };
@@ -392,6 +393,27 @@ static struct sh_eth_cpu_data r8a777x_data = {
        .hw_swap        = 1,
 };
 
+/* R8A7790 */
+static struct sh_eth_cpu_data r8a7790_data = {
+       .set_duplex     = sh_eth_set_duplex,
+       .set_rate       = sh_eth_set_rate_r8a777x,
+
+       .ecsr_value     = ECSR_PSRTO | ECSR_LCHNG | ECSR_ICD,
+       .ecsipr_value   = ECSIPR_PSRTOIP | ECSIPR_LCHNGIP | ECSIPR_ICDIP,
+       .eesipr_value   = 0x01ff009f,
+
+       .tx_check       = EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | EESR_RTO,
+       .eesr_err_check = EESR_TWB | EESR_TABT | EESR_RABT | EESR_RFE |
+                         EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE |
+                         EESR_ECI,
+
+       .apr            = 1,
+       .mpr            = 1,
+       .tpauser        = 1,
+       .hw_swap        = 1,
+       .rmiimode       = 1,
+};
+
 static void sh_eth_set_rate_sh7724(struct net_device *ndev)
 {
        struct sh_eth_private *mdp = netdev_priv(ndev);
@@ -1124,6 +1146,9 @@ static int sh_eth_dev_init(struct net_device *ndev, bool start)
        if (ret)
                goto out;
 
+       if (mdp->cd->rmiimode)
+               sh_eth_write(ndev, 0x1, RMIIMODE);
+
        /* Descriptor format */
        sh_eth_ring_format(ndev);
        if (mdp->cd->rpadir)
@@ -2749,6 +2774,7 @@ static struct platform_device_id sh_eth_id_table[] = {
        { "sh7763-gether", (kernel_ulong_t)&sh7763_data },
        { "r8a7740-gether", (kernel_ulong_t)&r8a7740_data },
        { "r8a777x-ether", (kernel_ulong_t)&r8a777x_data },
+       { "r8a7790-ether", (kernel_ulong_t)&r8a7790_data },
        { }
 };
 MODULE_DEVICE_TABLE(platform, sh_eth_id_table);
index 99995bf38c403a3eb641a9d1f79fe5fc54aa6b8b..da93f5cf41f81d049af75b6fc8ec26ce2789ea02 100644 (file)
@@ -60,6 +60,7 @@ enum {
        EDOCR,
        TFUCR,
        RFOCR,
+       RMIIMODE,
        FCFTR,
        RPADIR,
        TRIMD,
@@ -482,6 +483,7 @@ struct sh_eth_cpu_data {
        unsigned hw_crc:1;      /* E-DMAC have CSMR */
        unsigned select_mii:1;  /* EtherC have RMII_MII (MII select register) */
        unsigned shift_rd0:1;   /* shift Rx descriptor word 0 right by 16 */
+       unsigned rmiimode:1;    /* EtherC has RMIIMODE register */
 };
 
 struct sh_eth_private {
index b74a60ab9ac79913111a4f79d4a5a8ca1c723862..2a469b27a5061641a07a8502ecf63736953070a2 100644 (file)
@@ -1209,7 +1209,9 @@ int efx_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb,
        EFX_BUG_ON_PARANOID(skb_headlen(skb) < nhoff + 4 * ip->ihl + 4);
        ports = (const __be16 *)(skb->data + nhoff + 4 * ip->ihl);
 
-       efx_filter_init_rx(&spec, EFX_FILTER_PRI_HINT, 0, rxq_index);
+       efx_filter_init_rx(&spec, EFX_FILTER_PRI_HINT,
+                          efx->rx_scatter ? EFX_FILTER_FLAG_RX_SCATTER : 0,
+                          rxq_index);
        rc = efx_filter_set_ipv4_full(&spec, ip->protocol,
                                      ip->daddr, ports[1], ip->saddr, ports[0]);
        if (rc)
index 03de76c7a177b6c9b54d571370e92d697c9a9ef6..da8be6e630961bac8478565741afe03b7b36a046 100644 (file)
@@ -109,9 +109,6 @@ static int stmmac_pltfr_probe(struct platform_device *pdev)
        const char *mac = NULL;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENODEV;
-
        addr = devm_ioremap_resource(dev, res);
        if (IS_ERR(addr))
                return PTR_ERR(addr);
index 05a1674e204f772f84eb3d4ff70633942ba7c256..f51fcd49f3af8c124e37102328e82d5cba795008 100644 (file)
@@ -91,6 +91,7 @@ do {                                                          \
 #define CPSW1_SLAVE_SIZE       0x040
 #define CPSW1_CPDMA_OFFSET     0x100
 #define CPSW1_STATERAM_OFFSET  0x200
+#define CPSW1_HW_STATS         0x400
 #define CPSW1_CPTS_OFFSET      0x500
 #define CPSW1_ALE_OFFSET       0x600
 #define CPSW1_SLIVER_OFFSET    0x700
@@ -99,6 +100,7 @@ do {                                                         \
 #define CPSW2_SLAVE_OFFSET     0x200
 #define CPSW2_SLAVE_SIZE       0x100
 #define CPSW2_CPDMA_OFFSET     0x800
+#define CPSW2_HW_STATS         0x900
 #define CPSW2_STATERAM_OFFSET  0xa00
 #define CPSW2_CPTS_OFFSET      0xc00
 #define CPSW2_ALE_OFFSET       0xd00
@@ -299,6 +301,44 @@ struct cpsw_sliver_regs {
        u32     rx_pri_map;
 };
 
+struct cpsw_hw_stats {
+       u32     rxgoodframes;
+       u32     rxbroadcastframes;
+       u32     rxmulticastframes;
+       u32     rxpauseframes;
+       u32     rxcrcerrors;
+       u32     rxaligncodeerrors;
+       u32     rxoversizedframes;
+       u32     rxjabberframes;
+       u32     rxundersizedframes;
+       u32     rxfragments;
+       u32     __pad_0[2];
+       u32     rxoctets;
+       u32     txgoodframes;
+       u32     txbroadcastframes;
+       u32     txmulticastframes;
+       u32     txpauseframes;
+       u32     txdeferredframes;
+       u32     txcollisionframes;
+       u32     txsinglecollframes;
+       u32     txmultcollframes;
+       u32     txexcessivecollisions;
+       u32     txlatecollisions;
+       u32     txunderrun;
+       u32     txcarriersenseerrors;
+       u32     txoctets;
+       u32     octetframes64;
+       u32     octetframes65t127;
+       u32     octetframes128t255;
+       u32     octetframes256t511;
+       u32     octetframes512t1023;
+       u32     octetframes1024tup;
+       u32     netoctets;
+       u32     rxsofoverruns;
+       u32     rxmofoverruns;
+       u32     rxdmaoverruns;
+};
+
 struct cpsw_slave {
        void __iomem                    *regs;
        struct cpsw_sliver_regs __iomem *sliver;
@@ -332,6 +372,7 @@ struct cpsw_priv {
        struct cpsw_platform_data       data;
        struct cpsw_ss_regs __iomem     *regs;
        struct cpsw_wr_regs __iomem     *wr_regs;
+       u8 __iomem                      *hw_stats;
        struct cpsw_host_regs __iomem   *host_port_regs;
        u32                             msg_enable;
        u32                             version;
@@ -354,6 +395,94 @@ struct cpsw_priv {
        u32 emac_port;
 };
 
+struct cpsw_stats {
+       char stat_string[ETH_GSTRING_LEN];
+       int type;
+       int sizeof_stat;
+       int stat_offset;
+};
+
+enum {
+       CPSW_STATS,
+       CPDMA_RX_STATS,
+       CPDMA_TX_STATS,
+};
+
+#define CPSW_STAT(m)           CPSW_STATS,                             \
+                               sizeof(((struct cpsw_hw_stats *)0)->m), \
+                               offsetof(struct cpsw_hw_stats, m)
+#define CPDMA_RX_STAT(m)       CPDMA_RX_STATS,                            \
+                               sizeof(((struct cpdma_chan_stats *)0)->m), \
+                               offsetof(struct cpdma_chan_stats, m)
+#define CPDMA_TX_STAT(m)       CPDMA_TX_STATS,                            \
+                               sizeof(((struct cpdma_chan_stats *)0)->m), \
+                               offsetof(struct cpdma_chan_stats, m)
+
+static const struct cpsw_stats cpsw_gstrings_stats[] = {
+       { "Good Rx Frames", CPSW_STAT(rxgoodframes) },
+       { "Broadcast Rx Frames", CPSW_STAT(rxbroadcastframes) },
+       { "Multicast Rx Frames", CPSW_STAT(rxmulticastframes) },
+       { "Pause Rx Frames", CPSW_STAT(rxpauseframes) },
+       { "Rx CRC Errors", CPSW_STAT(rxcrcerrors) },
+       { "Rx Align/Code Errors", CPSW_STAT(rxaligncodeerrors) },
+       { "Oversize Rx Frames", CPSW_STAT(rxoversizedframes) },
+       { "Rx Jabbers", CPSW_STAT(rxjabberframes) },
+       { "Undersize (Short) Rx Frames", CPSW_STAT(rxundersizedframes) },
+       { "Rx Fragments", CPSW_STAT(rxfragments) },
+       { "Rx Octets", CPSW_STAT(rxoctets) },
+       { "Good Tx Frames", CPSW_STAT(txgoodframes) },
+       { "Broadcast Tx Frames", CPSW_STAT(txbroadcastframes) },
+       { "Multicast Tx Frames", CPSW_STAT(txmulticastframes) },
+       { "Pause Tx Frames", CPSW_STAT(txpauseframes) },
+       { "Deferred Tx Frames", CPSW_STAT(txdeferredframes) },
+       { "Collisions", CPSW_STAT(txcollisionframes) },
+       { "Single Collision Tx Frames", CPSW_STAT(txsinglecollframes) },
+       { "Multiple Collision Tx Frames", CPSW_STAT(txmultcollframes) },
+       { "Excessive Collisions", CPSW_STAT(txexcessivecollisions) },
+       { "Late Collisions", CPSW_STAT(txlatecollisions) },
+       { "Tx Underrun", CPSW_STAT(txunderrun) },
+       { "Carrier Sense Errors", CPSW_STAT(txcarriersenseerrors) },
+       { "Tx Octets", CPSW_STAT(txoctets) },
+       { "Rx + Tx 64 Octet Frames", CPSW_STAT(octetframes64) },
+       { "Rx + Tx 65-127 Octet Frames", CPSW_STAT(octetframes65t127) },
+       { "Rx + Tx 128-255 Octet Frames", CPSW_STAT(octetframes128t255) },
+       { "Rx + Tx 256-511 Octet Frames", CPSW_STAT(octetframes256t511) },
+       { "Rx + Tx 512-1023 Octet Frames", CPSW_STAT(octetframes512t1023) },
+       { "Rx + Tx 1024-Up Octet Frames", CPSW_STAT(octetframes1024tup) },
+       { "Net Octets", CPSW_STAT(netoctets) },
+       { "Rx Start of Frame Overruns", CPSW_STAT(rxsofoverruns) },
+       { "Rx Middle of Frame Overruns", CPSW_STAT(rxmofoverruns) },
+       { "Rx DMA Overruns", CPSW_STAT(rxdmaoverruns) },
+       { "Rx DMA chan: head_enqueue", CPDMA_RX_STAT(head_enqueue) },
+       { "Rx DMA chan: tail_enqueue", CPDMA_RX_STAT(tail_enqueue) },
+       { "Rx DMA chan: pad_enqueue", CPDMA_RX_STAT(pad_enqueue) },
+       { "Rx DMA chan: misqueued", CPDMA_RX_STAT(misqueued) },
+       { "Rx DMA chan: desc_alloc_fail", CPDMA_RX_STAT(desc_alloc_fail) },
+       { "Rx DMA chan: pad_alloc_fail", CPDMA_RX_STAT(pad_alloc_fail) },
+       { "Rx DMA chan: runt_receive_buf", CPDMA_RX_STAT(runt_receive_buff) },
+       { "Rx DMA chan: runt_transmit_buf", CPDMA_RX_STAT(runt_transmit_buff) },
+       { "Rx DMA chan: empty_dequeue", CPDMA_RX_STAT(empty_dequeue) },
+       { "Rx DMA chan: busy_dequeue", CPDMA_RX_STAT(busy_dequeue) },
+       { "Rx DMA chan: good_dequeue", CPDMA_RX_STAT(good_dequeue) },
+       { "Rx DMA chan: requeue", CPDMA_RX_STAT(requeue) },
+       { "Rx DMA chan: teardown_dequeue", CPDMA_RX_STAT(teardown_dequeue) },
+       { "Tx DMA chan: head_enqueue", CPDMA_TX_STAT(head_enqueue) },
+       { "Tx DMA chan: tail_enqueue", CPDMA_TX_STAT(tail_enqueue) },
+       { "Tx DMA chan: pad_enqueue", CPDMA_TX_STAT(pad_enqueue) },
+       { "Tx DMA chan: misqueued", CPDMA_TX_STAT(misqueued) },
+       { "Tx DMA chan: desc_alloc_fail", CPDMA_TX_STAT(desc_alloc_fail) },
+       { "Tx DMA chan: pad_alloc_fail", CPDMA_TX_STAT(pad_alloc_fail) },
+       { "Tx DMA chan: runt_receive_buf", CPDMA_TX_STAT(runt_receive_buff) },
+       { "Tx DMA chan: runt_transmit_buf", CPDMA_TX_STAT(runt_transmit_buff) },
+       { "Tx DMA chan: empty_dequeue", CPDMA_TX_STAT(empty_dequeue) },
+       { "Tx DMA chan: busy_dequeue", CPDMA_TX_STAT(busy_dequeue) },
+       { "Tx DMA chan: good_dequeue", CPDMA_TX_STAT(good_dequeue) },
+       { "Tx DMA chan: requeue", CPDMA_TX_STAT(requeue) },
+       { "Tx DMA chan: teardown_dequeue", CPDMA_TX_STAT(teardown_dequeue) },
+};
+
+#define CPSW_STATS_LEN ARRAY_SIZE(cpsw_gstrings_stats)
+
 #define napi_to_priv(napi)     container_of(napi, struct cpsw_priv, napi)
 #define for_each_slave(priv, func, arg...)                             \
        do {                                                            \
@@ -723,6 +852,69 @@ static int cpsw_set_coalesce(struct net_device *ndev,
        return 0;
 }
 
+static int cpsw_get_sset_count(struct net_device *ndev, int sset)
+{
+       switch (sset) {
+       case ETH_SS_STATS:
+               return CPSW_STATS_LEN;
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static void cpsw_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
+{
+       u8 *p = data;
+       int i;
+
+       switch (stringset) {
+       case ETH_SS_STATS:
+               for (i = 0; i < CPSW_STATS_LEN; i++) {
+                       memcpy(p, cpsw_gstrings_stats[i].stat_string,
+                              ETH_GSTRING_LEN);
+                       p += ETH_GSTRING_LEN;
+               }
+               break;
+       }
+}
+
+static void cpsw_get_ethtool_stats(struct net_device *ndev,
+                                   struct ethtool_stats *stats, u64 *data)
+{
+       struct cpsw_priv *priv = netdev_priv(ndev);
+       struct cpdma_chan_stats rx_stats;
+       struct cpdma_chan_stats tx_stats;
+       u32 val;
+       u8 *p;
+       int i;
+
+       /* Collect Davinci CPDMA stats for Rx and Tx Channel */
+       cpdma_chan_get_stats(priv->rxch, &rx_stats);
+       cpdma_chan_get_stats(priv->txch, &tx_stats);
+
+       for (i = 0; i < CPSW_STATS_LEN; i++) {
+               switch (cpsw_gstrings_stats[i].type) {
+               case CPSW_STATS:
+                       val = readl(priv->hw_stats +
+                                   cpsw_gstrings_stats[i].stat_offset);
+                       data[i] = val;
+                       break;
+
+               case CPDMA_RX_STATS:
+                       p = (u8 *)&rx_stats +
+                               cpsw_gstrings_stats[i].stat_offset;
+                       data[i] = *(u32 *)p;
+                       break;
+
+               case CPDMA_TX_STATS:
+                       p = (u8 *)&tx_stats +
+                               cpsw_gstrings_stats[i].stat_offset;
+                       data[i] = *(u32 *)p;
+                       break;
+               }
+       }
+}
+
 static inline int __show_stat(char *buf, int maxlen, const char *name, u32 val)
 {
        static char *leader = "........................................";
@@ -1232,6 +1424,33 @@ static void cpsw_ndo_tx_timeout(struct net_device *ndev)
 
 }
 
+static int cpsw_ndo_set_mac_address(struct net_device *ndev, void *p)
+{
+       struct cpsw_priv *priv = netdev_priv(ndev);
+       struct sockaddr *addr = (struct sockaddr *)p;
+       int flags = 0;
+       u16 vid = 0;
+
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+
+       if (priv->data.dual_emac) {
+               vid = priv->slaves[priv->emac_port].port_vlan;
+               flags = ALE_VLAN;
+       }
+
+       cpsw_ale_del_ucast(priv->ale, priv->mac_addr, priv->host_port,
+                          flags, vid);
+       cpsw_ale_add_ucast(priv->ale, addr->sa_data, priv->host_port,
+                          flags, vid);
+
+       memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN);
+       memcpy(ndev->dev_addr, priv->mac_addr, ETH_ALEN);
+       for_each_slave(priv, cpsw_set_slave_mac, priv);
+
+       return 0;
+}
+
 static struct net_device_stats *cpsw_ndo_get_stats(struct net_device *ndev)
 {
        struct cpsw_priv *priv = netdev_priv(ndev);
@@ -1326,6 +1545,7 @@ static const struct net_device_ops cpsw_netdev_ops = {
        .ndo_stop               = cpsw_ndo_stop,
        .ndo_start_xmit         = cpsw_ndo_start_xmit,
        .ndo_change_rx_flags    = cpsw_ndo_change_rx_flags,
+       .ndo_set_mac_address    = cpsw_ndo_set_mac_address,
        .ndo_do_ioctl           = cpsw_ndo_ioctl,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_change_mtu         = eth_change_mtu,
@@ -1426,6 +1646,9 @@ static const struct ethtool_ops cpsw_ethtool_ops = {
        .set_settings   = cpsw_set_settings,
        .get_coalesce   = cpsw_get_coalesce,
        .set_coalesce   = cpsw_set_coalesce,
+       .get_sset_count         = cpsw_get_sset_count,
+       .get_strings            = cpsw_get_strings,
+       .get_ethtool_stats      = cpsw_get_ethtool_stats,
 };
 
 static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv,
@@ -1623,6 +1846,7 @@ static int cpsw_probe_dual_emac(struct platform_device *pdev,
        priv_sl2->host_port = priv->host_port;
        priv_sl2->host_port_regs = priv->host_port_regs;
        priv_sl2->wr_regs = priv->wr_regs;
+       priv_sl2->hw_stats = priv->hw_stats;
        priv_sl2->dma = priv->dma;
        priv_sl2->txch = priv->txch;
        priv_sl2->rxch = priv->rxch;
@@ -1780,7 +2004,8 @@ static int cpsw_probe(struct platform_device *pdev)
        switch (priv->version) {
        case CPSW_VERSION_1:
                priv->host_port_regs = ss_regs + CPSW1_HOST_PORT_OFFSET;
-               priv->cpts->reg       = ss_regs + CPSW1_CPTS_OFFSET;
+               priv->cpts->reg      = ss_regs + CPSW1_CPTS_OFFSET;
+               priv->hw_stats       = ss_regs + CPSW1_HW_STATS;
                dma_params.dmaregs   = ss_regs + CPSW1_CPDMA_OFFSET;
                dma_params.txhdp     = ss_regs + CPSW1_STATERAM_OFFSET;
                ale_params.ale_regs  = ss_regs + CPSW1_ALE_OFFSET;
@@ -1791,7 +2016,8 @@ static int cpsw_probe(struct platform_device *pdev)
                break;
        case CPSW_VERSION_2:
                priv->host_port_regs = ss_regs + CPSW2_HOST_PORT_OFFSET;
-               priv->cpts->reg       = ss_regs + CPSW2_CPTS_OFFSET;
+               priv->cpts->reg      = ss_regs + CPSW2_CPTS_OFFSET;
+               priv->hw_stats       = ss_regs + CPSW2_HW_STATS;
                dma_params.dmaregs   = ss_regs + CPSW2_CPDMA_OFFSET;
                dma_params.txhdp     = ss_regs + CPSW2_STATERAM_OFFSET;
                ale_params.ale_regs  = ss_regs + CPSW2_ALE_OFFSET;
index 098b1c42b39368faef868e50fdbb3174a6ccf8d9..4083ba8839e1f2e73d1a1b872c4e4149a6db419e 100644 (file)
@@ -15,3 +15,14 @@ config TILE_NET
 
          To compile this driver as a module, choose M here: the module
          will be called tile_net.
+
+config PTP_1588_CLOCK_TILEGX
+        tristate "Tilera TILE-Gx mPIPE as PTP clock"
+        select PTP_1588_CLOCK
+        depends on TILE_NET
+        depends on TILEGX
+        ---help---
+          This driver adds support for using the mPIPE as a PTP
+          clock. This clock is only useful if your PTP programs are
+          getting hardware time stamps on the PTP Ethernet packets
+          using the SO_TIMESTAMPING API.
index f3c2d034b32c817530f3767de710de41c1d71b90..907b5772fd552688af2dba806dee70a8a243ff30 100644 (file)
 #include <linux/io.h>
 #include <linux/ctype.h>
 #include <linux/ip.h>
+#include <linux/ipv6.h>
 #include <linux/tcp.h>
+#include <linux/net_tstamp.h>
+#include <linux/ptp_clock_kernel.h>
 
 #include <asm/checksum.h>
 #include <asm/homecache.h>
@@ -76,6 +79,9 @@
 
 #define MAX_FRAGS (MAX_SKB_FRAGS + 1)
 
+/* The "kinds" of buffer stacks (small/large/jumbo). */
+#define MAX_KINDS 3
+
 /* Size of completions data to allocate.
  * ISSUE: Probably more than needed since we don't use all the channels.
  */
@@ -130,29 +136,31 @@ struct tile_net_tx_wake {
 
 /* Info for a specific cpu. */
 struct tile_net_info {
-       /* The NAPI struct. */
-       struct napi_struct napi;
-       /* Packet queue. */
-       gxio_mpipe_iqueue_t iqueue;
        /* Our cpu. */
        int my_cpu;
-       /* True if iqueue is valid. */
-       bool has_iqueue;
-       /* NAPI flags. */
-       bool napi_added;
-       bool napi_enabled;
-       /* Number of small sk_buffs which must still be provided. */
-       unsigned int num_needed_small_buffers;
-       /* Number of large sk_buffs which must still be provided. */
-       unsigned int num_needed_large_buffers;
        /* A timer for handling egress completions. */
        struct hrtimer egress_timer;
        /* True if "egress_timer" is scheduled. */
        bool egress_timer_scheduled;
-       /* Comps for each egress channel. */
-       struct tile_net_comps *comps_for_echannel[TILE_NET_CHANNELS];
-       /* Transmit wake timer for each egress channel. */
-       struct tile_net_tx_wake tx_wake[TILE_NET_CHANNELS];
+       struct info_mpipe {
+               /* Packet queue. */
+               gxio_mpipe_iqueue_t iqueue;
+               /* The NAPI struct. */
+               struct napi_struct napi;
+               /* Number of buffers (by kind) which must still be provided. */
+               unsigned int num_needed_buffers[MAX_KINDS];
+               /* instance id. */
+               int instance;
+               /* True if iqueue is valid. */
+               bool has_iqueue;
+               /* NAPI flags. */
+               bool napi_added;
+               bool napi_enabled;
+               /* Comps for each egress channel. */
+               struct tile_net_comps *comps_for_echannel[TILE_NET_CHANNELS];
+               /* Transmit wake timer for each egress channel. */
+               struct tile_net_tx_wake tx_wake[TILE_NET_CHANNELS];
+       } mpipe[NR_MPIPE_MAX];
 };
 
 /* Info for egress on a particular egress channel. */
@@ -177,19 +185,67 @@ struct tile_net_priv {
        int loopify_channel;
        /* The egress channel (channel or loopify_channel). */
        int echannel;
-       /* Total stats. */
-       struct net_device_stats stats;
+       /* mPIPE instance, 0 or 1. */
+       int instance;
+#ifdef CONFIG_PTP_1588_CLOCK_TILEGX
+       /* The timestamp config. */
+       struct hwtstamp_config stamp_cfg;
+#endif
 };
 
-/* Egress info, indexed by "priv->echannel" (lazily created as needed). */
-static struct tile_net_egress egress_for_echannel[TILE_NET_CHANNELS];
+static struct mpipe_data {
+       /* The ingress irq. */
+       int ingress_irq;
 
-/* Devices currently associated with each channel.
- * NOTE: The array entry can become NULL after ifconfig down, but
- * we do not free the underlying net_device structures, so it is
- * safe to use a pointer after reading it from this array.
- */
-static struct net_device *tile_net_devs_for_channel[TILE_NET_CHANNELS];
+       /* The "context" for all devices. */
+       gxio_mpipe_context_t context;
+
+       /* Egress info, indexed by "priv->echannel"
+        * (lazily created as needed).
+        */
+       struct tile_net_egress
+       egress_for_echannel[TILE_NET_CHANNELS];
+
+       /* Devices currently associated with each channel.
+        * NOTE: The array entry can become NULL after ifconfig down, but
+        * we do not free the underlying net_device structures, so it is
+        * safe to use a pointer after reading it from this array.
+        */
+       struct net_device
+       *tile_net_devs_for_channel[TILE_NET_CHANNELS];
+
+       /* The actual memory allocated for the buffer stacks. */
+       void *buffer_stack_vas[MAX_KINDS];
+
+       /* The amount of memory allocated for each buffer stack. */
+       size_t buffer_stack_bytes[MAX_KINDS];
+
+       /* The first buffer stack index
+        * (small = +0, large = +1, jumbo = +2).
+        */
+       int first_buffer_stack;
+
+       /* The buckets. */
+       int first_bucket;
+       int num_buckets;
+
+#ifdef CONFIG_PTP_1588_CLOCK_TILEGX
+       /* PTP-specific data. */
+       struct ptp_clock *ptp_clock;
+       struct ptp_clock_info caps;
+
+       /* Lock for ptp accessors. */
+       struct mutex ptp_lock;
+#endif
+
+} mpipe_data[NR_MPIPE_MAX] = {
+       [0 ... (NR_MPIPE_MAX - 1)] {
+               .ingress_irq = -1,
+               .first_buffer_stack = -1,
+               .first_bucket = -1,
+               .num_buckets = 1
+       }
+};
 
 /* A mutex for "tile_net_devs_for_channel". */
 static DEFINE_MUTEX(tile_net_devs_for_channel_mutex);
@@ -197,34 +253,17 @@ static DEFINE_MUTEX(tile_net_devs_for_channel_mutex);
 /* The per-cpu info. */
 static DEFINE_PER_CPU(struct tile_net_info, per_cpu_info);
 
-/* The "context" for all devices. */
-static gxio_mpipe_context_t context;
 
-/* Buffer sizes and mpipe enum codes for buffer stacks.
+/* The buffer size enums for each buffer stack.
  * See arch/tile/include/gxio/mpipe.h for the set of possible values.
+ * We avoid the "10384" size because it can induce "false chaining"
+ * on "cut-through" jumbo packets.
  */
-#define BUFFER_SIZE_SMALL_ENUM GXIO_MPIPE_BUFFER_SIZE_128
-#define BUFFER_SIZE_SMALL 128
-#define BUFFER_SIZE_LARGE_ENUM GXIO_MPIPE_BUFFER_SIZE_1664
-#define BUFFER_SIZE_LARGE 1664
-
-/* The small/large "buffer stacks". */
-static int small_buffer_stack = -1;
-static int large_buffer_stack = -1;
-
-/* Amount of memory allocated for each buffer stack. */
-static size_t buffer_stack_size;
-
-/* The actual memory allocated for the buffer stacks. */
-static void *small_buffer_stack_va;
-static void *large_buffer_stack_va;
-
-/* The buckets. */
-static int first_bucket = -1;
-static int num_buckets = 1;
-
-/* The ingress irq. */
-static int ingress_irq = -1;
+static gxio_mpipe_buffer_size_enum_t buffer_size_enums[MAX_KINDS] = {
+       GXIO_MPIPE_BUFFER_SIZE_128,
+       GXIO_MPIPE_BUFFER_SIZE_1664,
+       GXIO_MPIPE_BUFFER_SIZE_16384
+};
 
 /* Text value of tile_net.cpus if passed as a module parameter. */
 static char *network_cpus_string;
@@ -232,11 +271,21 @@ static char *network_cpus_string;
 /* The actual cpus in "network_cpus". */
 static struct cpumask network_cpus_map;
 
-/* If "loopify=LINK" was specified, this is "LINK". */
+/* If "tile_net.loopify=LINK" was specified, this is "LINK". */
 static char *loopify_link_name;
 
-/* If "tile_net.custom" was specified, this is non-NULL. */
-static char *custom_str;
+/* If "tile_net.custom" was specified, this is true. */
+static bool custom_flag;
+
+/* If "tile_net.jumbo=NUM" was specified, this is "NUM". */
+static uint jumbo_num;
+
+/* Obtain mpipe instance from struct tile_net_priv given struct net_device. */
+static inline int mpipe_instance(struct net_device *dev)
+{
+       struct tile_net_priv *priv = netdev_priv(dev);
+       return priv->instance;
+}
 
 /* The "tile_net.cpus" argument specifies the cpus that are dedicated
  * to handle ingress packets.
@@ -289,9 +338,15 @@ MODULE_PARM_DESC(loopify, "name the device to use loop0/1 for ingress/egress");
 /* The "tile_net.custom" argument causes us to ignore the "conventional"
  * classifier metadata, in particular, the "l2_offset".
  */
-module_param_named(custom, custom_str, charp, 0444);
+module_param_named(custom, custom_flag, bool, 0444);
 MODULE_PARM_DESC(custom, "indicates a (heavily) customized classifier");
 
+/* The "tile_net.jumbo" argument causes us to support "jumbo" packets,
+ * and to allocate the given number of "jumbo" buffers.
+ */
+module_param_named(jumbo, jumbo_num, uint, 0444);
+MODULE_PARM_DESC(jumbo, "the number of buffers to support jumbo packets");
+
 /* Atomically update a statistics field.
  * Note that on TILE-Gx, this operation is fire-and-forget on the
  * issuing core (single-cycle dispatch) and takes only a few cycles
@@ -305,15 +360,16 @@ static void tile_net_stats_add(unsigned long value, unsigned long *field)
 }
 
 /* Allocate and push a buffer. */
-static bool tile_net_provide_buffer(bool small)
+static bool tile_net_provide_buffer(int instance, int kind)
 {
-       int stack = small ? small_buffer_stack : large_buffer_stack;
+       struct mpipe_data *md = &mpipe_data[instance];
+       gxio_mpipe_buffer_size_enum_t bse = buffer_size_enums[kind];
+       size_t bs = gxio_mpipe_buffer_size_enum_to_buffer_size(bse);
        const unsigned long buffer_alignment = 128;
        struct sk_buff *skb;
        int len;
 
-       len = sizeof(struct sk_buff **) + buffer_alignment;
-       len += (small ? BUFFER_SIZE_SMALL : BUFFER_SIZE_LARGE);
+       len = sizeof(struct sk_buff **) + buffer_alignment + bs;
        skb = dev_alloc_skb(len);
        if (skb == NULL)
                return false;
@@ -328,7 +384,7 @@ static bool tile_net_provide_buffer(bool small)
        /* Make sure "skb" and the back-pointer have been flushed. */
        wmb();
 
-       gxio_mpipe_push_buffer(&context, stack,
+       gxio_mpipe_push_buffer(&md->context, md->first_buffer_stack + kind,
                               (void *)va_to_tile_io_addr(skb->data));
 
        return true;
@@ -354,11 +410,14 @@ static struct sk_buff *mpipe_buf_to_skb(void *va)
        return skb;
 }
 
-static void tile_net_pop_all_buffers(int stack)
+static void tile_net_pop_all_buffers(int instance, int stack)
 {
+       struct mpipe_data *md = &mpipe_data[instance];
+
        for (;;) {
                tile_io_addr_t addr =
-                       (tile_io_addr_t)gxio_mpipe_pop_buffer(&context, stack);
+                       (tile_io_addr_t)gxio_mpipe_pop_buffer(&md->context,
+                                                             stack);
                if (addr == 0)
                        break;
                dev_kfree_skb_irq(mpipe_buf_to_skb(tile_io_addr_to_va(addr)));
@@ -369,24 +428,111 @@ static void tile_net_pop_all_buffers(int stack)
 static void tile_net_provide_needed_buffers(void)
 {
        struct tile_net_info *info = &__get_cpu_var(per_cpu_info);
+       int instance, kind;
+       for (instance = 0; instance < NR_MPIPE_MAX &&
+                    info->mpipe[instance].has_iqueue; instance++)      {
+               for (kind = 0; kind < MAX_KINDS; kind++) {
+                       while (info->mpipe[instance].num_needed_buffers[kind]
+                              != 0) {
+                               if (!tile_net_provide_buffer(instance, kind)) {
+                                       pr_notice("Tile %d still needs"
+                                                 " some buffers\n",
+                                                 info->my_cpu);
+                                       return;
+                               }
+                               info->mpipe[instance].
+                                       num_needed_buffers[kind]--;
+                       }
+               }
+       }
+}
 
-       while (info->num_needed_small_buffers != 0) {
-               if (!tile_net_provide_buffer(true))
-                       goto oops;
-               info->num_needed_small_buffers--;
+/* Get RX timestamp, and store it in the skb. */
+static void tile_rx_timestamp(struct tile_net_priv *priv, struct sk_buff *skb,
+                             gxio_mpipe_idesc_t *idesc)
+{
+#ifdef CONFIG_PTP_1588_CLOCK_TILEGX
+       if (unlikely(priv->stamp_cfg.rx_filter != HWTSTAMP_FILTER_NONE)) {
+               struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
+               memset(shhwtstamps, 0, sizeof(*shhwtstamps));
+               shhwtstamps->hwtstamp = ktime_set(idesc->time_stamp_sec,
+                                                 idesc->time_stamp_ns);
        }
+#endif
+}
 
-       while (info->num_needed_large_buffers != 0) {
-               if (!tile_net_provide_buffer(false))
-                       goto oops;
-               info->num_needed_large_buffers--;
+/* Get TX timestamp, and store it in the skb. */
+static void tile_tx_timestamp(struct sk_buff *skb, int instance)
+{
+#ifdef CONFIG_PTP_1588_CLOCK_TILEGX
+       struct skb_shared_info *shtx = skb_shinfo(skb);
+       if (unlikely((shtx->tx_flags & SKBTX_HW_TSTAMP) != 0)) {
+               struct mpipe_data *md = &mpipe_data[instance];
+               struct skb_shared_hwtstamps shhwtstamps;
+               struct timespec ts;
+
+               shtx->tx_flags |= SKBTX_IN_PROGRESS;
+               gxio_mpipe_get_timestamp(&md->context, &ts);
+               memset(&shhwtstamps, 0, sizeof(shhwtstamps));
+               shhwtstamps.hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec);
+               skb_tstamp_tx(skb, &shhwtstamps);
        }
+#endif
+}
+
+/* Use ioctl() to enable or disable TX or RX timestamping. */
+static int tile_hwtstamp_ioctl(struct net_device *dev, struct ifreq *rq,
+                              int cmd)
+{
+#ifdef CONFIG_PTP_1588_CLOCK_TILEGX
+       struct hwtstamp_config config;
+       struct tile_net_priv *priv = netdev_priv(dev);
 
-       return;
+       if (copy_from_user(&config, rq->ifr_data, sizeof(config)))
+               return -EFAULT;
+
+       if (config.flags)  /* reserved for future extensions */
+               return -EINVAL;
 
-oops:
-       /* Add a description to the page allocation failure dump. */
-       pr_notice("Tile %d still needs some buffers\n", info->my_cpu);
+       switch (config.tx_type) {
+       case HWTSTAMP_TX_OFF:
+       case HWTSTAMP_TX_ON:
+               break;
+       default:
+               return -ERANGE;
+       }
+
+       switch (config.rx_filter) {
+       case HWTSTAMP_FILTER_NONE:
+               break;
+       case HWTSTAMP_FILTER_ALL:
+       case HWTSTAMP_FILTER_SOME:
+       case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+       case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+       case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+       case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+       case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+       case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+       case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+       case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+       case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+       case HWTSTAMP_FILTER_PTP_V2_EVENT:
+       case HWTSTAMP_FILTER_PTP_V2_SYNC:
+       case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+               config.rx_filter = HWTSTAMP_FILTER_ALL;
+               break;
+       default:
+               return -ERANGE;
+       }
+
+       if (copy_to_user(rq->ifr_data, &config, sizeof(config)))
+               return -EFAULT;
+
+       priv->stamp_cfg = config;
+       return 0;
+#else
+       return -EOPNOTSUPP;
+#endif
 }
 
 static inline bool filter_packet(struct net_device *dev, void *buf)
@@ -409,6 +555,7 @@ static void tile_net_receive_skb(struct net_device *dev, struct sk_buff *skb,
 {
        struct tile_net_info *info = &__get_cpu_var(per_cpu_info);
        struct tile_net_priv *priv = netdev_priv(dev);
+       int instance = priv->instance;
 
        /* Encode the actual packet length. */
        skb_put(skb, len);
@@ -419,47 +566,52 @@ static void tile_net_receive_skb(struct net_device *dev, struct sk_buff *skb,
        if (idesc->cs && idesc->csum_seed_val == 0xFFFF)
                skb->ip_summed = CHECKSUM_UNNECESSARY;
 
-       netif_receive_skb(skb);
+       /* Get RX timestamp from idesc. */
+       tile_rx_timestamp(priv, skb, idesc);
+
+       napi_gro_receive(&info->mpipe[instance].napi, skb);
 
        /* Update stats. */
-       tile_net_stats_add(1, &priv->stats.rx_packets);
-       tile_net_stats_add(len, &priv->stats.rx_bytes);
+       tile_net_stats_add(1, &dev->stats.rx_packets);
+       tile_net_stats_add(len, &dev->stats.rx_bytes);
 
        /* Need a new buffer. */
-       if (idesc->size == BUFFER_SIZE_SMALL_ENUM)
-               info->num_needed_small_buffers++;
+       if (idesc->size == buffer_size_enums[0])
+               info->mpipe[instance].num_needed_buffers[0]++;
+       else if (idesc->size == buffer_size_enums[1])
+               info->mpipe[instance].num_needed_buffers[1]++;
        else
-               info->num_needed_large_buffers++;
+               info->mpipe[instance].num_needed_buffers[2]++;
 }
 
 /* Handle a packet.  Return true if "processed", false if "filtered". */
-static bool tile_net_handle_packet(gxio_mpipe_idesc_t *idesc)
+static bool tile_net_handle_packet(int instance, gxio_mpipe_idesc_t *idesc)
 {
        struct tile_net_info *info = &__get_cpu_var(per_cpu_info);
-       struct net_device *dev = tile_net_devs_for_channel[idesc->channel];
+       struct mpipe_data *md = &mpipe_data[instance];
+       struct net_device *dev = md->tile_net_devs_for_channel[idesc->channel];
        uint8_t l2_offset;
        void *va;
        void *buf;
        unsigned long len;
        bool filter;
 
-       /* Drop packets for which no buffer was available.
-        * NOTE: This happens under heavy load.
+       /* Drop packets for which no buffer was available (which can
+        * happen under heavy load), or for which the me/tr/ce flags
+        * are set (which can happen for jumbo cut-through packets,
+        * or with a customized classifier).
         */
-       if (idesc->be) {
-               struct tile_net_priv *priv = netdev_priv(dev);
-               tile_net_stats_add(1, &priv->stats.rx_dropped);
-               gxio_mpipe_iqueue_consume(&info->iqueue, idesc);
-               if (net_ratelimit())
-                       pr_info("Dropping packet (insufficient buffers).\n");
-               return false;
+       if (idesc->be || idesc->me || idesc->tr || idesc->ce) {
+               if (dev)
+                       tile_net_stats_add(1, &dev->stats.rx_errors);
+               goto drop;
        }
 
        /* Get the "l2_offset", if allowed. */
-       l2_offset = custom_str ? 0 : gxio_mpipe_idesc_get_l2_offset(idesc);
+       l2_offset = custom_flag ? 0 : gxio_mpipe_idesc_get_l2_offset(idesc);
 
-       /* Get the raw buffer VA (includes "headroom"). */
-       va = tile_io_addr_to_va((unsigned long)(long)idesc->va);
+       /* Get the VA (including NET_IP_ALIGN bytes of "headroom"). */
+       va = tile_io_addr_to_va((unsigned long)idesc->va);
 
        /* Get the actual packet start/length. */
        buf = va + l2_offset;
@@ -470,7 +622,10 @@ static bool tile_net_handle_packet(gxio_mpipe_idesc_t *idesc)
 
        filter = filter_packet(dev, buf);
        if (filter) {
-               gxio_mpipe_iqueue_drop(&info->iqueue, idesc);
+               if (dev)
+                       tile_net_stats_add(1, &dev->stats.rx_dropped);
+drop:
+               gxio_mpipe_iqueue_drop(&info->mpipe[instance].iqueue, idesc);
        } else {
                struct sk_buff *skb = mpipe_buf_to_skb(va);
 
@@ -480,7 +635,7 @@ static bool tile_net_handle_packet(gxio_mpipe_idesc_t *idesc)
                tile_net_receive_skb(dev, skb, idesc, len);
        }
 
-       gxio_mpipe_iqueue_consume(&info->iqueue, idesc);
+       gxio_mpipe_iqueue_consume(&info->mpipe[instance].iqueue, idesc);
        return !filter;
 }
 
@@ -501,14 +656,20 @@ static int tile_net_poll(struct napi_struct *napi, int budget)
        struct tile_net_info *info = &__get_cpu_var(per_cpu_info);
        unsigned int work = 0;
        gxio_mpipe_idesc_t *idesc;
-       int i, n;
-
-       /* Process packets. */
-       while ((n = gxio_mpipe_iqueue_try_peek(&info->iqueue, &idesc)) > 0) {
+       int instance, i, n;
+       struct mpipe_data *md;
+       struct info_mpipe *info_mpipe =
+               container_of(napi, struct info_mpipe, napi);
+
+       instance = info_mpipe->instance;
+       while ((n = gxio_mpipe_iqueue_try_peek(
+                       &info_mpipe->iqueue,
+                       &idesc)) > 0) {
                for (i = 0; i < n; i++) {
                        if (i == TILE_NET_BATCH)
                                goto done;
-                       if (tile_net_handle_packet(idesc + i)) {
+                       if (tile_net_handle_packet(instance,
+                                                  idesc + i)) {
                                if (++work >= budget)
                                        goto done;
                        }
@@ -516,14 +677,16 @@ static int tile_net_poll(struct napi_struct *napi, int budget)
        }
 
        /* There are no packets left. */
-       napi_complete(&info->napi);
+       napi_complete(&info_mpipe->napi);
 
+       md = &mpipe_data[instance];
        /* Re-enable hypervisor interrupts. */
-       gxio_mpipe_enable_notif_ring_interrupt(&context, info->iqueue.ring);
+       gxio_mpipe_enable_notif_ring_interrupt(
+               &md->context, info->mpipe[instance].iqueue.ring);
 
        /* HACK: Avoid the "rotting packet" problem. */
-       if (gxio_mpipe_iqueue_try_peek(&info->iqueue, &idesc) > 0)
-               napi_schedule(&info->napi);
+       if (gxio_mpipe_iqueue_try_peek(&info_mpipe->iqueue, &idesc) > 0)
+               napi_schedule(&info_mpipe->napi);
 
        /* ISSUE: Handle completions? */
 
@@ -533,11 +696,11 @@ done:
        return work;
 }
 
-/* Handle an ingress interrupt on the current cpu. */
-static irqreturn_t tile_net_handle_ingress_irq(int irq, void *unused)
+/* Handle an ingress interrupt from an instance on the current cpu. */
+static irqreturn_t tile_net_handle_ingress_irq(int irq, void *id)
 {
        struct tile_net_info *info = &__get_cpu_var(per_cpu_info);
-       napi_schedule(&info->napi);
+       napi_schedule(&info->mpipe[(uint64_t)id].napi);
        return IRQ_HANDLED;
 }
 
@@ -579,7 +742,9 @@ static void tile_net_schedule_tx_wake_timer(struct net_device *dev,
 {
        struct tile_net_info *info = &per_cpu(per_cpu_info, tx_queue_idx);
        struct tile_net_priv *priv = netdev_priv(dev);
-       struct tile_net_tx_wake *tx_wake = &info->tx_wake[priv->echannel];
+       int instance = priv->instance;
+       struct tile_net_tx_wake *tx_wake =
+               &info->mpipe[instance].tx_wake[priv->echannel];
 
        hrtimer_start(&tx_wake->timer,
                      ktime_set(0, TX_TIMER_DELAY_USEC * 1000UL),
@@ -617,7 +782,7 @@ static enum hrtimer_restart tile_net_handle_egress_timer(struct hrtimer *t)
        struct tile_net_info *info = &__get_cpu_var(per_cpu_info);
        unsigned long irqflags;
        bool pending = false;
-       int i;
+       int i, instance;
 
        local_irq_save(irqflags);
 
@@ -625,13 +790,19 @@ static enum hrtimer_restart tile_net_handle_egress_timer(struct hrtimer *t)
        info->egress_timer_scheduled = false;
 
        /* Free all possible comps for this tile. */
-       for (i = 0; i < TILE_NET_CHANNELS; i++) {
-               struct tile_net_egress *egress = &egress_for_echannel[i];
-               struct tile_net_comps *comps = info->comps_for_echannel[i];
-               if (comps->comp_last >= comps->comp_next)
-                       continue;
-               tile_net_free_comps(egress->equeue, comps, -1, true);
-               pending = pending || (comps->comp_last < comps->comp_next);
+       for (instance = 0; instance < NR_MPIPE_MAX &&
+                    info->mpipe[instance].has_iqueue; instance++) {
+               for (i = 0; i < TILE_NET_CHANNELS; i++) {
+                       struct tile_net_egress *egress =
+                               &mpipe_data[instance].egress_for_echannel[i];
+                       struct tile_net_comps *comps =
+                               info->mpipe[instance].comps_for_echannel[i];
+                       if (!egress || comps->comp_last >= comps->comp_next)
+                               continue;
+                       tile_net_free_comps(egress->equeue, comps, -1, true);
+                       pending = pending ||
+                               (comps->comp_last < comps->comp_next);
+               }
        }
 
        /* Reschedule timer if needed. */
@@ -643,37 +814,112 @@ static enum hrtimer_restart tile_net_handle_egress_timer(struct hrtimer *t)
        return HRTIMER_NORESTART;
 }
 
-/* Helper function for "tile_net_update()".
- * "dev" (i.e. arg) is the device being brought up or down,
- * or NULL if all devices are now down.
- */
-static void tile_net_update_cpu(void *arg)
+#ifdef CONFIG_PTP_1588_CLOCK_TILEGX
+
+/* PTP clock operations. */
+
+static int ptp_mpipe_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
 {
-       struct tile_net_info *info = &__get_cpu_var(per_cpu_info);
-       struct net_device *dev = arg;
+       int ret = 0;
+       struct mpipe_data *md = container_of(ptp, struct mpipe_data, caps);
+       mutex_lock(&md->ptp_lock);
+       if (gxio_mpipe_adjust_timestamp_freq(&md->context, ppb))
+               ret = -EINVAL;
+       mutex_unlock(&md->ptp_lock);
+       return ret;
+}
 
-       if (!info->has_iqueue)
-               return;
+static int ptp_mpipe_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+       int ret = 0;
+       struct mpipe_data *md = container_of(ptp, struct mpipe_data, caps);
+       mutex_lock(&md->ptp_lock);
+       if (gxio_mpipe_adjust_timestamp(&md->context, delta))
+               ret = -EBUSY;
+       mutex_unlock(&md->ptp_lock);
+       return ret;
+}
 
-       if (dev != NULL) {
-               if (!info->napi_added) {
-                       netif_napi_add(dev, &info->napi,
-                                      tile_net_poll, TILE_NET_WEIGHT);
-                       info->napi_added = true;
-               }
-               if (!info->napi_enabled) {
-                       napi_enable(&info->napi);
-                       info->napi_enabled = true;
-               }
-               enable_percpu_irq(ingress_irq, 0);
-       } else {
-               disable_percpu_irq(ingress_irq);
-               if (info->napi_enabled) {
-                       napi_disable(&info->napi);
-                       info->napi_enabled = false;
-               }
-               /* FIXME: Drain the iqueue. */
-       }
+static int ptp_mpipe_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
+{
+       int ret = 0;
+       struct mpipe_data *md = container_of(ptp, struct mpipe_data, caps);
+       mutex_lock(&md->ptp_lock);
+       if (gxio_mpipe_get_timestamp(&md->context, ts))
+               ret = -EBUSY;
+       mutex_unlock(&md->ptp_lock);
+       return ret;
+}
+
+static int ptp_mpipe_settime(struct ptp_clock_info *ptp,
+                            const struct timespec *ts)
+{
+       int ret = 0;
+       struct mpipe_data *md = container_of(ptp, struct mpipe_data, caps);
+       mutex_lock(&md->ptp_lock);
+       if (gxio_mpipe_set_timestamp(&md->context, ts))
+               ret = -EBUSY;
+       mutex_unlock(&md->ptp_lock);
+       return ret;
+}
+
+static int ptp_mpipe_enable(struct ptp_clock_info *ptp,
+                           struct ptp_clock_request *request, int on)
+{
+       return -EOPNOTSUPP;
+}
+
+static struct ptp_clock_info ptp_mpipe_caps = {
+       .owner          = THIS_MODULE,
+       .name           = "mPIPE clock",
+       .max_adj        = 999999999,
+       .n_ext_ts       = 0,
+       .pps            = 0,
+       .adjfreq        = ptp_mpipe_adjfreq,
+       .adjtime        = ptp_mpipe_adjtime,
+       .gettime        = ptp_mpipe_gettime,
+       .settime        = ptp_mpipe_settime,
+       .enable         = ptp_mpipe_enable,
+};
+
+#endif /* CONFIG_PTP_1588_CLOCK_TILEGX */
+
+/* Sync mPIPE's timestamp up with Linux system time and register PTP clock. */
+static void register_ptp_clock(struct net_device *dev, struct mpipe_data *md)
+{
+#ifdef CONFIG_PTP_1588_CLOCK_TILEGX
+       struct timespec ts;
+
+       getnstimeofday(&ts);
+       gxio_mpipe_set_timestamp(&md->context, &ts);
+
+       mutex_init(&md->ptp_lock);
+       md->caps = ptp_mpipe_caps;
+       md->ptp_clock = ptp_clock_register(&md->caps, NULL);
+       if (IS_ERR(md->ptp_clock))
+               netdev_err(dev, "ptp_clock_register failed %ld\n",
+                          PTR_ERR(md->ptp_clock));
+#endif
+}
+
+/* Initialize PTP fields in a new device. */
+static void init_ptp_dev(struct tile_net_priv *priv)
+{
+#ifdef CONFIG_PTP_1588_CLOCK_TILEGX
+       priv->stamp_cfg.rx_filter = HWTSTAMP_FILTER_NONE;
+       priv->stamp_cfg.tx_type = HWTSTAMP_TX_OFF;
+#endif
+}
+
+/* Helper functions for "tile_net_update()". */
+static void enable_ingress_irq(void *irq)
+{
+       enable_percpu_irq((long)irq, 0);
+}
+
+static void disable_ingress_irq(void *irq)
+{
+       disable_percpu_irq((long)irq);
 }
 
 /* Helper function for tile_net_open() and tile_net_stop().
@@ -683,19 +929,22 @@ static int tile_net_update(struct net_device *dev)
 {
        static gxio_mpipe_rules_t rules;  /* too big to fit on the stack */
        bool saw_channel = false;
+       int instance = mpipe_instance(dev);
+       struct mpipe_data *md = &mpipe_data[instance];
        int channel;
        int rc;
        int cpu;
 
-       gxio_mpipe_rules_init(&rules, &context);
+       saw_channel = false;
+       gxio_mpipe_rules_init(&rules, &md->context);
 
        for (channel = 0; channel < TILE_NET_CHANNELS; channel++) {
-               if (tile_net_devs_for_channel[channel] == NULL)
+               if (md->tile_net_devs_for_channel[channel] == NULL)
                        continue;
                if (!saw_channel) {
                        saw_channel = true;
-                       gxio_mpipe_rules_begin(&rules, first_bucket,
-                                              num_buckets, NULL);
+                       gxio_mpipe_rules_begin(&rules, md->first_bucket,
+                                              md->num_buckets, NULL);
                        gxio_mpipe_rules_set_headroom(&rules, NET_IP_ALIGN);
                }
                gxio_mpipe_rules_add_channel(&rules, channel);
@@ -706,102 +955,150 @@ static int tile_net_update(struct net_device *dev)
         */
        rc = gxio_mpipe_rules_commit(&rules);
        if (rc != 0) {
-               netdev_warn(dev, "gxio_mpipe_rules_commit failed: %d\n", rc);
+               netdev_warn(dev, "gxio_mpipe_rules_commit: mpipe[%d] %d\n",
+                           instance, rc);
                return -EIO;
        }
 
-       /* Update all cpus, sequentially (to protect "netif_napi_add()"). */
-       for_each_online_cpu(cpu)
-               smp_call_function_single(cpu, tile_net_update_cpu,
-                                        (saw_channel ? dev : NULL), 1);
+       /* Update all cpus, sequentially (to protect "netif_napi_add()").
+        * We use on_each_cpu to handle the IPI mask or unmask.
+        */
+       if (!saw_channel)
+               on_each_cpu(disable_ingress_irq,
+                           (void *)(long)(md->ingress_irq), 1);
+       for_each_online_cpu(cpu) {
+               struct tile_net_info *info = &per_cpu(per_cpu_info, cpu);
+
+               if (!info->mpipe[instance].has_iqueue)
+                       continue;
+               if (saw_channel) {
+                       if (!info->mpipe[instance].napi_added) {
+                               netif_napi_add(dev, &info->mpipe[instance].napi,
+                                              tile_net_poll, TILE_NET_WEIGHT);
+                               info->mpipe[instance].napi_added = true;
+                       }
+                       if (!info->mpipe[instance].napi_enabled) {
+                               napi_enable(&info->mpipe[instance].napi);
+                               info->mpipe[instance].napi_enabled = true;
+                       }
+               } else {
+                       if (info->mpipe[instance].napi_enabled) {
+                               napi_disable(&info->mpipe[instance].napi);
+                               info->mpipe[instance].napi_enabled = false;
+                       }
+                       /* FIXME: Drain the iqueue. */
+               }
+       }
+       if (saw_channel)
+               on_each_cpu(enable_ingress_irq,
+                           (void *)(long)(md->ingress_irq), 1);
 
        /* HACK: Allow packets to flow in the simulator. */
        if (saw_channel)
-               sim_enable_mpipe_links(0, -1);
+               sim_enable_mpipe_links(instance, -1);
 
        return 0;
 }
 
-/* Allocate and initialize mpipe buffer stacks, and register them in
- * the mPIPE TLBs, for both small and large packet sizes.
- * This routine supports tile_net_init_mpipe(), below.
- */
-static int init_buffer_stacks(struct net_device *dev, int num_buffers)
+/* Initialize a buffer stack. */
+static int create_buffer_stack(struct net_device *dev,
+                              int kind, size_t num_buffers)
 {
        pte_t hash_pte = pte_set_home((pte_t) { 0 }, PAGE_HOME_HASH);
-       int rc;
+       int instance = mpipe_instance(dev);
+       struct mpipe_data *md = &mpipe_data[instance];
+       size_t needed = gxio_mpipe_calc_buffer_stack_bytes(num_buffers);
+       int stack_idx = md->first_buffer_stack + kind;
+       void *va;
+       int i, rc;
 
-       /* Compute stack bytes; we round up to 64KB and then use
-        * alloc_pages() so we get the required 64KB alignment as well.
+       /* Round up to 64KB and then use alloc_pages() so we get the
+        * required 64KB alignment.
         */
-       buffer_stack_size =
-               ALIGN(gxio_mpipe_calc_buffer_stack_bytes(num_buffers),
-                     64 * 1024);
-
-       /* Allocate two buffer stack indices. */
-       rc = gxio_mpipe_alloc_buffer_stacks(&context, 2, 0, 0);
-       if (rc < 0) {
-               netdev_err(dev, "gxio_mpipe_alloc_buffer_stacks failed: %d\n",
-                          rc);
-               return rc;
-       }
-       small_buffer_stack = rc;
-       large_buffer_stack = rc + 1;
+       md->buffer_stack_bytes[kind] =
+               ALIGN(needed, 64 * 1024);
 
-       /* Allocate the small memory stack. */
-       small_buffer_stack_va =
-               alloc_pages_exact(buffer_stack_size, GFP_KERNEL);
-       if (small_buffer_stack_va == NULL) {
+       va = alloc_pages_exact(md->buffer_stack_bytes[kind], GFP_KERNEL);
+       if (va == NULL) {
                netdev_err(dev,
-                          "Could not alloc %zd bytes for buffer stacks\n",
-                          buffer_stack_size);
+                          "Could not alloc %zd bytes for buffer stack %d\n",
+                          md->buffer_stack_bytes[kind], kind);
                return -ENOMEM;
        }
-       rc = gxio_mpipe_init_buffer_stack(&context, small_buffer_stack,
-                                         BUFFER_SIZE_SMALL_ENUM,
-                                         small_buffer_stack_va,
-                                         buffer_stack_size, 0);
+
+       /* Initialize the buffer stack. */
+       rc = gxio_mpipe_init_buffer_stack(&md->context, stack_idx,
+                                         buffer_size_enums[kind],  va,
+                                         md->buffer_stack_bytes[kind], 0);
        if (rc != 0) {
-               netdev_err(dev, "gxio_mpipe_init_buffer_stack: %d\n", rc);
+               netdev_err(dev, "gxio_mpipe_init_buffer_stack: mpipe[%d] %d\n",
+                          instance, rc);
+               free_pages_exact(va, md->buffer_stack_bytes[kind]);
                return rc;
        }
-       rc = gxio_mpipe_register_client_memory(&context, small_buffer_stack,
+
+       md->buffer_stack_vas[kind] = va;
+
+       rc = gxio_mpipe_register_client_memory(&md->context, stack_idx,
                                               hash_pte, 0);
        if (rc != 0) {
                netdev_err(dev,
-                          "gxio_mpipe_register_buffer_memory failed: %d\n",
-                          rc);
+                          "gxio_mpipe_register_client_memory: mpipe[%d] %d\n",
+                          instance, rc);
                return rc;
        }
 
-       /* Allocate the large buffer stack. */
-       large_buffer_stack_va =
-               alloc_pages_exact(buffer_stack_size, GFP_KERNEL);
-       if (large_buffer_stack_va == NULL) {
-               netdev_err(dev,
-                          "Could not alloc %zd bytes for buffer stacks\n",
-                          buffer_stack_size);
-               return -ENOMEM;
-       }
-       rc = gxio_mpipe_init_buffer_stack(&context, large_buffer_stack,
-                                         BUFFER_SIZE_LARGE_ENUM,
-                                         large_buffer_stack_va,
-                                         buffer_stack_size, 0);
-       if (rc != 0) {
-               netdev_err(dev, "gxio_mpipe_init_buffer_stack failed: %d\n",
-                          rc);
-               return rc;
+       /* Provide initial buffers. */
+       for (i = 0; i < num_buffers; i++) {
+               if (!tile_net_provide_buffer(instance, kind)) {
+                       netdev_err(dev, "Cannot allocate initial sk_bufs!\n");
+                       return -ENOMEM;
+               }
        }
-       rc = gxio_mpipe_register_client_memory(&context, large_buffer_stack,
-                                              hash_pte, 0);
-       if (rc != 0) {
+
+       return 0;
+}
+
+/* Allocate and initialize mpipe buffer stacks, and register them in
+ * the mPIPE TLBs, for small, large, and (possibly) jumbo packet sizes.
+ * This routine supports tile_net_init_mpipe(), below.
+ */
+static int init_buffer_stacks(struct net_device *dev,
+                             int network_cpus_count)
+{
+       int num_kinds = MAX_KINDS - (jumbo_num == 0);
+       size_t num_buffers;
+       int rc;
+       int instance = mpipe_instance(dev);
+       struct mpipe_data *md = &mpipe_data[instance];
+
+       /* Allocate the buffer stacks. */
+       rc = gxio_mpipe_alloc_buffer_stacks(&md->context, num_kinds, 0, 0);
+       if (rc < 0) {
                netdev_err(dev,
-                          "gxio_mpipe_register_buffer_memory failed: %d\n",
-                          rc);
+                          "gxio_mpipe_alloc_buffer_stacks: mpipe[%d] %d\n",
+                          instance, rc);
                return rc;
        }
+       md->first_buffer_stack = rc;
 
-       return 0;
+       /* Enough small/large buffers to (normally) avoid buffer errors. */
+       num_buffers =
+               network_cpus_count * (IQUEUE_ENTRIES + TILE_NET_BATCH);
+
+       /* Allocate the small memory stack. */
+       if (rc >= 0)
+               rc = create_buffer_stack(dev, 0, num_buffers);
+
+       /* Allocate the large buffer stack. */
+       if (rc >= 0)
+               rc = create_buffer_stack(dev, 1, num_buffers);
+
+       /* Allocate the jumbo buffer stack if needed. */
+       if (rc >= 0 && jumbo_num != 0)
+               rc = create_buffer_stack(dev, 2, jumbo_num);
+
+       return rc;
 }
 
 /* Allocate per-cpu resources (memory for completions and idescs).
@@ -812,6 +1109,8 @@ static int alloc_percpu_mpipe_resources(struct net_device *dev,
 {
        struct tile_net_info *info = &per_cpu(per_cpu_info, cpu);
        int order, i, rc;
+       int instance = mpipe_instance(dev);
+       struct mpipe_data *md = &mpipe_data[instance];
        struct page *page;
        void *addr;
 
@@ -826,7 +1125,7 @@ static int alloc_percpu_mpipe_resources(struct net_device *dev,
        addr = pfn_to_kaddr(page_to_pfn(page));
        memset(addr, 0, COMPS_SIZE);
        for (i = 0; i < TILE_NET_CHANNELS; i++)
-               info->comps_for_echannel[i] =
+               info->mpipe[instance].comps_for_echannel[i] =
                        addr + i * sizeof(struct tile_net_comps);
 
        /* If this is a network cpu, create an iqueue. */
@@ -840,14 +1139,15 @@ static int alloc_percpu_mpipe_resources(struct net_device *dev,
                        return -ENOMEM;
                }
                addr = pfn_to_kaddr(page_to_pfn(page));
-               rc = gxio_mpipe_iqueue_init(&info->iqueue, &context, ring++,
-                                           addr, NOTIF_RING_SIZE, 0);
+               rc = gxio_mpipe_iqueue_init(&info->mpipe[instance].iqueue,
+                                           &md->context, ring++, addr,
+                                           NOTIF_RING_SIZE, 0);
                if (rc < 0) {
                        netdev_err(dev,
                                   "gxio_mpipe_iqueue_init failed: %d\n", rc);
                        return rc;
                }
-               info->has_iqueue = true;
+               info->mpipe[instance].has_iqueue = true;
        }
 
        return ring;
@@ -860,40 +1160,41 @@ static int init_notif_group_and_buckets(struct net_device *dev,
                                        int ring, int network_cpus_count)
 {
        int group, rc;
+       int instance = mpipe_instance(dev);
+       struct mpipe_data *md = &mpipe_data[instance];
 
        /* Allocate one NotifGroup. */
-       rc = gxio_mpipe_alloc_notif_groups(&context, 1, 0, 0);
+       rc = gxio_mpipe_alloc_notif_groups(&md->context, 1, 0, 0);
        if (rc < 0) {
-               netdev_err(dev, "gxio_mpipe_alloc_notif_groups failed: %d\n",
-                          rc);
+               netdev_err(dev, "gxio_mpipe_alloc_notif_groups: mpipe[%d] %d\n",
+                          instance, rc);
                return rc;
        }
        group = rc;
 
        /* Initialize global num_buckets value. */
        if (network_cpus_count > 4)
-               num_buckets = 256;
+               md->num_buckets = 256;
        else if (network_cpus_count > 1)
-               num_buckets = 16;
+               md->num_buckets = 16;
 
        /* Allocate some buckets, and set global first_bucket value. */
-       rc = gxio_mpipe_alloc_buckets(&context, num_buckets, 0, 0);
+       rc = gxio_mpipe_alloc_buckets(&md->context, md->num_buckets, 0, 0);
        if (rc < 0) {
-               netdev_err(dev, "gxio_mpipe_alloc_buckets failed: %d\n", rc);
+               netdev_err(dev, "gxio_mpipe_alloc_buckets: mpipe[%d] %d\n",
+                          instance, rc);
                return rc;
        }
-       first_bucket = rc;
+       md->first_bucket = rc;
 
        /* Init group and buckets. */
        rc = gxio_mpipe_init_notif_group_and_buckets(
-               &context, group, ring, network_cpus_count,
-               first_bucket, num_buckets,
+               &md->context, group, ring, network_cpus_count,
+               md->first_bucket, md->num_buckets,
                GXIO_MPIPE_BUCKET_STICKY_FLOW_LOCALITY);
        if (rc != 0) {
-               netdev_err(
-                       dev,
-                       "gxio_mpipe_init_notif_group_and_buckets failed: %d\n",
-                       rc);
+               netdev_err(dev, "gxio_mpipe_init_notif_group_and_buckets: "
+                          "mpipe[%d] %d\n", instance, rc);
                return rc;
        }
 
@@ -907,30 +1208,39 @@ static int init_notif_group_and_buckets(struct net_device *dev,
  */
 static int tile_net_setup_interrupts(struct net_device *dev)
 {
-       int cpu, rc;
+       int cpu, rc, irq;
+       int instance = mpipe_instance(dev);
+       struct mpipe_data *md = &mpipe_data[instance];
+
+       irq = md->ingress_irq;
+       if (irq < 0) {
+               irq = create_irq();
+               if (irq < 0) {
+                       netdev_err(dev,
+                                  "create_irq failed: mpipe[%d] %d\n",
+                                  instance, irq);
+                       return irq;
+               }
+               tile_irq_activate(irq, TILE_IRQ_PERCPU);
 
-       rc = create_irq();
-       if (rc < 0) {
-               netdev_err(dev, "create_irq failed: %d\n", rc);
-               return rc;
-       }
-       ingress_irq = rc;
-       tile_irq_activate(ingress_irq, TILE_IRQ_PERCPU);
-       rc = request_irq(ingress_irq, tile_net_handle_ingress_irq,
-                        0, "tile_net", NULL);
-       if (rc != 0) {
-               netdev_err(dev, "request_irq failed: %d\n", rc);
-               destroy_irq(ingress_irq);
-               ingress_irq = -1;
-               return rc;
+               rc = request_irq(irq, tile_net_handle_ingress_irq,
+                                0, "tile_net", (void *)((uint64_t)instance));
+
+               if (rc != 0) {
+                       netdev_err(dev, "request_irq failed: mpipe[%d] %d\n",
+                                  instance, rc);
+                       destroy_irq(irq);
+                       return rc;
+               }
+               md->ingress_irq = irq;
        }
 
        for_each_online_cpu(cpu) {
                struct tile_net_info *info = &per_cpu(per_cpu_info, cpu);
-               if (info->has_iqueue) {
-                       gxio_mpipe_request_notif_ring_interrupt(
-                               &context, cpu_x(cpu), cpu_y(cpu),
-                               KERNEL_PL, ingress_irq, info->iqueue.ring);
+               if (info->mpipe[instance].has_iqueue) {
+                       gxio_mpipe_request_notif_ring_interrupt(&md->context,
+                               cpu_x(cpu), cpu_y(cpu), KERNEL_PL, irq,
+                               info->mpipe[instance].iqueue.ring);
                }
        }
 
@@ -938,39 +1248,45 @@ static int tile_net_setup_interrupts(struct net_device *dev)
 }
 
 /* Undo any state set up partially by a failed call to tile_net_init_mpipe. */
-static void tile_net_init_mpipe_fail(void)
+static void tile_net_init_mpipe_fail(int instance)
 {
-       int cpu;
+       int kind, cpu;
+       struct mpipe_data *md = &mpipe_data[instance];
 
        /* Do cleanups that require the mpipe context first. */
-       if (small_buffer_stack >= 0)
-               tile_net_pop_all_buffers(small_buffer_stack);
-       if (large_buffer_stack >= 0)
-               tile_net_pop_all_buffers(large_buffer_stack);
+       for (kind = 0; kind < MAX_KINDS; kind++) {
+               if (md->buffer_stack_vas[kind] != NULL) {
+                       tile_net_pop_all_buffers(instance,
+                                                md->first_buffer_stack +
+                                                kind);
+               }
+       }
 
        /* Destroy mpipe context so the hardware no longer owns any memory. */
-       gxio_mpipe_destroy(&context);
+       gxio_mpipe_destroy(&md->context);
 
        for_each_online_cpu(cpu) {
                struct tile_net_info *info = &per_cpu(per_cpu_info, cpu);
-               free_pages((unsigned long)(info->comps_for_echannel[0]),
-                          get_order(COMPS_SIZE));
-               info->comps_for_echannel[0] = NULL;
-               free_pages((unsigned long)(info->iqueue.idescs),
+               free_pages(
+                       (unsigned long)(
+                               info->mpipe[instance].comps_for_echannel[0]),
+                       get_order(COMPS_SIZE));
+               info->mpipe[instance].comps_for_echannel[0] = NULL;
+               free_pages((unsigned long)(info->mpipe[instance].iqueue.idescs),
                           get_order(NOTIF_RING_SIZE));
-               info->iqueue.idescs = NULL;
+               info->mpipe[instance].iqueue.idescs = NULL;
        }
 
-       if (small_buffer_stack_va)
-               free_pages_exact(small_buffer_stack_va, buffer_stack_size);
-       if (large_buffer_stack_va)
-               free_pages_exact(large_buffer_stack_va, buffer_stack_size);
+       for (kind = 0; kind < MAX_KINDS; kind++) {
+               if (md->buffer_stack_vas[kind] != NULL) {
+                       free_pages_exact(md->buffer_stack_vas[kind],
+                                        md->buffer_stack_bytes[kind]);
+                       md->buffer_stack_vas[kind] = NULL;
+               }
+       }
 
-       small_buffer_stack_va = NULL;
-       large_buffer_stack_va = NULL;
-       large_buffer_stack = -1;
-       small_buffer_stack = -1;
-       first_bucket = -1;
+       md->first_buffer_stack = -1;
+       md->first_bucket = -1;
 }
 
 /* The first time any tilegx network device is opened, we initialize
@@ -984,9 +1300,11 @@ static void tile_net_init_mpipe_fail(void)
  */
 static int tile_net_init_mpipe(struct net_device *dev)
 {
-       int i, num_buffers, rc;
+       int rc;
        int cpu;
        int first_ring, ring;
+       int instance = mpipe_instance(dev);
+       struct mpipe_data *md = &mpipe_data[instance];
        int network_cpus_count = cpus_weight(network_cpus_map);
 
        if (!hash_default) {
@@ -994,36 +1312,21 @@ static int tile_net_init_mpipe(struct net_device *dev)
                return -EIO;
        }
 
-       rc = gxio_mpipe_init(&context, 0);
+       rc = gxio_mpipe_init(&md->context, instance);
        if (rc != 0) {
-               netdev_err(dev, "gxio_mpipe_init failed: %d\n", rc);
+               netdev_err(dev, "gxio_mpipe_init: mpipe[%d] %d\n",
+                          instance, rc);
                return -EIO;
        }
 
        /* Set up the buffer stacks. */
-       num_buffers =
-               network_cpus_count * (IQUEUE_ENTRIES + TILE_NET_BATCH);
-       rc = init_buffer_stacks(dev, num_buffers);
+       rc = init_buffer_stacks(dev, network_cpus_count);
        if (rc != 0)
                goto fail;
 
-       /* Provide initial buffers. */
-       rc = -ENOMEM;
-       for (i = 0; i < num_buffers; i++) {
-               if (!tile_net_provide_buffer(true)) {
-                       netdev_err(dev, "Cannot allocate initial sk_bufs!\n");
-                       goto fail;
-               }
-       }
-       for (i = 0; i < num_buffers; i++) {
-               if (!tile_net_provide_buffer(false)) {
-                       netdev_err(dev, "Cannot allocate initial sk_bufs!\n");
-                       goto fail;
-               }
-       }
-
        /* Allocate one NotifRing for each network cpu. */
-       rc = gxio_mpipe_alloc_notif_rings(&context, network_cpus_count, 0, 0);
+       rc = gxio_mpipe_alloc_notif_rings(&md->context,
+                                         network_cpus_count, 0, 0);
        if (rc < 0) {
                netdev_err(dev, "gxio_mpipe_alloc_notif_rings failed %d\n",
                           rc);
@@ -1050,10 +1353,13 @@ static int tile_net_init_mpipe(struct net_device *dev)
        if (rc != 0)
                goto fail;
 
+       /* Register PTP clock and set mPIPE timestamp, if configured. */
+       register_ptp_clock(dev, md);
+
        return 0;
 
 fail:
-       tile_net_init_mpipe_fail();
+       tile_net_init_mpipe_fail(instance);
        return rc;
 }
 
@@ -1063,17 +1369,19 @@ fail:
  */
 static int tile_net_init_egress(struct net_device *dev, int echannel)
 {
+       static int ering = -1;
        struct page *headers_page, *edescs_page, *equeue_page;
        gxio_mpipe_edesc_t *edescs;
        gxio_mpipe_equeue_t *equeue;
        unsigned char *headers;
        int headers_order, edescs_order, equeue_order;
        size_t edescs_size;
-       int edma;
        int rc = -ENOMEM;
+       int instance = mpipe_instance(dev);
+       struct mpipe_data *md = &mpipe_data[instance];
 
        /* Only initialize once. */
-       if (egress_for_echannel[echannel].equeue != NULL)
+       if (md->egress_for_echannel[echannel].equeue != NULL)
                return 0;
 
        /* Allocate memory for the "headers". */
@@ -1110,28 +1418,41 @@ static int tile_net_init_egress(struct net_device *dev, int echannel)
        }
        equeue = pfn_to_kaddr(page_to_pfn(equeue_page));
 
-       /* Allocate an edma ring.  Note that in practice this can't
-        * fail, which is good, because we will leak an edma ring if so.
-        */
-       rc = gxio_mpipe_alloc_edma_rings(&context, 1, 0, 0);
-       if (rc < 0) {
-               netdev_warn(dev, "gxio_mpipe_alloc_edma_rings failed: %d\n",
-                           rc);
-               goto fail_equeue;
+       /* Allocate an edma ring (using a one entry "free list"). */
+       if (ering < 0) {
+               rc = gxio_mpipe_alloc_edma_rings(&md->context, 1, 0, 0);
+               if (rc < 0) {
+                       netdev_warn(dev, "gxio_mpipe_alloc_edma_rings: "
+                                   "mpipe[%d] %d\n", instance, rc);
+                       goto fail_equeue;
+               }
+               ering = rc;
        }
-       edma = rc;
 
        /* Initialize the equeue. */
-       rc = gxio_mpipe_equeue_init(equeue, &context, edma, echannel,
+       rc = gxio_mpipe_equeue_init(equeue, &md->context, ering, echannel,
                                    edescs, edescs_size, 0);
        if (rc != 0) {
-               netdev_err(dev, "gxio_mpipe_equeue_init failed: %d\n", rc);
+               netdev_err(dev, "gxio_mpipe_equeue_init: mpipe[%d] %d\n",
+                          instance, rc);
                goto fail_equeue;
        }
 
+       /* Don't reuse the ering later. */
+       ering = -1;
+
+       if (jumbo_num != 0) {
+               /* Make sure "jumbo" packets can be egressed safely. */
+               if (gxio_mpipe_equeue_set_snf_size(equeue, 10368) < 0) {
+                       /* ISSUE: There is no "gxio_mpipe_equeue_destroy()". */
+                       netdev_warn(dev, "Jumbo packets may not be egressed"
+                                   " properly on channel %d\n", echannel);
+               }
+       }
+
        /* Done. */
-       egress_for_echannel[echannel].equeue = equeue;
-       egress_for_echannel[echannel].headers = headers;
+       md->egress_for_echannel[echannel].equeue = equeue;
+       md->egress_for_echannel[echannel].headers = headers;
        return 0;
 
 fail_equeue:
@@ -1151,11 +1472,25 @@ fail:
 static int tile_net_link_open(struct net_device *dev, gxio_mpipe_link_t *link,
                              const char *link_name)
 {
-       int rc = gxio_mpipe_link_open(link, &context, link_name, 0);
+       int instance = mpipe_instance(dev);
+       struct mpipe_data *md = &mpipe_data[instance];
+       int rc = gxio_mpipe_link_open(link, &md->context, link_name, 0);
        if (rc < 0) {
-               netdev_err(dev, "Failed to open '%s'\n", link_name);
+               netdev_err(dev, "Failed to open '%s', mpipe[%d], %d\n",
+                          link_name, instance, rc);
                return rc;
        }
+       if (jumbo_num != 0) {
+               u32 attr = GXIO_MPIPE_LINK_RECEIVE_JUMBO;
+               rc = gxio_mpipe_link_set_attr(link, attr, 1);
+               if (rc != 0) {
+                       netdev_err(dev,
+                                  "Cannot receive jumbo packets on '%s'\n",
+                                  link_name);
+                       gxio_mpipe_link_close(link);
+                       return rc;
+               }
+       }
        rc = gxio_mpipe_link_channel(link);
        if (rc < 0 || rc >= TILE_NET_CHANNELS) {
                netdev_err(dev, "gxio_mpipe_link_channel bad value: %d\n", rc);
@@ -1169,12 +1504,21 @@ static int tile_net_link_open(struct net_device *dev, gxio_mpipe_link_t *link,
 static int tile_net_open(struct net_device *dev)
 {
        struct tile_net_priv *priv = netdev_priv(dev);
-       int cpu, rc;
+       int cpu, rc, instance;
 
        mutex_lock(&tile_net_devs_for_channel_mutex);
 
-       /* Do one-time initialization the first time any device is opened. */
-       if (ingress_irq < 0) {
+       /* Get the instance info. */
+       rc = gxio_mpipe_link_instance(dev->name);
+       if (rc < 0 || rc >= NR_MPIPE_MAX)
+               return -EIO;
+
+       priv->instance = rc;
+       instance = rc;
+       if (!mpipe_data[rc].context.mmio_fast_base) {
+               /* Do one-time initialization per instance the first time
+                * any device is opened.
+                */
                rc = tile_net_init_mpipe(dev);
                if (rc != 0)
                        goto fail;
@@ -1205,7 +1549,7 @@ static int tile_net_open(struct net_device *dev)
        if (rc != 0)
                goto fail;
 
-       tile_net_devs_for_channel[priv->channel] = dev;
+       mpipe_data[instance].tile_net_devs_for_channel[priv->channel] = dev;
 
        rc = tile_net_update(dev);
        if (rc != 0)
@@ -1217,7 +1561,7 @@ static int tile_net_open(struct net_device *dev)
        for_each_online_cpu(cpu) {
                struct tile_net_info *info = &per_cpu(per_cpu_info, cpu);
                struct tile_net_tx_wake *tx_wake =
-                       &info->tx_wake[priv->echannel];
+                       &info->mpipe[instance].tx_wake[priv->echannel];
 
                hrtimer_init(&tx_wake->timer, CLOCK_MONOTONIC,
                             HRTIMER_MODE_REL);
@@ -1243,7 +1587,7 @@ fail:
                priv->channel = -1;
        }
        priv->echannel = -1;
-       tile_net_devs_for_channel[priv->channel] = NULL;
+       mpipe_data[instance].tile_net_devs_for_channel[priv->channel] = NULL;
        mutex_unlock(&tile_net_devs_for_channel_mutex);
 
        /* Don't return raw gxio error codes to generic Linux. */
@@ -1255,18 +1599,20 @@ static int tile_net_stop(struct net_device *dev)
 {
        struct tile_net_priv *priv = netdev_priv(dev);
        int cpu;
+       int instance = priv->instance;
+       struct mpipe_data *md = &mpipe_data[instance];
 
        for_each_online_cpu(cpu) {
                struct tile_net_info *info = &per_cpu(per_cpu_info, cpu);
                struct tile_net_tx_wake *tx_wake =
-                       &info->tx_wake[priv->echannel];
+                       &info->mpipe[instance].tx_wake[priv->echannel];
 
                hrtimer_cancel(&tx_wake->timer);
                netif_stop_subqueue(dev, cpu);
        }
 
        mutex_lock(&tile_net_devs_for_channel_mutex);
-       tile_net_devs_for_channel[priv->channel] = NULL;
+       md->tile_net_devs_for_channel[priv->channel] = NULL;
        (void)tile_net_update(dev);
        if (priv->loopify_channel >= 0) {
                if (gxio_mpipe_link_close(&priv->loopify_link) != 0)
@@ -1374,20 +1720,20 @@ static int tso_count_edescs(struct sk_buff *skb)
        return num_edescs;
 }
 
-/* Prepare modified copies of the skbuff headers.
- * FIXME: add support for IPv6.
- */
+/* Prepare modified copies of the skbuff headers. */
 static void tso_headers_prepare(struct sk_buff *skb, unsigned char *headers,
                                s64 slot)
 {
        struct skb_shared_info *sh = skb_shinfo(skb);
        struct iphdr *ih;
+       struct ipv6hdr *ih6;
        struct tcphdr *th;
        unsigned int sh_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
        unsigned int data_len = skb->len - sh_len;
        unsigned char *data = skb->data;
        unsigned int ih_off, th_off, p_len;
        unsigned int isum_seed, tsum_seed, id, seq;
+       int is_ipv6;
        long f_id = -1;    /* id of the current fragment */
        long f_size = skb_headlen(skb) - sh_len;  /* current fragment size */
        long f_used = 0;  /* bytes used from the current fragment */
@@ -1395,18 +1741,24 @@ static void tso_headers_prepare(struct sk_buff *skb, unsigned char *headers,
        int segment;
 
        /* Locate original headers and compute various lengths. */
-       ih = ip_hdr(skb);
+       is_ipv6 = skb_is_gso_v6(skb);
+       if (is_ipv6) {
+               ih6 = ipv6_hdr(skb);
+               ih_off = skb_network_offset(skb);
+       } else {
+               ih = ip_hdr(skb);
+               ih_off = skb_network_offset(skb);
+               isum_seed = ((0xFFFF - ih->check) +
+                            (0xFFFF - ih->tot_len) +
+                            (0xFFFF - ih->id));
+               id = ntohs(ih->id);
+       }
+
        th = tcp_hdr(skb);
-       ih_off = skb_network_offset(skb);
        th_off = skb_transport_offset(skb);
        p_len = sh->gso_size;
 
-       /* Set up seed values for IP and TCP csum and initialize id and seq. */
-       isum_seed = ((0xFFFF - ih->check) +
-                    (0xFFFF - ih->tot_len) +
-                    (0xFFFF - ih->id));
        tsum_seed = th->check + (0xFFFF ^ htons(skb->len));
-       id = ntohs(ih->id);
        seq = ntohl(th->seq);
 
        /* Prepare all the headers. */
@@ -1420,11 +1772,17 @@ static void tso_headers_prepare(struct sk_buff *skb, unsigned char *headers,
                memcpy(buf, data, sh_len);
 
                /* Update copied ip header. */
-               ih = (struct iphdr *)(buf + ih_off);
-               ih->tot_len = htons(sh_len + p_len - ih_off);
-               ih->id = htons(id);
-               ih->check = csum_long(isum_seed + ih->tot_len +
-                                     ih->id) ^ 0xffff;
+               if (is_ipv6) {
+                       ih6 = (struct ipv6hdr *)(buf + ih_off);
+                       ih6->payload_len = htons(sh_len + p_len - ih_off -
+                                                sizeof(*ih6));
+               } else {
+                       ih = (struct iphdr *)(buf + ih_off);
+                       ih->tot_len = htons(sh_len + p_len - ih_off);
+                       ih->id = htons(id);
+                       ih->check = csum_long(isum_seed + ih->tot_len +
+                                             ih->id) ^ 0xffff;
+               }
 
                /* Update copied tcp header. */
                th = (struct tcphdr *)(buf + th_off);
@@ -1475,8 +1833,9 @@ static void tso_headers_prepare(struct sk_buff *skb, unsigned char *headers,
 static void tso_egress(struct net_device *dev, gxio_mpipe_equeue_t *equeue,
                       struct sk_buff *skb, unsigned char *headers, s64 slot)
 {
-       struct tile_net_priv *priv = netdev_priv(dev);
        struct skb_shared_info *sh = skb_shinfo(skb);
+       int instance = mpipe_instance(dev);
+       struct mpipe_data *md = &mpipe_data[instance];
        unsigned int sh_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
        unsigned int data_len = skb->len - sh_len;
        unsigned int p_len = sh->gso_size;
@@ -1499,8 +1858,8 @@ static void tso_egress(struct net_device *dev, gxio_mpipe_equeue_t *equeue,
        edesc_head.xfer_size = sh_len;
 
        /* This is only used to specify the TLB. */
-       edesc_head.stack_idx = large_buffer_stack;
-       edesc_body.stack_idx = large_buffer_stack;
+       edesc_head.stack_idx = md->first_buffer_stack;
+       edesc_body.stack_idx = md->first_buffer_stack;
 
        /* Egress all the edescs. */
        for (segment = 0; segment < sh->gso_segs; segment++) {
@@ -1553,8 +1912,8 @@ static void tso_egress(struct net_device *dev, gxio_mpipe_equeue_t *equeue,
        }
 
        /* Update stats. */
-       tile_net_stats_add(tx_packets, &priv->stats.tx_packets);
-       tile_net_stats_add(tx_bytes, &priv->stats.tx_bytes);
+       tile_net_stats_add(tx_packets, &dev->stats.tx_packets);
+       tile_net_stats_add(tx_bytes, &dev->stats.tx_bytes);
 }
 
 /* Do "TSO" handling for egress.
@@ -1575,8 +1934,11 @@ static int tile_net_tx_tso(struct sk_buff *skb, struct net_device *dev)
        struct tile_net_info *info = &__get_cpu_var(per_cpu_info);
        struct tile_net_priv *priv = netdev_priv(dev);
        int channel = priv->echannel;
-       struct tile_net_egress *egress = &egress_for_echannel[channel];
-       struct tile_net_comps *comps = info->comps_for_echannel[channel];
+       int instance = priv->instance;
+       struct mpipe_data *md = &mpipe_data[instance];
+       struct tile_net_egress *egress = &md->egress_for_echannel[channel];
+       struct tile_net_comps *comps =
+               info->mpipe[instance].comps_for_echannel[channel];
        gxio_mpipe_equeue_t *equeue = egress->equeue;
        unsigned long irqflags;
        int num_edescs;
@@ -1640,10 +2002,13 @@ static int tile_net_tx(struct sk_buff *skb, struct net_device *dev)
 {
        struct tile_net_info *info = &__get_cpu_var(per_cpu_info);
        struct tile_net_priv *priv = netdev_priv(dev);
-       struct tile_net_egress *egress = &egress_for_echannel[priv->echannel];
+       int instance = priv->instance;
+       struct mpipe_data *md = &mpipe_data[instance];
+       struct tile_net_egress *egress =
+               &md->egress_for_echannel[priv->echannel];
        gxio_mpipe_equeue_t *equeue = egress->equeue;
        struct tile_net_comps *comps =
-               info->comps_for_echannel[priv->echannel];
+               info->mpipe[instance].comps_for_echannel[priv->echannel];
        unsigned int len = skb->len;
        unsigned char *data = skb->data;
        unsigned int num_edescs;
@@ -1660,7 +2025,7 @@ static int tile_net_tx(struct sk_buff *skb, struct net_device *dev)
        num_edescs = tile_net_tx_frags(frags, skb, data, skb_headlen(skb));
 
        /* This is only used to specify the TLB. */
-       edesc.stack_idx = large_buffer_stack;
+       edesc.stack_idx = md->first_buffer_stack;
 
        /* Prepare the edescs. */
        for (i = 0; i < num_edescs; i++) {
@@ -1693,13 +2058,16 @@ static int tile_net_tx(struct sk_buff *skb, struct net_device *dev)
        for (i = 0; i < num_edescs; i++)
                gxio_mpipe_equeue_put_at(equeue, edescs[i], slot++);
 
+       /* Store TX timestamp if needed. */
+       tile_tx_timestamp(skb, instance);
+
        /* Add a completion record. */
        add_comp(equeue, comps, slot - 1, skb);
 
        /* NOTE: Use ETH_ZLEN for short packets (e.g. 42 < 60). */
-       tile_net_stats_add(1, &priv->stats.tx_packets);
+       tile_net_stats_add(1, &dev->stats.tx_packets);
        tile_net_stats_add(max_t(unsigned int, len, ETH_ZLEN),
-                          &priv->stats.tx_bytes);
+                          &dev->stats.tx_bytes);
 
        local_irq_restore(irqflags);
 
@@ -1727,20 +2095,18 @@ static void tile_net_tx_timeout(struct net_device *dev)
 /* Ioctl commands. */
 static int tile_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-       return -EOPNOTSUPP;
-}
+       if (cmd == SIOCSHWTSTAMP)
+               return tile_hwtstamp_ioctl(dev, rq, cmd);
 
-/* Get system network statistics for device. */
-static struct net_device_stats *tile_net_get_stats(struct net_device *dev)
-{
-       struct tile_net_priv *priv = netdev_priv(dev);
-       return &priv->stats;
+       return -EOPNOTSUPP;
 }
 
 /* Change the MTU. */
 static int tile_net_change_mtu(struct net_device *dev, int new_mtu)
 {
-       if ((new_mtu < 68) || (new_mtu > 1500))
+       if (new_mtu < 68)
+               return -EINVAL;
+       if (new_mtu > ((jumbo_num != 0) ? 9000 : 1500))
                return -EINVAL;
        dev->mtu = new_mtu;
        return 0;
@@ -1772,9 +2138,13 @@ static int tile_net_set_mac_address(struct net_device *dev, void *p)
  */
 static void tile_net_netpoll(struct net_device *dev)
 {
-       disable_percpu_irq(ingress_irq);
-       tile_net_handle_ingress_irq(ingress_irq, NULL);
-       enable_percpu_irq(ingress_irq, 0);
+       int instance = mpipe_instance(dev);
+       struct tile_net_info *info = &__get_cpu_var(per_cpu_info);
+       struct mpipe_data *md = &mpipe_data[instance];
+
+       disable_percpu_irq(md->ingress_irq);
+       napi_schedule(&info->mpipe[instance].napi);
+       enable_percpu_irq(md->ingress_irq, 0);
 }
 #endif
 
@@ -1784,7 +2154,6 @@ static const struct net_device_ops tile_net_ops = {
        .ndo_start_xmit = tile_net_tx,
        .ndo_select_queue = tile_net_select_queue,
        .ndo_do_ioctl = tile_net_ioctl,
-       .ndo_get_stats = tile_net_get_stats,
        .ndo_change_mtu = tile_net_change_mtu,
        .ndo_tx_timeout = tile_net_tx_timeout,
        .ndo_set_mac_address = tile_net_set_mac_address,
@@ -1800,14 +2169,21 @@ static const struct net_device_ops tile_net_ops = {
  */
 static void tile_net_setup(struct net_device *dev)
 {
+       netdev_features_t features = 0;
+
        ether_setup(dev);
        dev->netdev_ops = &tile_net_ops;
        dev->watchdog_timeo = TILE_NET_TIMEOUT;
-       dev->features |= NETIF_F_LLTX;
-       dev->features |= NETIF_F_HW_CSUM;
-       dev->features |= NETIF_F_SG;
-       dev->features |= NETIF_F_TSO;
        dev->mtu = 1500;
+
+       features |= NETIF_F_HW_CSUM;
+       features |= NETIF_F_SG;
+       features |= NETIF_F_TSO;
+       features |= NETIF_F_TSO6;
+
+       dev->hw_features   |= features;
+       dev->vlan_features |= features;
+       dev->features      |= features;
 }
 
 /* Allocate the device structure, register the device, and obtain the
@@ -1842,6 +2218,7 @@ static void tile_net_dev_init(const char *name, const uint8_t *mac)
        priv->channel = -1;
        priv->loopify_channel = -1;
        priv->echannel = -1;
+       init_ptp_dev(priv);
 
        /* Get the MAC address and set it in the device struct; this must
         * be done before the device is opened.  If the MAC is all zeroes,
@@ -1871,9 +2248,12 @@ static void tile_net_init_module_percpu(void *unused)
 {
        struct tile_net_info *info = &__get_cpu_var(per_cpu_info);
        int my_cpu = smp_processor_id();
+       int instance;
 
-       info->has_iqueue = false;
-
+       for (instance = 0; instance < NR_MPIPE_MAX; instance++) {
+               info->mpipe[instance].has_iqueue = false;
+               info->mpipe[instance].instance = instance;
+       }
        info->my_cpu = my_cpu;
 
        /* Initialize the egress timer. */
@@ -1890,6 +2270,8 @@ static int __init tile_net_init_module(void)
 
        pr_info("Tilera Network Driver\n");
 
+       BUILD_BUG_ON(NR_MPIPE_MAX != 2);
+
        mutex_init(&tile_net_devs_for_channel_mutex);
 
        /* Initialize each CPU. */
index 36435499814b78d34020503caa41fdb00d2cd57f..106be47716e796105012efd7b8d644929faaccef 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/in6.h>
 #include <linux/timer.h>
 #include <linux/io.h>
+#include <linux/u64_stats_sync.h>
 #include <asm/checksum.h>
 #include <asm/homecache.h>
 
 /* ISSUE: This has not been thoroughly tested (except at 1500). */
 #define TILE_NET_MTU 1500
 
-/* HACK: Define to support GSO. */
-/* ISSUE: This may actually hurt performance of the TCP blaster. */
-/* #define TILE_NET_GSO */
-
-/* Define this to collapse "duplicate" acks. */
-/* #define IGNORE_DUP_ACKS */
-
 /* HACK: Define this to verify incoming packets. */
 /* #define TILE_NET_VERIFY_INGRESS */
 
@@ -156,10 +150,13 @@ struct tile_netio_queue {
  * Statistics counters for a specific cpu and device.
  */
 struct tile_net_stats_t {
-       u32 rx_packets;
-       u32 rx_bytes;
-       u32 tx_packets;
-       u32 tx_bytes;
+       struct u64_stats_sync syncp;
+       u64 rx_packets;         /* total packets received       */
+       u64 tx_packets;         /* total packets transmitted    */
+       u64 rx_bytes;           /* total bytes received         */
+       u64 tx_bytes;           /* total bytes transmitted      */
+       u64 rx_errors;          /* packets truncated or marked bad by hw */
+       u64 rx_dropped;         /* packets not for us or intf not up */
 };
 
 
@@ -218,8 +215,6 @@ struct tile_net_priv {
        int network_cpus_count;
        /* Credits per network cpu. */
        int network_cpus_credits;
-       /* Network stats. */
-       struct net_device_stats stats;
        /* For NetIO bringup retries. */
        struct delayed_work retry_work;
        /* Quick access to per cpu data. */
@@ -627,79 +622,6 @@ static void tile_net_handle_egress_timer(unsigned long arg)
 }
 
 
-#ifdef IGNORE_DUP_ACKS
-
-/*
- * Help detect "duplicate" ACKs.  These are sequential packets (for a
- * given flow) which are exactly 66 bytes long, sharing everything but
- * ID=2@0x12, Hsum=2@0x18, Ack=4@0x2a, WinSize=2@0x30, Csum=2@0x32,
- * Tstamps=10@0x38.  The ID's are +1, the Hsum's are -1, the Ack's are
- * +N, and the Tstamps are usually identical.
- *
- * NOTE: Apparently truly duplicate acks (with identical "ack" values),
- * should not be collapsed, as they are used for some kind of flow control.
- */
-static bool is_dup_ack(char *s1, char *s2, unsigned int len)
-{
-       int i;
-
-       unsigned long long ignorable = 0;
-
-       /* Identification. */
-       ignorable |= (1ULL << 0x12);
-       ignorable |= (1ULL << 0x13);
-
-       /* Header checksum. */
-       ignorable |= (1ULL << 0x18);
-       ignorable |= (1ULL << 0x19);
-
-       /* ACK. */
-       ignorable |= (1ULL << 0x2a);
-       ignorable |= (1ULL << 0x2b);
-       ignorable |= (1ULL << 0x2c);
-       ignorable |= (1ULL << 0x2d);
-
-       /* WinSize. */
-       ignorable |= (1ULL << 0x30);
-       ignorable |= (1ULL << 0x31);
-
-       /* Checksum. */
-       ignorable |= (1ULL << 0x32);
-       ignorable |= (1ULL << 0x33);
-
-       for (i = 0; i < len; i++, ignorable >>= 1) {
-
-               if ((ignorable & 1) || (s1[i] == s2[i]))
-                       continue;
-
-#ifdef TILE_NET_DEBUG
-               /* HACK: Mention non-timestamp diffs. */
-               if (i < 0x38 && i != 0x2f &&
-                   net_ratelimit())
-                       pr_info("Diff at 0x%x\n", i);
-#endif
-
-               return false;
-       }
-
-#ifdef TILE_NET_NO_SUPPRESS_DUP_ACKS
-       /* HACK: Do not suppress truly duplicate ACKs. */
-       /* ISSUE: Is this actually necessary or helpful? */
-       if (s1[0x2a] == s2[0x2a] &&
-           s1[0x2b] == s2[0x2b] &&
-           s1[0x2c] == s2[0x2c] &&
-           s1[0x2d] == s2[0x2d]) {
-               return false;
-       }
-#endif
-
-       return true;
-}
-
-#endif
-
-
-
 static void tile_net_discard_aux(struct tile_net_cpu *info, int index)
 {
        struct tile_netio_queue *queue = &info->queue;
@@ -774,6 +696,7 @@ static bool tile_net_poll_aux(struct tile_net_cpu *info, int index)
        netio_pkt_t *pkt = (netio_pkt_t *)((unsigned long) &qsp[1] + index);
 
        netio_pkt_metadata_t *metadata = NETIO_PKT_METADATA(pkt);
+       netio_pkt_status_t pkt_status = NETIO_PKT_STATUS_M(metadata, pkt);
 
        /* Extract the packet size.  FIXME: Shouldn't the second line */
        /* get subtracted?  Mostly moot, since it should be "zero". */
@@ -806,40 +729,25 @@ static bool tile_net_poll_aux(struct tile_net_cpu *info, int index)
 #endif /* TILE_NET_DUMP_PACKETS */
 
 #ifdef TILE_NET_VERIFY_INGRESS
-       if (!NETIO_PKT_L4_CSUM_CORRECT_M(metadata, pkt) &&
-           NETIO_PKT_L4_CSUM_CALCULATED_M(metadata, pkt)) {
-               /* Bug 6624: Includes UDP packets with a "zero" checksum. */
-               pr_warning("Bad L4 checksum on %d byte packet.\n", len);
-       }
-       if (!NETIO_PKT_L3_CSUM_CORRECT_M(metadata, pkt) &&
-           NETIO_PKT_L3_CSUM_CALCULATED_M(metadata, pkt)) {
+       if (pkt_status == NETIO_PKT_STATUS_OVERSIZE && len >= 64) {
                dump_packet(buf, len, "rx");
-               panic("Bad L3 checksum.");
-       }
-       switch (NETIO_PKT_STATUS_M(metadata, pkt)) {
-       case NETIO_PKT_STATUS_OVERSIZE:
-               if (len >= 64) {
-                       dump_packet(buf, len, "rx");
-                       panic("Unexpected OVERSIZE.");
-               }
-               break;
-       case NETIO_PKT_STATUS_BAD:
-               pr_warning("Unexpected BAD %ld byte packet.\n", len);
+               panic("Unexpected OVERSIZE.");
        }
 #endif
 
        filter = 0;
 
-       /* ISSUE: Filter TCP packets with "bad" checksums? */
-
-       if (!(dev->flags & IFF_UP)) {
+       if (pkt_status == NETIO_PKT_STATUS_BAD) {
+               /* Handle CRC error and hardware truncation. */
+               filter = 2;
+       } else if (!(dev->flags & IFF_UP)) {
                /* Filter packets received before we're up. */
                filter = 1;
-       } else if (NETIO_PKT_STATUS_M(metadata, pkt) == NETIO_PKT_STATUS_BAD) {
+       } else if (NETIO_PKT_ETHERTYPE_RECOGNIZED_M(metadata, pkt) &&
+                  pkt_status == NETIO_PKT_STATUS_UNDERSIZE) {
                /* Filter "truncated" packets. */
-               filter = 1;
+               filter = 2;
        } else if (!(dev->flags & IFF_PROMISC)) {
-               /* FIXME: Implement HW multicast filter. */
                if (!is_multicast_ether_addr(buf)) {
                        /* Filter packets not for our address. */
                        const u8 *mine = dev->dev_addr;
@@ -847,9 +755,14 @@ static bool tile_net_poll_aux(struct tile_net_cpu *info, int index)
                }
        }
 
-       if (filter) {
+       u64_stats_update_begin(&stats->syncp);
 
-               /* ISSUE: Update "drop" statistics? */
+       if (filter != 0) {
+
+               if (filter == 1)
+                       stats->rx_dropped++;
+               else
+                       stats->rx_errors++;
 
                tile_net_provide_linux_buffer(info, va, small);
 
@@ -881,6 +794,8 @@ static bool tile_net_poll_aux(struct tile_net_cpu *info, int index)
                stats->rx_bytes += len;
        }
 
+       u64_stats_update_end(&stats->syncp);
+
        /* ISSUE: It would be nice to defer this until the packet has */
        /* actually been processed. */
        tile_net_return_credit(info);
@@ -1907,8 +1822,10 @@ busy:
                kfree_skb(olds[i]);
 
        /* Update stats. */
+       u64_stats_update_begin(&stats->syncp);
        stats->tx_packets += num_segs;
        stats->tx_bytes += (num_segs * sh_len) + d_len;
+       u64_stats_update_end(&stats->syncp);
 
        /* Make sure the egress timer is scheduled. */
        tile_net_schedule_egress_timer(info);
@@ -1936,7 +1853,7 @@ static int tile_net_tx(struct sk_buff *skb, struct net_device *dev)
 
        unsigned int csum_start = skb_checksum_start_offset(skb);
 
-       lepp_frag_t frags[LEPP_MAX_FRAGS];
+       lepp_frag_t frags[1 + MAX_SKB_FRAGS];
 
        unsigned int num_frags;
 
@@ -1951,7 +1868,7 @@ static int tile_net_tx(struct sk_buff *skb, struct net_device *dev)
        unsigned int cmd_head, cmd_tail, cmd_next;
        unsigned int comp_tail;
 
-       lepp_cmd_t cmds[LEPP_MAX_FRAGS];
+       lepp_cmd_t cmds[1 + MAX_SKB_FRAGS];
 
 
        /*
@@ -2089,8 +2006,10 @@ busy:
                kfree_skb(olds[i]);
 
        /* HACK: Track "expanded" size for short packets (e.g. 42 < 60). */
+       u64_stats_update_begin(&stats->syncp);
        stats->tx_packets++;
        stats->tx_bytes += ((len >= ETH_ZLEN) ? len : ETH_ZLEN);
+       u64_stats_update_end(&stats->syncp);
 
        /* Make sure the egress timer is scheduled. */
        tile_net_schedule_egress_timer(info);
@@ -2127,30 +2046,51 @@ static int tile_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
  *
  * Returns the address of the device statistics structure.
  */
-static struct net_device_stats *tile_net_get_stats(struct net_device *dev)
+static struct rtnl_link_stats64 *tile_net_get_stats64(struct net_device *dev,
+               struct rtnl_link_stats64 *stats)
 {
        struct tile_net_priv *priv = netdev_priv(dev);
-       u32 rx_packets = 0;
-       u32 tx_packets = 0;
-       u32 rx_bytes = 0;
-       u32 tx_bytes = 0;
+       u64 rx_packets = 0, tx_packets = 0;
+       u64 rx_bytes = 0, tx_bytes = 0;
+       u64 rx_errors = 0, rx_dropped = 0;
        int i;
 
        for_each_online_cpu(i) {
-               if (priv->cpu[i]) {
-                       rx_packets += priv->cpu[i]->stats.rx_packets;
-                       rx_bytes += priv->cpu[i]->stats.rx_bytes;
-                       tx_packets += priv->cpu[i]->stats.tx_packets;
-                       tx_bytes += priv->cpu[i]->stats.tx_bytes;
-               }
+               struct tile_net_stats_t *cpu_stats;
+               u64 trx_packets, ttx_packets, trx_bytes, ttx_bytes;
+               u64 trx_errors, trx_dropped;
+               unsigned int start;
+
+               if (priv->cpu[i] == NULL)
+                       continue;
+               cpu_stats = &priv->cpu[i]->stats;
+
+               do {
+                       start = u64_stats_fetch_begin_bh(&cpu_stats->syncp);
+                       trx_packets = cpu_stats->rx_packets;
+                       ttx_packets = cpu_stats->tx_packets;
+                       trx_bytes   = cpu_stats->rx_bytes;
+                       ttx_bytes   = cpu_stats->tx_bytes;
+                       trx_errors  = cpu_stats->rx_errors;
+                       trx_dropped = cpu_stats->rx_dropped;
+               } while (u64_stats_fetch_retry_bh(&cpu_stats->syncp, start));
+
+               rx_packets += trx_packets;
+               tx_packets += ttx_packets;
+               rx_bytes   += trx_bytes;
+               tx_bytes   += ttx_bytes;
+               rx_errors  += trx_errors;
+               rx_dropped += trx_dropped;
        }
 
-       priv->stats.rx_packets = rx_packets;
-       priv->stats.rx_bytes = rx_bytes;
-       priv->stats.tx_packets = tx_packets;
-       priv->stats.tx_bytes = tx_bytes;
+       stats->rx_packets = rx_packets;
+       stats->tx_packets = tx_packets;
+       stats->rx_bytes   = rx_bytes;
+       stats->tx_bytes   = tx_bytes;
+       stats->rx_errors  = rx_errors;
+       stats->rx_dropped = rx_dropped;
 
-       return &priv->stats;
+       return stats;
 }
 
 
@@ -2287,7 +2227,7 @@ static const struct net_device_ops tile_net_ops = {
        .ndo_stop = tile_net_stop,
        .ndo_start_xmit = tile_net_tx,
        .ndo_do_ioctl = tile_net_ioctl,
-       .ndo_get_stats = tile_net_get_stats,
+       .ndo_get_stats64 = tile_net_get_stats64,
        .ndo_change_mtu = tile_net_change_mtu,
        .ndo_tx_timeout = tile_net_tx_timeout,
        .ndo_set_mac_address = tile_net_set_mac_address,
@@ -2305,39 +2245,30 @@ static const struct net_device_ops tile_net_ops = {
  */
 static void tile_net_setup(struct net_device *dev)
 {
-       PDEBUG("tile_net_setup()\n");
+       netdev_features_t features = 0;
 
        ether_setup(dev);
-
        dev->netdev_ops = &tile_net_ops;
-
        dev->watchdog_timeo = TILE_NET_TIMEOUT;
+       dev->tx_queue_len = TILE_NET_TX_QUEUE_LEN;
+       dev->mtu = TILE_NET_MTU;
 
-       /* We want lockless xmit. */
-       dev->features |= NETIF_F_LLTX;
-
-       /* We support hardware tx checksums. */
-       dev->features |= NETIF_F_HW_CSUM;
-
-       /* We support scatter/gather. */
-       dev->features |= NETIF_F_SG;
-
-       /* We support TSO. */
-       dev->features |= NETIF_F_TSO;
+       features |= NETIF_F_HW_CSUM;
+       features |= NETIF_F_SG;
 
-#ifdef TILE_NET_GSO
-       /* We support GSO. */
-       dev->features |= NETIF_F_GSO;
-#endif
+       /* We support TSO iff the HV supports sufficient frags. */
+       if (LEPP_MAX_FRAGS >= 1 + MAX_SKB_FRAGS)
+               features |= NETIF_F_TSO;
 
+       /* We can't support HIGHDMA without hash_default, since we need
+        * to be able to finv() with a VA if we don't have hash_default.
+        */
        if (hash_default)
-               dev->features |= NETIF_F_HIGHDMA;
-
-       /* ISSUE: We should support NETIF_F_UFO. */
+               features |= NETIF_F_HIGHDMA;
 
-       dev->tx_queue_len = TILE_NET_TX_QUEUE_LEN;
-
-       dev->mtu = TILE_NET_MTU;
+       dev->hw_features   |= features;
+       dev->vlan_features |= features;
+       dev->features      |= features;
 }
 
 
index 1d6dc41f755dba00edfbc83d07c1d898c05020cf..ef776310fab1dbc2ff69130a783ae80bb9d1ac1f 100644 (file)
@@ -2376,6 +2376,23 @@ out_0:
        return ret;
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/**
+ *  velocity_poll_controller           -       Velocity Poll controller function
+ *  @dev: network device
+ *
+ *
+ *  Used by NETCONSOLE and other diagnostic tools to allow network I/P
+ *  with interrupts disabled.
+ */
+static void velocity_poll_controller(struct net_device *dev)
+{
+       disable_irq(dev->irq);
+       velocity_intr(dev->irq, dev);
+       enable_irq(dev->irq);
+}
+#endif
+
 /**
  *     velocity_mii_ioctl              -       MII ioctl handler
  *     @dev: network device
@@ -2641,6 +2658,9 @@ static const struct net_device_ops velocity_netdev_ops = {
        .ndo_do_ioctl           = velocity_ioctl,
        .ndo_vlan_rx_add_vid    = velocity_vlan_rx_add_vid,
        .ndo_vlan_rx_kill_vid   = velocity_vlan_rx_kill_vid,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller = velocity_poll_controller,
+#endif
 };
 
 /**
index 18373b6ae37d78543cf925e2d86efab1578f3019..a822207b82410e7c76c1bb7cb6ef4de37ea72338 100644 (file)
@@ -337,8 +337,11 @@ static int macvlan_open(struct net_device *dev)
        int err;
 
        if (vlan->port->passthru) {
-               if (!(vlan->flags & MACVLAN_FLAG_NOPROMISC))
-                       dev_set_promiscuity(lowerdev, 1);
+               if (!(vlan->flags & MACVLAN_FLAG_NOPROMISC)) {
+                       err = dev_set_promiscuity(lowerdev, 1);
+                       if (err < 0)
+                               goto out;
+               }
                goto hash_add;
        }
 
@@ -597,6 +600,9 @@ static int macvlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
        if (!vlan->port->passthru)
                return -EOPNOTSUPP;
 
+       if (flags & NLM_F_REPLACE)
+               return -EOPNOTSUPP;
+
        if (is_unicast_ether_addr(addr))
                err = dev_uc_add_excl(dev, addr);
        else if (is_multicast_ether_addr(addr))
@@ -863,6 +869,18 @@ static int macvlan_changelink(struct net_device *dev,
                struct nlattr *tb[], struct nlattr *data[])
 {
        struct macvlan_dev *vlan = netdev_priv(dev);
+       enum macvlan_mode mode;
+       bool set_mode = false;
+
+       /* Validate mode, but don't set yet: setting flags may fail. */
+       if (data && data[IFLA_MACVLAN_MODE]) {
+               set_mode = true;
+               mode = nla_get_u32(data[IFLA_MACVLAN_MODE]);
+               /* Passthrough mode can't be set or cleared dynamically */
+               if ((mode == MACVLAN_MODE_PASSTHRU) !=
+                   (vlan->mode == MACVLAN_MODE_PASSTHRU))
+                       return -EINVAL;
+       }
 
        if (data && data[IFLA_MACVLAN_FLAGS]) {
                __u16 flags = nla_get_u16(data[IFLA_MACVLAN_FLAGS]);
@@ -879,8 +897,8 @@ static int macvlan_changelink(struct net_device *dev,
                }
                vlan->flags = flags;
        }
-       if (data && data[IFLA_MACVLAN_MODE])
-               vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]);
+       if (set_mode)
+               vlan->mode = mode;
        return 0;
 }
 
index 61d3f4ebf52e5590f41b260aa7a354e2ac4b862a..7f25e49ae37f21167bebda2f8051dc4da6c6ba0c 100644 (file)
@@ -40,7 +40,7 @@ struct sun4i_mdio_data {
 static int sun4i_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
 {
        struct sun4i_mdio_data *data = bus->priv;
-       unsigned long start_jiffies;
+       unsigned long timeout_jiffies;
        int value;
 
        /* issue the phy address and reg */
@@ -49,10 +49,9 @@ static int sun4i_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
        writel(0x1, data->membase + EMAC_MAC_MCMD_REG);
 
        /* Wait read complete */
-       start_jiffies = jiffies;
+       timeout_jiffies = jiffies + MDIO_TIMEOUT;
        while (readl(data->membase + EMAC_MAC_MIND_REG) & 0x1) {
-               if (time_after(start_jiffies,
-                              start_jiffies + MDIO_TIMEOUT))
+               if (time_is_before_jiffies(timeout_jiffies))
                        return -ETIMEDOUT;
                msleep(1);
        }
@@ -69,7 +68,7 @@ static int sun4i_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
                            u16 value)
 {
        struct sun4i_mdio_data *data = bus->priv;
-       unsigned long start_jiffies;
+       unsigned long timeout_jiffies;
 
        /* issue the phy address and reg */
        writel((mii_id << 8) | regnum, data->membase + EMAC_MAC_MADR_REG);
@@ -77,10 +76,9 @@ static int sun4i_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
        writel(0x1, data->membase + EMAC_MAC_MCMD_REG);
 
        /* Wait read complete */
-       start_jiffies = jiffies;
+       timeout_jiffies = jiffies + MDIO_TIMEOUT;
        while (readl(data->membase + EMAC_MAC_MIND_REG) & 0x1) {
-               if (time_after(start_jiffies,
-                              start_jiffies + MDIO_TIMEOUT))
+               if (time_is_before_jiffies(timeout_jiffies))
                        return -ETIMEDOUT;
                msleep(1);
        }
index bff7e0b0b4e70d10ccdf9a6de11cdbae056a64f0..9ccccd40c4101b07c0f5ecbaec7c25484b67ceeb 100644 (file)
@@ -622,6 +622,86 @@ static int team_change_mode(struct team *team, const char *kind)
 }
 
 
+/*********************
+ * Peers notification
+ *********************/
+
+static void team_notify_peers_work(struct work_struct *work)
+{
+       struct team *team;
+
+       team = container_of(work, struct team, notify_peers.dw.work);
+
+       if (!rtnl_trylock()) {
+               schedule_delayed_work(&team->notify_peers.dw, 0);
+               return;
+       }
+       call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, team->dev);
+       rtnl_unlock();
+       if (!atomic_dec_and_test(&team->notify_peers.count_pending))
+               schedule_delayed_work(&team->notify_peers.dw,
+                                     msecs_to_jiffies(team->notify_peers.interval));
+}
+
+static void team_notify_peers(struct team *team)
+{
+       if (!team->notify_peers.count || !netif_running(team->dev))
+               return;
+       atomic_set(&team->notify_peers.count_pending, team->notify_peers.count);
+       schedule_delayed_work(&team->notify_peers.dw, 0);
+}
+
+static void team_notify_peers_init(struct team *team)
+{
+       INIT_DELAYED_WORK(&team->notify_peers.dw, team_notify_peers_work);
+}
+
+static void team_notify_peers_fini(struct team *team)
+{
+       cancel_delayed_work_sync(&team->notify_peers.dw);
+}
+
+
+/*******************************
+ * Send multicast group rejoins
+ *******************************/
+
+static void team_mcast_rejoin_work(struct work_struct *work)
+{
+       struct team *team;
+
+       team = container_of(work, struct team, mcast_rejoin.dw.work);
+
+       if (!rtnl_trylock()) {
+               schedule_delayed_work(&team->mcast_rejoin.dw, 0);
+               return;
+       }
+       call_netdevice_notifiers(NETDEV_RESEND_IGMP, team->dev);
+       rtnl_unlock();
+       if (!atomic_dec_and_test(&team->mcast_rejoin.count_pending))
+               schedule_delayed_work(&team->mcast_rejoin.dw,
+                                     msecs_to_jiffies(team->mcast_rejoin.interval));
+}
+
+static void team_mcast_rejoin(struct team *team)
+{
+       if (!team->mcast_rejoin.count || !netif_running(team->dev))
+               return;
+       atomic_set(&team->mcast_rejoin.count_pending, team->mcast_rejoin.count);
+       schedule_delayed_work(&team->mcast_rejoin.dw, 0);
+}
+
+static void team_mcast_rejoin_init(struct team *team)
+{
+       INIT_DELAYED_WORK(&team->mcast_rejoin.dw, team_mcast_rejoin_work);
+}
+
+static void team_mcast_rejoin_fini(struct team *team)
+{
+       cancel_delayed_work_sync(&team->mcast_rejoin.dw);
+}
+
+
 /************************
  * Rx path frame handler
  ************************/
@@ -846,6 +926,8 @@ static void team_port_enable(struct team *team,
        team_queue_override_port_add(team, port);
        if (team->ops.port_enabled)
                team->ops.port_enabled(team, port);
+       team_notify_peers(team);
+       team_mcast_rejoin(team);
 }
 
 static void __reconstruct_port_hlist(struct team *team, int rm_index)
@@ -875,6 +957,8 @@ static void team_port_disable(struct team *team,
        team->en_port_count--;
        team_queue_override_port_del(team, port);
        team_adjust_ops(team);
+       team_notify_peers(team);
+       team_mcast_rejoin(team);
 }
 
 #define TEAM_VLAN_FEATURES (NETIF_F_ALL_CSUM | NETIF_F_SG | \
@@ -953,6 +1037,9 @@ static int team_port_enable_netpoll(struct team *team, struct team_port *port,
        struct netpoll *np;
        int err;
 
+       if (!team->dev->npinfo)
+               return 0;
+
        np = kzalloc(sizeof(*np), gfp);
        if (!np)
                return -ENOMEM;
@@ -979,12 +1066,6 @@ static void team_port_disable_netpoll(struct team_port *port)
        __netpoll_cleanup(np);
        kfree(np);
 }
-
-static struct netpoll_info *team_netpoll_info(struct team *team)
-{
-       return team->dev->npinfo;
-}
-
 #else
 static int team_port_enable_netpoll(struct team *team, struct team_port *port,
                                    gfp_t gfp)
@@ -994,10 +1075,6 @@ static int team_port_enable_netpoll(struct team *team, struct team_port *port,
 static void team_port_disable_netpoll(struct team_port *port)
 {
 }
-static struct netpoll_info *team_netpoll_info(struct team *team)
-{
-       return NULL;
-}
 #endif
 
 static void __team_port_change_port_added(struct team_port *port, bool linkup);
@@ -1079,13 +1156,11 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
                goto err_vids_add;
        }
 
-       if (team_netpoll_info(team)) {
-               err = team_port_enable_netpoll(team, port, GFP_KERNEL);
-               if (err) {
-                       netdev_err(dev, "Failed to enable netpoll on device %s\n",
-                                  portname);
-                       goto err_enable_netpoll;
-               }
+       err = team_port_enable_netpoll(team, port, GFP_KERNEL);
+       if (err) {
+               netdev_err(dev, "Failed to enable netpoll on device %s\n",
+                          portname);
+               goto err_enable_netpoll;
        }
 
        err = netdev_master_upper_dev_link(port_dev, dev);
@@ -1205,6 +1280,62 @@ static int team_mode_option_set(struct team *team, struct team_gsetter_ctx *ctx)
        return team_change_mode(team, ctx->data.str_val);
 }
 
+static int team_notify_peers_count_get(struct team *team,
+                                      struct team_gsetter_ctx *ctx)
+{
+       ctx->data.u32_val = team->notify_peers.count;
+       return 0;
+}
+
+static int team_notify_peers_count_set(struct team *team,
+                                      struct team_gsetter_ctx *ctx)
+{
+       team->notify_peers.count = ctx->data.u32_val;
+       return 0;
+}
+
+static int team_notify_peers_interval_get(struct team *team,
+                                         struct team_gsetter_ctx *ctx)
+{
+       ctx->data.u32_val = team->notify_peers.interval;
+       return 0;
+}
+
+static int team_notify_peers_interval_set(struct team *team,
+                                         struct team_gsetter_ctx *ctx)
+{
+       team->notify_peers.interval = ctx->data.u32_val;
+       return 0;
+}
+
+static int team_mcast_rejoin_count_get(struct team *team,
+                                      struct team_gsetter_ctx *ctx)
+{
+       ctx->data.u32_val = team->mcast_rejoin.count;
+       return 0;
+}
+
+static int team_mcast_rejoin_count_set(struct team *team,
+                                      struct team_gsetter_ctx *ctx)
+{
+       team->mcast_rejoin.count = ctx->data.u32_val;
+       return 0;
+}
+
+static int team_mcast_rejoin_interval_get(struct team *team,
+                                         struct team_gsetter_ctx *ctx)
+{
+       ctx->data.u32_val = team->mcast_rejoin.interval;
+       return 0;
+}
+
+static int team_mcast_rejoin_interval_set(struct team *team,
+                                         struct team_gsetter_ctx *ctx)
+{
+       team->mcast_rejoin.interval = ctx->data.u32_val;
+       return 0;
+}
+
 static int team_port_en_option_get(struct team *team,
                                   struct team_gsetter_ctx *ctx)
 {
@@ -1316,6 +1447,30 @@ static const struct team_option team_options[] = {
                .getter = team_mode_option_get,
                .setter = team_mode_option_set,
        },
+       {
+               .name = "notify_peers_count",
+               .type = TEAM_OPTION_TYPE_U32,
+               .getter = team_notify_peers_count_get,
+               .setter = team_notify_peers_count_set,
+       },
+       {
+               .name = "notify_peers_interval",
+               .type = TEAM_OPTION_TYPE_U32,
+               .getter = team_notify_peers_interval_get,
+               .setter = team_notify_peers_interval_set,
+       },
+       {
+               .name = "mcast_rejoin_count",
+               .type = TEAM_OPTION_TYPE_U32,
+               .getter = team_mcast_rejoin_count_get,
+               .setter = team_mcast_rejoin_count_set,
+       },
+       {
+               .name = "mcast_rejoin_interval",
+               .type = TEAM_OPTION_TYPE_U32,
+               .getter = team_mcast_rejoin_interval_get,
+               .setter = team_mcast_rejoin_interval_set,
+       },
        {
                .name = "enabled",
                .type = TEAM_OPTION_TYPE_BOOL,
@@ -1396,6 +1551,10 @@ static int team_init(struct net_device *dev)
 
        INIT_LIST_HEAD(&team->option_list);
        INIT_LIST_HEAD(&team->option_inst_list);
+
+       team_notify_peers_init(team);
+       team_mcast_rejoin_init(team);
+
        err = team_options_register(team, team_options, ARRAY_SIZE(team_options));
        if (err)
                goto err_options_register;
@@ -1406,6 +1565,8 @@ static int team_init(struct net_device *dev)
        return 0;
 
 err_options_register:
+       team_mcast_rejoin_fini(team);
+       team_notify_peers_fini(team);
        team_queue_override_fini(team);
 err_team_queue_override_init:
        free_percpu(team->pcpu_stats);
@@ -1425,6 +1586,8 @@ static void team_uninit(struct net_device *dev)
 
        __team_change_mode(team, NULL); /* cleanup */
        __team_options_unregister(team, team_options, ARRAY_SIZE(team_options));
+       team_mcast_rejoin_fini(team);
+       team_notify_peers_fini(team);
        team_queue_override_fini(team);
        mutex_unlock(&team->lock);
 }
@@ -2698,6 +2861,10 @@ static int team_device_event(struct notifier_block *unused,
        case NETDEV_PRE_TYPE_CHANGE:
                /* Forbid to change type of underlaying device */
                return NOTIFY_BAD;
+       case NETDEV_RESEND_IGMP:
+               /* Propagate to master device */
+               call_netdevice_notifiers(event, port->team->dev);
+               break;
        }
        return NOTIFY_DONE;
 }
index db690a372260786b395186dffb38ea24e58d45ee..5dce262f538ecc8bfb46df05d33e54c5577299dd 100644 (file)
@@ -60,6 +60,7 @@
 #include <linux/if_arp.h>
 #include <linux/if_ether.h>
 #include <linux/if_tun.h>
+#include <linux/if_vlan.h>
 #include <linux/crc32.h>
 #include <linux/nsproxy.h>
 #include <linux/virtio_net.h>
@@ -739,6 +740,11 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
                          >= dev->tx_queue_len / tun->numqueues)
                goto drop;
 
+       if (skb->sk) {
+               sock_tx_timestamp(skb->sk, &skb_shinfo(skb)->tx_flags);
+               sw_tx_timestamp(skb);
+       }
+
        /* Orphan the skb - required as we might hang on to it
         * for indefinite time. */
        if (unlikely(skb_orphan_frags(skb, GFP_ATOMIC)))
@@ -1260,6 +1266,7 @@ static ssize_t tun_put_user(struct tun_struct *tun,
 {
        struct tun_pi pi = { 0, skb->protocol };
        ssize_t total = 0;
+       int vlan_offset = 0;
 
        if (!(tun->flags & TUN_NO_PI)) {
                if ((len -= sizeof(pi)) < 0)
@@ -1323,11 +1330,40 @@ static ssize_t tun_put_user(struct tun_struct *tun,
                total += tun->vnet_hdr_sz;
        }
 
-       len = min_t(int, skb->len, len);
+       if (!vlan_tx_tag_present(skb)) {
+               len = min_t(int, skb->len, len);
+       } else {
+               int copy, ret;
+               struct {
+                       __be16 h_vlan_proto;
+                       __be16 h_vlan_TCI;
+               } veth;
+
+               veth.h_vlan_proto = skb->vlan_proto;
+               veth.h_vlan_TCI = htons(vlan_tx_tag_get(skb));
+
+               vlan_offset = offsetof(struct vlan_ethhdr, h_vlan_proto);
+               len = min_t(int, skb->len + VLAN_HLEN, len);
+
+               copy = min_t(int, vlan_offset, len);
+               ret = skb_copy_datagram_const_iovec(skb, 0, iv, total, copy);
+               len -= copy;
+               total += copy;
+               if (ret || !len)
+                       goto done;
 
-       skb_copy_datagram_const_iovec(skb, 0, iv, total, len);
-       total += skb->len;
+               copy = min_t(int, sizeof(veth), len);
+               ret = memcpy_toiovecend(iv, (void *)&veth, total, copy);
+               len -= copy;
+               total += copy;
+               if (ret || !len)
+                       goto done;
+       }
 
+       skb_copy_datagram_const_iovec(skb, vlan_offset, iv, total, len);
+       total += len;
+
+done:
        tun->dev->stats.tx_packets++;
        tun->dev->stats.tx_bytes += len;
 
@@ -1476,7 +1512,6 @@ static int tun_sendmsg(struct kiocb *iocb, struct socket *sock,
        return ret;
 }
 
-
 static int tun_recvmsg(struct kiocb *iocb, struct socket *sock,
                       struct msghdr *m, size_t total_len,
                       int flags)
@@ -1488,10 +1523,15 @@ static int tun_recvmsg(struct kiocb *iocb, struct socket *sock,
        if (!tun)
                return -EBADFD;
 
-       if (flags & ~(MSG_DONTWAIT|MSG_TRUNC)) {
+       if (flags & ~(MSG_DONTWAIT|MSG_TRUNC|MSG_ERRQUEUE)) {
                ret = -EINVAL;
                goto out;
        }
+       if (flags & MSG_ERRQUEUE) {
+               ret = sock_recv_errqueue(sock->sk, m, total_len,
+                                        SOL_PACKET, TUN_TX_TIMESTAMP);
+               goto out;
+       }
        ret = tun_do_read(tun, tfile, iocb, m->msg_iov, total_len,
                          flags & MSG_DONTWAIT);
        if (ret > total_len) {
@@ -1682,7 +1722,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
                tun_flow_init(tun);
 
                dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST |
-                       TUN_USER_FEATURES;
+                                  TUN_USER_FEATURES | NETIF_F_HW_VLAN_CTAG_TX |
+                                  NETIF_F_HW_VLAN_STAG_TX;
                dev->features = dev->hw_features;
                dev->vlan_features = dev->features;
 
@@ -2274,6 +2315,7 @@ static const struct ethtool_ops tun_ethtool_ops = {
        .get_msglevel   = tun_get_msglevel,
        .set_msglevel   = tun_set_msglevel,
        .get_link       = ethtool_op_get_link,
+       .get_ts_info    = ethtool_op_get_ts_info,
 };
 
 
index ad5d1e4384db7b3b6c3ab6f2406b5cd8075cd2d0..b96ad4f15b8ae0856fc52a7b53efeb08d6c42815 100644 (file)
@@ -778,6 +778,9 @@ static int ax88178_change_mtu(struct net_device *net, int new_mtu)
        dev->hard_mtu = net->mtu + net->hard_header_len;
        ax88178_set_mfb(dev);
 
+       /* max qlen depend on hard_mtu and rx_urb_size */
+       usbnet_update_max_qlen(dev);
+
        return 0;
 }
 
index 1e3c302d94fe338dec36ba934fc90a79bfb00e0d..5a468f317ca5c02d907da9ff5f291a0a96771d43 100644 (file)
@@ -688,6 +688,9 @@ static int ax88179_change_mtu(struct net_device *net, int new_mtu)
                                  2, 2, &tmp16);
        }
 
+       /* max qlen depend on hard_mtu and rx_urb_size */
+       usbnet_update_max_qlen(dev);
+
        return 0;
 }
 
@@ -1029,10 +1032,10 @@ static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf)
        dev->mii.supports_gmii = 1;
 
        dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
-                             NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO;
+                             NETIF_F_RXCSUM;
 
        dev->net->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
-                                NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO;
+                                NETIF_F_RXCSUM;
 
        /* Enable checksum offload */
        *tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP |
@@ -1173,7 +1176,6 @@ ax88179_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
        if (((skb->len + 8) % frame_size) == 0)
                tx_hdr2 |= 0x80008000;  /* Enable padding */
 
-       skb_linearize(skb);
        headroom = skb_headroom(skb);
        tailroom = skb_tailroom(skb);
 
@@ -1317,10 +1319,10 @@ static int ax88179_reset(struct usbnet *dev)
                          1, 1, tmp);
 
        dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
-                             NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO;
+                             NETIF_F_RXCSUM;
 
        dev->net->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
-                                NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO;
+                                NETIF_F_RXCSUM;
 
        /* Enable checksum offload */
        *tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP |
index ee13f9eb740c0bf18b793b308194675e9967a317..11c51f275366a15999ad7684330bb644de76b557 100644 (file)
@@ -344,17 +344,41 @@ static const int multicast_filter_limit = 32;
 static
 int get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
 {
-       return usb_control_msg(tp->udev, usb_rcvctrlpipe(tp->udev, 0),
+       int ret;
+       void *tmp;
+
+       tmp = kmalloc(size, GFP_KERNEL);
+       if (!tmp)
+               return -ENOMEM;
+
+       ret = usb_control_msg(tp->udev, usb_rcvctrlpipe(tp->udev, 0),
                               RTL8152_REQ_GET_REGS, RTL8152_REQT_READ,
-                              value, index, data, size, 500);
+                              value, index, tmp, size, 500);
+
+       memcpy(data, tmp, size);
+       kfree(tmp);
+
+       return ret;
 }
 
 static
 int set_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
 {
-       return usb_control_msg(tp->udev, usb_sndctrlpipe(tp->udev, 0),
+       int ret;
+       void *tmp;
+
+       tmp = kmalloc(size, GFP_KERNEL);
+       if (!tmp)
+               return -ENOMEM;
+
+       memcpy(tmp, data, size);
+
+       ret = usb_control_msg(tp->udev, usb_sndctrlpipe(tp->udev, 0),
                               RTL8152_REQ_SET_REGS, RTL8152_REQT_WRITE,
-                              value, index, data, size, 500);
+                              value, index, tmp, size, 500);
+
+       kfree(tmp);
+       return ret;
 }
 
 static int generic_ocp_read(struct r8152 *tp, u16 index, u16 size,
@@ -490,37 +514,31 @@ int usb_ocp_write(struct r8152 *tp, u16 index, u16 byteen, u16 size, void *data)
 
 static u32 ocp_read_dword(struct r8152 *tp, u16 type, u16 index)
 {
-       u32 data;
+       __le32 data;
 
-       if (type == MCU_TYPE_PLA)
-               pla_ocp_read(tp, index, sizeof(data), &data);
-       else
-               usb_ocp_read(tp, index, sizeof(data), &data);
+       generic_ocp_read(tp, index, sizeof(data), &data, type);
 
        return __le32_to_cpu(data);
 }
 
 static void ocp_write_dword(struct r8152 *tp, u16 type, u16 index, u32 data)
 {
-       if (type == MCU_TYPE_PLA)
-               pla_ocp_write(tp, index, BYTE_EN_DWORD, sizeof(data), &data);
-       else
-               usb_ocp_write(tp, index, BYTE_EN_DWORD, sizeof(data), &data);
+       __le32 tmp = __cpu_to_le32(data);
+
+       generic_ocp_write(tp, index, BYTE_EN_DWORD, sizeof(tmp), &tmp, type);
 }
 
 static u16 ocp_read_word(struct r8152 *tp, u16 type, u16 index)
 {
        u32 data;
+       __le32 tmp;
        u8 shift = index & 2;
 
        index &= ~3;
 
-       if (type == MCU_TYPE_PLA)
-               pla_ocp_read(tp, index, sizeof(data), &data);
-       else
-               usb_ocp_read(tp, index, sizeof(data), &data);
+       generic_ocp_read(tp, index, sizeof(tmp), &tmp, type);
 
-       data = __le32_to_cpu(data);
+       data = __le32_to_cpu(tmp);
        data >>= (shift * 8);
        data &= 0xffff;
 
@@ -529,7 +547,8 @@ static u16 ocp_read_word(struct r8152 *tp, u16 type, u16 index)
 
 static void ocp_write_word(struct r8152 *tp, u16 type, u16 index, u32 data)
 {
-       u32 tmp, mask = 0xffff;
+       u32 mask = 0xffff;
+       __le32 tmp;
        u16 byen = BYTE_EN_WORD;
        u8 shift = index & 2;
 
@@ -542,34 +561,25 @@ static void ocp_write_word(struct r8152 *tp, u16 type, u16 index, u32 data)
                index &= ~3;
        }
 
-       if (type == MCU_TYPE_PLA)
-               pla_ocp_read(tp, index, sizeof(tmp), &tmp);
-       else
-               usb_ocp_read(tp, index, sizeof(tmp), &tmp);
+       generic_ocp_read(tp, index, sizeof(tmp), &tmp, type);
 
-       tmp = __le32_to_cpu(tmp) & ~mask;
-       tmp |= data;
-       tmp = __cpu_to_le32(tmp);
+       data |= __le32_to_cpu(tmp) & ~mask;
+       tmp = __cpu_to_le32(data);
 
-       if (type == MCU_TYPE_PLA)
-               pla_ocp_write(tp, index, byen, sizeof(tmp), &tmp);
-       else
-               usb_ocp_write(tp, index, byen, sizeof(tmp), &tmp);
+       generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type);
 }
 
 static u8 ocp_read_byte(struct r8152 *tp, u16 type, u16 index)
 {
        u32 data;
+       __le32 tmp;
        u8 shift = index & 3;
 
        index &= ~3;
 
-       if (type == MCU_TYPE_PLA)
-               pla_ocp_read(tp, index, sizeof(data), &data);
-       else
-               usb_ocp_read(tp, index, sizeof(data), &data);
+       generic_ocp_read(tp, index, sizeof(tmp), &tmp, type);
 
-       data = __le32_to_cpu(data);
+       data = __le32_to_cpu(tmp);
        data >>= (shift * 8);
        data &= 0xff;
 
@@ -578,7 +588,8 @@ static u8 ocp_read_byte(struct r8152 *tp, u16 type, u16 index)
 
 static void ocp_write_byte(struct r8152 *tp, u16 type, u16 index, u32 data)
 {
-       u32 tmp, mask = 0xff;
+       u32 mask = 0xff;
+       __le32 tmp;
        u16 byen = BYTE_EN_BYTE;
        u8 shift = index & 3;
 
@@ -591,19 +602,12 @@ static void ocp_write_byte(struct r8152 *tp, u16 type, u16 index, u32 data)
                index &= ~3;
        }
 
-       if (type == MCU_TYPE_PLA)
-               pla_ocp_read(tp, index, sizeof(tmp), &tmp);
-       else
-               usb_ocp_read(tp, index, sizeof(tmp), &tmp);
+       generic_ocp_read(tp, index, sizeof(tmp), &tmp, type);
 
-       tmp = __le32_to_cpu(tmp) & ~mask;
-       tmp |= data;
-       tmp = __cpu_to_le32(tmp);
+       data |= __le32_to_cpu(tmp) & ~mask;
+       tmp = __cpu_to_le32(data);
 
-       if (type == MCU_TYPE_PLA)
-               pla_ocp_write(tp, index, byen, sizeof(tmp), &tmp);
-       else
-               usb_ocp_write(tp, index, byen, sizeof(tmp), &tmp);
+       generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type);
 }
 
 static void r8152_mdio_write(struct r8152 *tp, u32 reg_addr, u32 value)
@@ -685,21 +689,14 @@ static void ocp_reg_write(struct r8152 *tp, u16 addr, u16 data)
 static inline void set_ethernet_addr(struct r8152 *tp)
 {
        struct net_device *dev = tp->netdev;
-       u8 *node_id;
-
-       node_id = kmalloc(sizeof(u8) * 8, GFP_KERNEL);
-       if (!node_id) {
-               netif_err(tp, probe, dev, "out of memory");
-               return;
-       }
+       u8 node_id[8] = {0};
 
-       if (pla_ocp_read(tp, PLA_IDR, sizeof(u8) * 8, node_id) < 0)
+       if (pla_ocp_read(tp, PLA_IDR, sizeof(node_id), node_id) < 0)
                netif_notice(tp, probe, dev, "inet addr fail\n");
        else {
                memcpy(dev->dev_addr, node_id, dev->addr_len);
                memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
        }
-       kfree(node_id);
 }
 
 static int rtl8152_set_mac_address(struct net_device *netdev, void *p)
@@ -882,15 +879,10 @@ static void rtl8152_set_rx_mode(struct net_device *netdev)
 static void _rtl8152_set_rx_mode(struct net_device *netdev)
 {
        struct r8152 *tp = netdev_priv(netdev);
-       u32 tmp, *mc_filter;    /* Multicast hash filter */
+       u32 mc_filter[2];       /* Multicast hash filter */
+       __le32 tmp[2];
        u32 ocp_data;
 
-       mc_filter = kmalloc(sizeof(u32) * 2, GFP_KERNEL);
-       if (!mc_filter) {
-               netif_err(tp, link, netdev, "out of memory");
-               return;
-       }
-
        clear_bit(RTL8152_SET_RX_MODE, &tp->flags);
        netif_stop_queue(netdev);
        ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
@@ -918,14 +910,12 @@ static void _rtl8152_set_rx_mode(struct net_device *netdev)
                }
        }
 
-       tmp = mc_filter[0];
-       mc_filter[0] = __cpu_to_le32(swab32(mc_filter[1]));
-       mc_filter[1] = __cpu_to_le32(swab32(tmp));
+       tmp[0] = __cpu_to_le32(swab32(mc_filter[1]));
+       tmp[1] = __cpu_to_le32(swab32(mc_filter[0]));
 
-       pla_ocp_write(tp, PLA_MAR, BYTE_EN_DWORD, sizeof(u32) * 2, mc_filter);
+       pla_ocp_write(tp, PLA_MAR, BYTE_EN_DWORD, sizeof(tmp), tmp);
        ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
        netif_wake_queue(netdev);
-       kfree(mc_filter);
 }
 
 static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb,
index 852392269718e1892119a3c42d45c635f768a77f..2df2f4fb42a7c381fb68275bfab10052b7a71363 100644 (file)
 
 static int pla_read_word(struct usb_device *udev, u16 index)
 {
-       int data, ret;
+       int ret;
        u8 shift = index & 2;
-       __le32 ocp_data;
+       __le32 *tmp;
+
+       tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
+       if (!tmp)
+               return -ENOMEM;
 
        index &= ~3;
 
        ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
                              RTL815x_REQ_GET_REGS, RTL815x_REQT_READ,
-                             index, MCU_TYPE_PLA, &ocp_data, sizeof(ocp_data),
-                             500);
+                             index, MCU_TYPE_PLA, tmp, sizeof(*tmp), 500);
        if (ret < 0)
-               return ret;
+               goto out2;
 
-       data = __le32_to_cpu(ocp_data);
-       data >>= (shift * 8);
-       data &= 0xffff;
+       ret = __le32_to_cpu(*tmp);
+       ret >>= (shift * 8);
+       ret &= 0xffff;
 
-       return data;
+out2:
+       kfree(tmp);
+       return ret;
 }
 
 static int pla_write_word(struct usb_device *udev, u16 index, u32 data)
 {
-       __le32 ocp_data;
+       __le32 *tmp;
        u32 mask = 0xffff;
        u16 byen = BYTE_EN_WORD;
        u8 shift = index & 2;
        int ret;
 
+       tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
+       if (!tmp)
+               return -ENOMEM;
+
        data &= mask;
 
        if (shift) {
@@ -63,19 +72,20 @@ static int pla_write_word(struct usb_device *udev, u16 index, u32 data)
 
        ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
                              RTL815x_REQ_GET_REGS, RTL815x_REQT_READ,
-                             index, MCU_TYPE_PLA, &ocp_data, sizeof(ocp_data),
-                             500);
+                             index, MCU_TYPE_PLA, tmp, sizeof(*tmp), 500);
        if (ret < 0)
-               return ret;
+               goto out3;
 
-       data |= __le32_to_cpu(ocp_data) & ~mask;
-       ocp_data = __cpu_to_le32(data);
+       data |= __le32_to_cpu(*tmp) & ~mask;
+       *tmp = __cpu_to_le32(data);
 
        ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
                              RTL815x_REQ_SET_REGS, RTL815x_REQT_WRITE,
-                             index, MCU_TYPE_PLA | byen, &ocp_data,
-                             sizeof(ocp_data), 500);
+                             index, MCU_TYPE_PLA | byen, tmp, sizeof(*tmp),
+                             500);
 
+out3:
+       kfree(tmp);
        return ret;
 }
 
@@ -116,11 +126,18 @@ out1:
 static int r815x_mdio_read(struct net_device *netdev, int phy_id, int reg)
 {
        struct usbnet *dev = netdev_priv(netdev);
+       int ret;
 
        if (phy_id != R815x_PHY_ID)
                return -EINVAL;
 
-       return ocp_reg_read(dev, BASE_MII + reg * 2);
+       if (usb_autopm_get_interface(dev->intf) < 0)
+               return -ENODEV;
+
+       ret = ocp_reg_read(dev, BASE_MII + reg * 2);
+
+       usb_autopm_put_interface(dev->intf);
+       return ret;
 }
 
 static
@@ -131,7 +148,12 @@ void r815x_mdio_write(struct net_device *netdev, int phy_id, int reg, int val)
        if (phy_id != R815x_PHY_ID)
                return;
 
+       if (usb_autopm_get_interface(dev->intf) < 0)
+               return;
+
        ocp_reg_write(dev, BASE_MII + reg * 2, val);
+
+       usb_autopm_put_interface(dev->intf);
 }
 
 static int r8153_bind(struct usbnet *dev, struct usb_interface *intf)
@@ -150,7 +172,7 @@ static int r8153_bind(struct usbnet *dev, struct usb_interface *intf)
        dev->mii.phy_id = R815x_PHY_ID;
        dev->mii.supports_gmii = 1;
 
-       return 0;
+       return status;
 }
 
 static int r8152_bind(struct usbnet *dev, struct usb_interface *intf)
@@ -169,7 +191,7 @@ static int r8152_bind(struct usbnet *dev, struct usb_interface *intf)
        dev->mii.phy_id = R815x_PHY_ID;
        dev->mii.supports_gmii = 0;
 
-       return 0;
+       return status;
 }
 
 static const struct driver_info r8152_info = {
index 75409748c77470da8cc5bcc7390e9f4c5a94ea6a..66ebbacf066f6692ba21d2fa07538535827074b9 100644 (file)
@@ -45,7 +45,6 @@
 #define EEPROM_MAC_OFFSET              (0x01)
 #define DEFAULT_TX_CSUM_ENABLE         (true)
 #define DEFAULT_RX_CSUM_ENABLE         (true)
-#define DEFAULT_TSO_ENABLE             (true)
 #define SMSC75XX_INTERNAL_PHY_ID       (1)
 #define SMSC75XX_TX_OVERHEAD           (8)
 #define MAX_RX_FIFO_SIZE               (20 * 1024)
@@ -1410,17 +1409,14 @@ static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf)
 
        INIT_WORK(&pdata->set_multicast, smsc75xx_deferred_multicast_write);
 
-       if (DEFAULT_TX_CSUM_ENABLE) {
+       if (DEFAULT_TX_CSUM_ENABLE)
                dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
-               if (DEFAULT_TSO_ENABLE)
-                       dev->net->features |= NETIF_F_SG |
-                               NETIF_F_TSO | NETIF_F_TSO6;
-       }
+
        if (DEFAULT_RX_CSUM_ENABLE)
                dev->net->features |= NETIF_F_RXCSUM;
 
        dev->net->hw_features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
-               NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_RXCSUM;
+                               NETIF_F_RXCSUM;
 
        ret = smsc75xx_wait_ready(dev, 0);
        if (ret < 0) {
@@ -2200,8 +2196,6 @@ static struct sk_buff *smsc75xx_tx_fixup(struct usbnet *dev,
 {
        u32 tx_cmd_a, tx_cmd_b;
 
-       skb_linearize(skb);
-
        if (skb_headroom(skb) < SMSC75XX_TX_OVERHEAD) {
                struct sk_buff *skb2 =
                        skb_copy_expand(skb, SMSC75XX_TX_OVERHEAD, 0, flags);
index 06ee82f557d45ba31b4847c187f57771ae2c73d2..e4811d7b5af1cb19aad389f231781cede61c3f81 100644 (file)
  * For high speed, each frame comfortably fits almost 36 max size
  * Ethernet packets (so queues should be bigger).
  *
- * REVISIT qlens should be members of 'struct usbnet'; the goal is to
- * let the USB host controller be busy for 5msec or more before an irq
- * is required, under load.  Jumbograms change the equation.
+ * The goal is to let the USB host controller be busy for 5msec or
+ * more before an irq is required, under load.  Jumbograms change
+ * the equation.
  */
-#define RX_MAX_QUEUE_MEMORY (60 * 1518)
-#define        RX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? \
-                       (RX_MAX_QUEUE_MEMORY/(dev)->rx_urb_size) : 4)
-#define        TX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? \
-                       (RX_MAX_QUEUE_MEMORY/(dev)->hard_mtu) : 4)
+#define        MAX_QUEUE_MEMORY        (60 * 1518)
+#define        RX_QLEN(dev)            ((dev)->rx_qlen)
+#define        TX_QLEN(dev)            ((dev)->tx_qlen)
 
 // reawaken network queue this soon after stopping; else watchdog barks
 #define TX_TIMEOUT_JIFFIES     (5*HZ)
@@ -347,6 +345,31 @@ void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb)
 }
 EXPORT_SYMBOL_GPL(usbnet_skb_return);
 
+/* must be called if hard_mtu or rx_urb_size changed */
+void usbnet_update_max_qlen(struct usbnet *dev)
+{
+       enum usb_device_speed speed = dev->udev->speed;
+
+       switch (speed) {
+       case USB_SPEED_HIGH:
+               dev->rx_qlen = MAX_QUEUE_MEMORY / dev->rx_urb_size;
+               dev->tx_qlen = MAX_QUEUE_MEMORY / dev->hard_mtu;
+               break;
+       case USB_SPEED_SUPER:
+               /*
+                * Not take default 5ms qlen for super speed HC to
+                * save memory, and iperf tests show 2.5ms qlen can
+                * work well
+                */
+               dev->rx_qlen = 5 * MAX_QUEUE_MEMORY / dev->rx_urb_size;
+               dev->tx_qlen = 5 * MAX_QUEUE_MEMORY / dev->hard_mtu;
+               break;
+       default:
+               dev->rx_qlen = dev->tx_qlen = 4;
+       }
+}
+EXPORT_SYMBOL_GPL(usbnet_update_max_qlen);
+
 \f
 /*-------------------------------------------------------------------------
  *
@@ -375,6 +398,9 @@ int usbnet_change_mtu (struct net_device *net, int new_mtu)
                        usbnet_unlink_rx_urbs(dev);
        }
 
+       /* max qlen depend on hard_mtu and rx_urb_size */
+       usbnet_update_max_qlen(dev);
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(usbnet_change_mtu);
@@ -843,6 +869,9 @@ int usbnet_open (struct net_device *net)
                goto done;
        }
 
+       /* hard_mtu or rx_urb_size may change in reset() */
+       usbnet_update_max_qlen(dev);
+
        // insist peer be connected
        if (info->check_connect && (retval = info->check_connect (dev)) < 0) {
                netif_dbg(dev, ifup, dev->net, "can't open; %d\n", retval);
@@ -927,6 +956,9 @@ int usbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd)
        if (dev->driver_info->link_reset)
                dev->driver_info->link_reset(dev);
 
+       /* hard_mtu or rx_urb_size may change in link_reset() */
+       usbnet_update_max_qlen(dev);
+
        return retval;
 
 }
@@ -1020,6 +1052,9 @@ static void __handle_link_change(struct usbnet *dev)
                tasklet_schedule(&dev->bh);
        }
 
+       /* hard_mtu or rx_urb_size may change during link change */
+       usbnet_update_max_qlen(dev);
+
        clear_bit(EVENT_LINK_CHANGE, &dev->flags);
 }
 
@@ -1599,6 +1634,9 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
        if ((dev->driver_info->flags & FLAG_WWAN) != 0)
                SET_NETDEV_DEVTYPE(net, &wwan_type);
 
+       /* initialize max rx_qlen and tx_qlen */
+       usbnet_update_max_qlen(dev);
+
        status = register_netdev (net);
        if (status)
                goto out4;
index da866523cf20097d57550c7357020e937782fd37..eee1f19ef1e9397469e343133490ec6972b4bbdc 100644 (file)
@@ -269,6 +269,7 @@ static void veth_setup(struct net_device *dev)
        dev->ethtool_ops = &veth_ethtool_ops;
        dev->features |= NETIF_F_LLTX;
        dev->features |= VETH_FEATURES;
+       dev->vlan_features = dev->features;
        dev->destructor = veth_dev_free;
 
        dev->hw_features = VETH_FEATURES;
index 3d2a90a626498d20c96ba7729beacec16b9b5040..f21600277583fac0b9e1a78065ccf588d8bc2f6d 100644 (file)
@@ -106,6 +106,9 @@ struct virtnet_info {
        /* Has control virtqueue */
        bool has_cvq;
 
+       /* Host can handle any s/g split between our header and packet data */
+       bool any_header_sg;
+
        /* enable config space updates */
        bool config_enable;
 
@@ -669,12 +672,28 @@ static void free_old_xmit_skbs(struct send_queue *sq)
 
 static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
 {
-       struct skb_vnet_hdr *hdr = skb_vnet_hdr(skb);
+       struct skb_vnet_hdr *hdr;
        const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
        struct virtnet_info *vi = sq->vq->vdev->priv;
        unsigned num_sg;
+       unsigned hdr_len;
+       bool can_push;
 
        pr_debug("%s: xmit %p %pM\n", vi->dev->name, skb, dest);
+       if (vi->mergeable_rx_bufs)
+               hdr_len = sizeof hdr->mhdr;
+       else
+               hdr_len = sizeof hdr->hdr;
+
+       can_push = vi->any_header_sg &&
+               !((unsigned long)skb->data & (__alignof__(*hdr) - 1)) &&
+               !skb_header_cloned(skb) && skb_headroom(skb) >= hdr_len;
+       /* Even if we can, don't push here yet as this would skew
+        * csum_start offset below. */
+       if (can_push)
+               hdr = (struct skb_vnet_hdr *)(skb->data - hdr_len);
+       else
+               hdr = skb_vnet_hdr(skb);
 
        if (skb->ip_summed == CHECKSUM_PARTIAL) {
                hdr->hdr.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
@@ -703,15 +722,18 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
                hdr->hdr.gso_size = hdr->hdr.hdr_len = 0;
        }
 
-       hdr->mhdr.num_buffers = 0;
-
-       /* Encode metadata header at front. */
        if (vi->mergeable_rx_bufs)
-               sg_set_buf(sq->sg, &hdr->mhdr, sizeof hdr->mhdr);
-       else
-               sg_set_buf(sq->sg, &hdr->hdr, sizeof hdr->hdr);
+               hdr->mhdr.num_buffers = 0;
 
-       num_sg = skb_to_sgvec(skb, sq->sg + 1, 0, skb->len) + 1;
+       if (can_push) {
+               __skb_push(skb, hdr_len);
+               num_sg = skb_to_sgvec(skb, sq->sg, 0, skb->len);
+               /* Pull header back to avoid skew in tx bytes calculations. */
+               __skb_pull(skb, hdr_len);
+       } else {
+               sg_set_buf(sq->sg, hdr, hdr_len);
+               num_sg = skb_to_sgvec(skb, sq->sg + 1, 0, skb->len) + 1;
+       }
        return virtqueue_add_outbuf(sq->vq, sq->sg, num_sg, skb, GFP_ATOMIC);
 }
 
@@ -1552,6 +1574,9 @@ static int virtnet_probe(struct virtio_device *vdev)
        if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
                vi->mergeable_rx_bufs = true;
 
+       if (virtio_has_feature(vdev, VIRTIO_F_ANY_LAYOUT))
+               vi->any_header_sg = true;
+
        if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
                vi->has_cvq = true;
 
@@ -1727,6 +1752,7 @@ static unsigned int features[] = {
        VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN,
        VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ,
        VIRTIO_NET_F_CTRL_MAC_ADDR,
+       VIRTIO_F_ANY_LAYOUT,
 };
 
 static struct virtio_driver virtio_net_driver = {
index a5ba8dd7e6bea33d060e9d5306b9eab6bb2095da..c3dd6e496327d1dca0886b2140d485ac27f194ed 100644 (file)
@@ -136,7 +136,8 @@ struct vxlan_dev {
        u32               flags;        /* VXLAN_F_* below */
 
        struct work_struct sock_work;
-       struct work_struct igmp_work;
+       struct work_struct igmp_join;
+       struct work_struct igmp_leave;
 
        unsigned long     age_interval;
        struct timer_list age_timer;
@@ -407,6 +408,26 @@ static struct vxlan_rdst *vxlan_fdb_find_rdst(struct vxlan_fdb *f,
        return NULL;
 }
 
+/* Replace destination of unicast mac */
+static int vxlan_fdb_replace(struct vxlan_fdb *f,
+                           __be32 ip, __be16 port, __u32 vni, __u32 ifindex)
+{
+       struct vxlan_rdst *rd;
+
+       rd = vxlan_fdb_find_rdst(f, ip, port, vni, ifindex);
+       if (rd)
+               return 0;
+
+       rd = list_first_entry_or_null(&f->remotes, struct vxlan_rdst, list);
+       if (!rd)
+               return 0;
+       rd->remote_ip = ip;
+       rd->remote_port = port;
+       rd->remote_vni = vni;
+       rd->remote_ifindex = ifindex;
+       return 1;
+}
+
 /* Add/update destinations for multicast */
 static int vxlan_fdb_append(struct vxlan_fdb *f,
                            __be32 ip, __be16 port, __u32 vni, __u32 ifindex)
@@ -457,6 +478,19 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan,
                        f->updated = jiffies;
                        notify = 1;
                }
+               if ((flags & NLM_F_REPLACE)) {
+                       /* Only change unicasts */
+                       if (!(is_multicast_ether_addr(f->eth_addr) ||
+                            is_zero_ether_addr(f->eth_addr))) {
+                               int rc = vxlan_fdb_replace(f, ip, port, vni,
+                                                          ifindex);
+
+                               if (rc < 0)
+                                       return rc;
+                               notify |= rc;
+                       } else
+                               return -EOPNOTSUPP;
+               }
                if ((flags & NLM_F_APPEND) &&
                    (is_multicast_ether_addr(f->eth_addr) ||
                     is_zero_ether_addr(f->eth_addr))) {
@@ -473,6 +507,11 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan,
                if (vxlan->addrmax && vxlan->addrcnt >= vxlan->addrmax)
                        return -ENOSPC;
 
+               /* Disallow replace to add a multicast entry */
+               if ((flags & NLM_F_REPLACE) &&
+                   (is_multicast_ether_addr(mac) || is_zero_ether_addr(mac)))
+                       return -EOPNOTSUPP;
+
                netdev_dbg(vxlan->dev, "add %pM -> %pI4\n", mac, &ip);
                f = kmalloc(sizeof(*f), GFP_ATOMIC);
                if (!f)
@@ -736,7 +775,6 @@ static bool vxlan_snoop(struct net_device *dev,
        return false;
 }
 
-
 /* See if multicast group is already in use by other ID */
 static bool vxlan_group_used(struct vxlan_net *vn, __be32 remote_ip)
 {
@@ -770,12 +808,13 @@ static void vxlan_sock_release(struct vxlan_net *vn, struct vxlan_sock *vs)
        queue_work(vxlan_wq, &vs->del_work);
 }
 
-/* Callback to update multicast group membership.
- * Scheduled when vxlan goes up/down.
+/* Callback to update multicast group membership when first VNI on
+ * multicast asddress is brought up
+ * Done as workqueue because ip_mc_join_group acquires RTNL.
  */
-static void vxlan_igmp_work(struct work_struct *work)
+static void vxlan_igmp_join(struct work_struct *work)
 {
-       struct vxlan_dev *vxlan = container_of(work, struct vxlan_dev, igmp_work);
+       struct vxlan_dev *vxlan = container_of(work, struct vxlan_dev, igmp_join);
        struct vxlan_net *vn = net_generic(dev_net(vxlan->dev), vxlan_net_id);
        struct vxlan_sock *vs = vxlan->vn_sock;
        struct sock *sk = vs->sock->sk;
@@ -785,10 +824,27 @@ static void vxlan_igmp_work(struct work_struct *work)
        };
 
        lock_sock(sk);
-       if (vxlan_group_used(vn, vxlan->default_dst.remote_ip))
-               ip_mc_join_group(sk, &mreq);
-       else
-               ip_mc_leave_group(sk, &mreq);
+       ip_mc_join_group(sk, &mreq);
+       release_sock(sk);
+
+       vxlan_sock_release(vn, vs);
+       dev_put(vxlan->dev);
+}
+
+/* Inverse of vxlan_igmp_join when last VNI is brought down */
+static void vxlan_igmp_leave(struct work_struct *work)
+{
+       struct vxlan_dev *vxlan = container_of(work, struct vxlan_dev, igmp_leave);
+       struct vxlan_net *vn = net_generic(dev_net(vxlan->dev), vxlan_net_id);
+       struct vxlan_sock *vs = vxlan->vn_sock;
+       struct sock *sk = vs->sock->sk;
+       struct ip_mreqn mreq = {
+               .imr_multiaddr.s_addr   = vxlan->default_dst.remote_ip,
+               .imr_ifindex            = vxlan->default_dst.remote_ifindex,
+       };
+
+       lock_sock(sk);
+       ip_mc_leave_group(sk, &mreq);
        release_sock(sk);
 
        vxlan_sock_release(vn, vs);
@@ -1359,6 +1415,7 @@ static void vxlan_uninit(struct net_device *dev)
 /* Start ageing timer and join group when device is brought up */
 static int vxlan_open(struct net_device *dev)
 {
+       struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id);
        struct vxlan_dev *vxlan = netdev_priv(dev);
        struct vxlan_sock *vs = vxlan->vn_sock;
 
@@ -1366,10 +1423,11 @@ static int vxlan_open(struct net_device *dev)
        if (!vs)
                return -ENOTCONN;
 
-       if (IN_MULTICAST(ntohl(vxlan->default_dst.remote_ip))) {
+       if (IN_MULTICAST(ntohl(vxlan->default_dst.remote_ip)) &&
+           ! vxlan_group_used(vn, vxlan->default_dst.remote_ip)) {
                vxlan_sock_hold(vs);
                dev_hold(dev);
-               queue_work(vxlan_wq, &vxlan->igmp_work);
+               queue_work(vxlan_wq, &vxlan->igmp_join);
        }
 
        if (vxlan->age_interval)
@@ -1400,13 +1458,15 @@ static void vxlan_flush(struct vxlan_dev *vxlan)
 /* Cleanup timer and forwarding table on shutdown */
 static int vxlan_stop(struct net_device *dev)
 {
+       struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id);
        struct vxlan_dev *vxlan = netdev_priv(dev);
        struct vxlan_sock *vs = vxlan->vn_sock;
 
-       if (vs && IN_MULTICAST(ntohl(vxlan->default_dst.remote_ip))) {
+       if (vs && IN_MULTICAST(ntohl(vxlan->default_dst.remote_ip)) &&
+           ! vxlan_group_used(vn, vxlan->default_dst.remote_ip)) {
                vxlan_sock_hold(vs);
                dev_hold(dev);
-               queue_work(vxlan_wq, &vxlan->igmp_work);
+               queue_work(vxlan_wq, &vxlan->igmp_leave);
        }
 
        del_timer_sync(&vxlan->age_timer);
@@ -1471,7 +1531,8 @@ static void vxlan_setup(struct net_device *dev)
 
        INIT_LIST_HEAD(&vxlan->next);
        spin_lock_init(&vxlan->hash_lock);
-       INIT_WORK(&vxlan->igmp_work, vxlan_igmp_work);
+       INIT_WORK(&vxlan->igmp_join, vxlan_igmp_join);
+       INIT_WORK(&vxlan->igmp_leave, vxlan_igmp_leave);
        INIT_WORK(&vxlan->sock_work, vxlan_sock_work);
 
        init_timer_deferrable(&vxlan->age_timer);
@@ -1878,10 +1939,12 @@ static __net_exit void vxlan_exit_net(struct net *net)
 {
        struct vxlan_net *vn = net_generic(net, vxlan_net_id);
        struct vxlan_dev *vxlan;
+       LIST_HEAD(list);
 
        rtnl_lock();
        list_for_each_entry(vxlan, &vn->vxlan_list, next)
-               dev_close(vxlan->dev);
+               unregister_netdevice_queue(vxlan->dev, &list);
+       unregister_netdevice_many(&list);
        rtnl_unlock();
 }
 
index cde58fe962543dff415d45f2be2ae06d0d7ceb91..82e8088ca9b4944e5cb13c3fb3c2b14c7af27efe 100644 (file)
@@ -1,6 +1,6 @@
 config ATH10K
         tristate "Atheros 802.11ac wireless cards support"
-        depends on MAC80211
+        depends on MAC80211 && HAS_DMA
        select ATH_COMMON
         ---help---
           This module adds support for wireless adapters based on
index 81b686c6a3764111e8c8e969a90d36d6ced054ea..40825d43322edb511862c90bd2587395745852e7 100644 (file)
@@ -325,7 +325,7 @@ ath5k_prepare_multicast(struct ieee80211_hw *hw,
        struct netdev_hw_addr *ha;
 
        mfilt[0] = 0;
-       mfilt[1] = 1;
+       mfilt[1] = 0;
 
        netdev_hw_addr_list_for_each(ha, mc_list) {
                /* calculate XOR of eight 6-bit values */
index d491a31789863fa08ce24a2282b2ab72b10bf949..c91bc6111c230afe64542d5d3a3e0a71a15d5a42 100644 (file)
@@ -96,6 +96,16 @@ config ATH9K_LEGACY_RATE_CONTROL
          has to be passed to mac80211 using the module parameter,
          ieee80211_default_rc_algo.
 
+config ATH9K_RFKILL
+       bool "Atheros ath9k rfkill support" if EXPERT
+       depends on ATH9K
+       depends on RFKILL=y || RFKILL=ATH9K
+       default y
+       help
+         Say Y to have ath9k poll the RF-Kill GPIO every couple of
+         seconds. Turn off to save power, but enable it if you have
+         a platform that can toggle the RF-Kill GPIO.
+
 config ATH9K_HTC
        tristate "Atheros HTC based wireless cards support"
        depends on USB && MAC80211
index 664844c5d3d51ae8752514bb3976fa2074ba0afe..291ca019d37b76c98bffe22ee4b3a00300ac4959 100644 (file)
@@ -25,28 +25,45 @@ static inline bool ath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta,
                (alt_rssi_avg > main_rssi_avg + mindelta)) && (pkt_count > 50);
 }
 
-static inline bool ath_ant_div_comb_alt_check(u8 div_group, int alt_ratio,
-                                             int curr_main_set, int curr_alt_set,
-                                             int alt_rssi_avg, int main_rssi_avg)
+static inline bool ath_ant_div_comb_alt_check(struct ath_hw_antcomb_conf *conf,
+                                             int alt_ratio, int alt_rssi_avg,
+                                             int main_rssi_avg)
 {
-       bool result = false;
-       switch (div_group) {
+       bool result, set1, set2;
+
+       result = set1 = set2 = false;
+
+       if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2 &&
+           conf->alt_lna_conf == ATH_ANT_DIV_COMB_LNA1)
+               set1 = true;
+
+       if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA1 &&
+           conf->alt_lna_conf == ATH_ANT_DIV_COMB_LNA2)
+               set2 = true;
+
+       switch (conf->div_group) {
        case 0:
                if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
                        result = true;
                break;
        case 1:
        case 2:
-               if ((((curr_main_set == ATH_ANT_DIV_COMB_LNA2) &&
-                     (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) &&
-                     (alt_rssi_avg >= (main_rssi_avg - 5))) ||
-                    ((curr_main_set == ATH_ANT_DIV_COMB_LNA1) &&
-                     (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) &&
-                     (alt_rssi_avg >= (main_rssi_avg - 2)))) &&
-                   (alt_rssi_avg >= 4))
+               if (alt_rssi_avg < 4)
+                       break;
+
+               if ((set1 && (alt_rssi_avg >= (main_rssi_avg - 5))) ||
+                   (set2 && (alt_rssi_avg >= (main_rssi_avg - 2))))
                        result = true;
-               else
-                       result = false;
+
+               break;
+       case 3:
+               if (alt_rssi_avg < 4)
+                       break;
+
+               if ((set1 && (alt_rssi_avg >= (main_rssi_avg - 3))) ||
+                   (set2 && (alt_rssi_avg >= (main_rssi_avg + 3))))
+                       result = true;
+
                break;
        }
 
@@ -108,6 +125,74 @@ static void ath_lnaconf_alt_good_scan(struct ath_ant_comb *antcomb,
        }
 }
 
+static void ath_ant_set_alt_ratio(struct ath_ant_comb *antcomb,
+                                 struct ath_hw_antcomb_conf *conf)
+{
+       /* set alt to the conf with maximun ratio */
+       if (antcomb->first_ratio && antcomb->second_ratio) {
+               if (antcomb->rssi_second > antcomb->rssi_third) {
+                       /* first alt*/
+                       if ((antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) ||
+                           (antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2))
+                               /* Set alt LNA1 or LNA2*/
+                               if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
+                                       conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
+                               else
+                                       conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
+                       else
+                               /* Set alt to A+B or A-B */
+                               conf->alt_lna_conf =
+                                       antcomb->first_quick_scan_conf;
+               } else if ((antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) ||
+                          (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2)) {
+                       /* Set alt LNA1 or LNA2 */
+                       if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
+                               conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
+                       else
+                               conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
+               } else {
+                       /* Set alt to A+B or A-B */
+                       conf->alt_lna_conf = antcomb->second_quick_scan_conf;
+               }
+       } else if (antcomb->first_ratio) {
+               /* first alt */
+               if ((antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) ||
+                   (antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2))
+                       /* Set alt LNA1 or LNA2 */
+                       if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
+                               conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
+                       else
+                               conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
+               else
+                       /* Set alt to A+B or A-B */
+                       conf->alt_lna_conf = antcomb->first_quick_scan_conf;
+       } else if (antcomb->second_ratio) {
+               /* second alt */
+               if ((antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) ||
+                   (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2))
+                       /* Set alt LNA1 or LNA2 */
+                       if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
+                               conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
+                       else
+                               conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
+               else
+                       /* Set alt to A+B or A-B */
+                       conf->alt_lna_conf = antcomb->second_quick_scan_conf;
+       } else {
+               /* main is largest */
+               if ((antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) ||
+                   (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2))
+                       /* Set alt LNA1 or LNA2 */
+                       if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
+                               conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
+                       else
+                               conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
+               else
+                       /* Set alt to A+B or A-B */
+                       conf->alt_lna_conf = antcomb->main_conf;
+       }
+}
+
 static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb,
                                       struct ath_hw_antcomb_conf *div_ant_conf,
                                       int main_rssi_avg, int alt_rssi_avg,
@@ -147,11 +232,11 @@ static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb,
                        else
                                antcomb->first_ratio = false;
                } else {
-                       if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
-                             (alt_rssi_avg > main_rssi_avg +
-                              ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
-                            (alt_rssi_avg > main_rssi_avg)) &&
-                           (antcomb->total_pkt_count > 50))
+                       if (ath_is_alt_ant_ratio_better(alt_ratio,
+                                               ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
+                                               0,
+                                               main_rssi_avg, alt_rssi_avg,
+                                               antcomb->total_pkt_count))
                                antcomb->first_ratio = true;
                        else
                                antcomb->first_ratio = false;
@@ -164,17 +249,21 @@ static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb,
                antcomb->rssi_first = main_rssi_avg;
                antcomb->rssi_third = alt_rssi_avg;
 
-               if (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1)
+               switch(antcomb->second_quick_scan_conf) {
+               case ATH_ANT_DIV_COMB_LNA1:
                        antcomb->rssi_lna1 = alt_rssi_avg;
-               else if (antcomb->second_quick_scan_conf ==
-                        ATH_ANT_DIV_COMB_LNA2)
+                       break;
+               case ATH_ANT_DIV_COMB_LNA2:
                        antcomb->rssi_lna2 = alt_rssi_avg;
-               else if (antcomb->second_quick_scan_conf ==
-                        ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2) {
+                       break;
+               case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
                        if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2)
                                antcomb->rssi_lna2 = main_rssi_avg;
                        else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1)
                                antcomb->rssi_lna1 = main_rssi_avg;
+                       break;
+               default:
+                       break;
                }
 
                if (antcomb->rssi_lna2 > antcomb->rssi_lna1 +
@@ -202,105 +291,18 @@ static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb,
                        else
                                antcomb->second_ratio = false;
                } else {
-                       if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
-                             (alt_rssi_avg > main_rssi_avg +
-                              ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
-                            (alt_rssi_avg > main_rssi_avg)) &&
-                           (antcomb->total_pkt_count > 50))
+                       if (ath_is_alt_ant_ratio_better(alt_ratio,
+                                               ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
+                                               0,
+                                               main_rssi_avg, alt_rssi_avg,
+                                               antcomb->total_pkt_count))
                                antcomb->second_ratio = true;
                        else
                                antcomb->second_ratio = false;
                }
 
-               /* set alt to the conf with maximun ratio */
-               if (antcomb->first_ratio && antcomb->second_ratio) {
-                       if (antcomb->rssi_second > antcomb->rssi_third) {
-                               /* first alt*/
-                               if ((antcomb->first_quick_scan_conf ==
-                                   ATH_ANT_DIV_COMB_LNA1) ||
-                                   (antcomb->first_quick_scan_conf ==
-                                   ATH_ANT_DIV_COMB_LNA2))
-                                       /* Set alt LNA1 or LNA2*/
-                                       if (div_ant_conf->main_lna_conf ==
-                                           ATH_ANT_DIV_COMB_LNA2)
-                                               div_ant_conf->alt_lna_conf =
-                                                       ATH_ANT_DIV_COMB_LNA1;
-                                       else
-                                               div_ant_conf->alt_lna_conf =
-                                                       ATH_ANT_DIV_COMB_LNA2;
-                               else
-                                       /* Set alt to A+B or A-B */
-                                       div_ant_conf->alt_lna_conf =
-                                               antcomb->first_quick_scan_conf;
-                       } else if ((antcomb->second_quick_scan_conf ==
-                                  ATH_ANT_DIV_COMB_LNA1) ||
-                                  (antcomb->second_quick_scan_conf ==
-                                  ATH_ANT_DIV_COMB_LNA2)) {
-                               /* Set alt LNA1 or LNA2 */
-                               if (div_ant_conf->main_lna_conf ==
-                                   ATH_ANT_DIV_COMB_LNA2)
-                                       div_ant_conf->alt_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA1;
-                               else
-                                       div_ant_conf->alt_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA2;
-                       } else {
-                               /* Set alt to A+B or A-B */
-                               div_ant_conf->alt_lna_conf =
-                                       antcomb->second_quick_scan_conf;
-                       }
-               } else if (antcomb->first_ratio) {
-                       /* first alt */
-                       if ((antcomb->first_quick_scan_conf ==
-                           ATH_ANT_DIV_COMB_LNA1) ||
-                           (antcomb->first_quick_scan_conf ==
-                           ATH_ANT_DIV_COMB_LNA2))
-                                       /* Set alt LNA1 or LNA2 */
-                               if (div_ant_conf->main_lna_conf ==
-                                   ATH_ANT_DIV_COMB_LNA2)
-                                       div_ant_conf->alt_lna_conf =
-                                                       ATH_ANT_DIV_COMB_LNA1;
-                               else
-                                       div_ant_conf->alt_lna_conf =
-                                                       ATH_ANT_DIV_COMB_LNA2;
-                       else
-                               /* Set alt to A+B or A-B */
-                               div_ant_conf->alt_lna_conf =
-                                               antcomb->first_quick_scan_conf;
-               } else if (antcomb->second_ratio) {
-                               /* second alt */
-                       if ((antcomb->second_quick_scan_conf ==
-                           ATH_ANT_DIV_COMB_LNA1) ||
-                           (antcomb->second_quick_scan_conf ==
-                           ATH_ANT_DIV_COMB_LNA2))
-                               /* Set alt LNA1 or LNA2 */
-                               if (div_ant_conf->main_lna_conf ==
-                                   ATH_ANT_DIV_COMB_LNA2)
-                                       div_ant_conf->alt_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA1;
-                               else
-                                       div_ant_conf->alt_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA2;
-                       else
-                               /* Set alt to A+B or A-B */
-                               div_ant_conf->alt_lna_conf =
-                                               antcomb->second_quick_scan_conf;
-               } else {
-                       /* main is largest */
-                       if ((antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) ||
-                           (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2))
-                               /* Set alt LNA1 or LNA2 */
-                               if (div_ant_conf->main_lna_conf ==
-                                   ATH_ANT_DIV_COMB_LNA2)
-                                       div_ant_conf->alt_lna_conf =
-                                                       ATH_ANT_DIV_COMB_LNA1;
-                               else
-                                       div_ant_conf->alt_lna_conf =
-                                                       ATH_ANT_DIV_COMB_LNA2;
-                       else
-                               /* Set alt to A+B or A-B */
-                               div_ant_conf->alt_lna_conf = antcomb->main_conf;
-               }
+               ath_ant_set_alt_ratio(antcomb, div_ant_conf);
+
                break;
        default:
                break;
@@ -540,6 +542,137 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf,
        }
 }
 
+static void ath_ant_try_scan(struct ath_ant_comb *antcomb,
+                            struct ath_hw_antcomb_conf *conf,
+                            int curr_alt_set, int alt_rssi_avg,
+                            int main_rssi_avg)
+{
+       switch (curr_alt_set) {
+       case ATH_ANT_DIV_COMB_LNA2:
+               antcomb->rssi_lna2 = alt_rssi_avg;
+               antcomb->rssi_lna1 = main_rssi_avg;
+               antcomb->scan = true;
+               /* set to A+B */
+               conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
+               conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+               break;
+       case ATH_ANT_DIV_COMB_LNA1:
+               antcomb->rssi_lna1 = alt_rssi_avg;
+               antcomb->rssi_lna2 = main_rssi_avg;
+               antcomb->scan = true;
+               /* set to A+B */
+               conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
+               conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+               break;
+       case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
+               antcomb->rssi_add = alt_rssi_avg;
+               antcomb->scan = true;
+               /* set to A-B */
+               conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+               break;
+       case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2:
+               antcomb->rssi_sub = alt_rssi_avg;
+               antcomb->scan = false;
+               if (antcomb->rssi_lna2 >
+                   (antcomb->rssi_lna1 + ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) {
+                       /* use LNA2 as main LNA */
+                       if ((antcomb->rssi_add > antcomb->rssi_lna1) &&
+                           (antcomb->rssi_add > antcomb->rssi_sub)) {
+                               /* set to A+B */
+                               conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
+                               conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+                       } else if (antcomb->rssi_sub >
+                                  antcomb->rssi_lna1) {
+                               /* set to A-B */
+                               conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
+                               conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+                       } else {
+                               /* set to LNA1 */
+                               conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
+                               conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
+                       }
+               } else {
+                       /* use LNA1 as main LNA */
+                       if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
+                           (antcomb->rssi_add > antcomb->rssi_sub)) {
+                               /* set to A+B */
+                               conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
+                               conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+                       } else if (antcomb->rssi_sub >
+                                  antcomb->rssi_lna1) {
+                               /* set to A-B */
+                               conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
+                               conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+                       } else {
+                               /* set to LNA2 */
+                               conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
+                               conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
+                       }
+               }
+               break;
+       default:
+               break;
+       }
+}
+
+static bool ath_ant_try_switch(struct ath_hw_antcomb_conf *div_ant_conf,
+                              int alt_ratio, int alt_rssi_avg,
+                              int main_rssi_avg, int curr_main_set,
+                              int curr_alt_set)
+{
+       bool ret = false;
+
+       if (ath_ant_div_comb_alt_check(div_ant_conf, alt_ratio,
+                                      alt_rssi_avg, main_rssi_avg)) {
+               if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) {
+                       /*
+                        * Switch main and alt LNA.
+                        */
+                       div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
+                       div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
+               } else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) {
+                       div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
+                       div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
+               }
+
+               ret = true;
+       } else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) &&
+                  (curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) {
+               /*
+                 Set alt to another LNA.
+               */
+               if (curr_main_set == ATH_ANT_DIV_COMB_LNA2)
+                       div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
+               else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1)
+                       div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
+
+               ret = true;
+       }
+
+       return ret;
+}
+
+static bool ath_ant_short_scan_check(struct ath_ant_comb *antcomb)
+{
+       int alt_ratio;
+
+       if (!antcomb->scan || !antcomb->alt_good)
+               return false;
+
+       if (time_after(jiffies, antcomb->scan_start_time +
+                      msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
+               return true;
+
+       if (antcomb->total_pkt_count == ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) {
+               alt_ratio = ((antcomb->alt_recv_cnt * 100) /
+                            antcomb->total_pkt_count);
+               if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
+                       return true;
+       }
+
+       return false;
+}
+
 void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
 {
        struct ath_hw_antcomb_conf div_ant_conf;
@@ -549,7 +682,7 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
        int main_rssi = rs->rs_rssi_ctl0;
        int alt_rssi = rs->rs_rssi_ctl1;
        int rx_ant_conf,  main_ant_conf;
-       bool short_scan = false;
+       bool short_scan = false, ret;
 
        rx_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_CURRENT_SHIFT) &
                       ATH_ANT_RX_MASK;
@@ -561,29 +694,26 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
                antcomb->total_pkt_count++;
                antcomb->main_total_rssi += main_rssi;
                antcomb->alt_total_rssi  += alt_rssi;
+
                if (main_ant_conf == rx_ant_conf)
                        antcomb->main_recv_cnt++;
                else
                        antcomb->alt_recv_cnt++;
        }
 
-       /* Short scan check */
-       if (antcomb->scan && antcomb->alt_good) {
-               if (time_after(jiffies, antcomb->scan_start_time +
-                   msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
-                       short_scan = true;
-               else
-                       if (antcomb->total_pkt_count ==
-                           ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) {
-                               alt_ratio = ((antcomb->alt_recv_cnt * 100) /
-                                           antcomb->total_pkt_count);
-                               if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
-                                       short_scan = true;
-                       }
+       if (main_ant_conf == rx_ant_conf) {
+               ANT_STAT_INC(ANT_MAIN, recv_cnt);
+               ANT_LNA_INC(ANT_MAIN, rx_ant_conf);
+       } else {
+               ANT_STAT_INC(ANT_ALT, recv_cnt);
+               ANT_LNA_INC(ANT_ALT, rx_ant_conf);
        }
 
+       /* Short scan check */
+       short_scan = ath_ant_short_scan_check(antcomb);
+
        if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) ||
-           rs->rs_moreaggr) && !short_scan)
+            rs->rs_moreaggr) && !short_scan)
                return;
 
        if (antcomb->total_pkt_count) {
@@ -595,11 +725,9 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
                                 antcomb->total_pkt_count);
        }
 
-
        ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf);
        curr_alt_set = div_ant_conf.alt_lna_conf;
        curr_main_set = div_ant_conf.main_lna_conf;
-
        antcomb->count++;
 
        if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) {
@@ -617,153 +745,47 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
        }
 
        if (!antcomb->scan) {
-               if (ath_ant_div_comb_alt_check(div_ant_conf.div_group,
-                                       alt_ratio, curr_main_set, curr_alt_set,
-                                       alt_rssi_avg, main_rssi_avg)) {
-                       if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) {
-                               /* Switch main and alt LNA */
-                               div_ant_conf.main_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA2;
-                               div_ant_conf.alt_lna_conf  =
-                                               ATH_ANT_DIV_COMB_LNA1;
-                       } else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) {
-                               div_ant_conf.main_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA1;
-                               div_ant_conf.alt_lna_conf  =
-                                               ATH_ANT_DIV_COMB_LNA2;
-                       }
-
-                       goto div_comb_done;
-               } else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) &&
-                          (curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) {
-                       /* Set alt to another LNA */
-                       if (curr_main_set == ATH_ANT_DIV_COMB_LNA2)
-                               div_ant_conf.alt_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA1;
-                       else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1)
-                               div_ant_conf.alt_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA2;
-
-                       goto div_comb_done;
-               }
-
-               if ((alt_rssi_avg < (main_rssi_avg +
-                                    div_ant_conf.lna1_lna2_delta)))
+               ret = ath_ant_try_switch(&div_ant_conf, alt_ratio,
+                                        alt_rssi_avg, main_rssi_avg,
+                                        curr_main_set, curr_alt_set);
+               if (ret)
                        goto div_comb_done;
        }
 
+       if (!antcomb->scan &&
+           (alt_rssi_avg < (main_rssi_avg + div_ant_conf.lna1_lna2_delta)))
+               goto div_comb_done;
+
        if (!antcomb->scan_not_start) {
-               switch (curr_alt_set) {
-               case ATH_ANT_DIV_COMB_LNA2:
-                       antcomb->rssi_lna2 = alt_rssi_avg;
-                       antcomb->rssi_lna1 = main_rssi_avg;
-                       antcomb->scan = true;
-                       /* set to A+B */
-                       div_ant_conf.main_lna_conf =
-                               ATH_ANT_DIV_COMB_LNA1;
-                       div_ant_conf.alt_lna_conf  =
-                               ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
-                       break;
-               case ATH_ANT_DIV_COMB_LNA1:
-                       antcomb->rssi_lna1 = alt_rssi_avg;
-                       antcomb->rssi_lna2 = main_rssi_avg;
-                       antcomb->scan = true;
-                       /* set to A+B */
-                       div_ant_conf.main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
-                       div_ant_conf.alt_lna_conf  =
-                               ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
-                       break;
-               case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
-                       antcomb->rssi_add = alt_rssi_avg;
-                       antcomb->scan = true;
-                       /* set to A-B */
-                       div_ant_conf.alt_lna_conf =
-                               ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
-                       break;
-               case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2:
-                       antcomb->rssi_sub = alt_rssi_avg;
-                       antcomb->scan = false;
-                       if (antcomb->rssi_lna2 >
-                           (antcomb->rssi_lna1 +
-                           ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) {
-                               /* use LNA2 as main LNA */
-                               if ((antcomb->rssi_add > antcomb->rssi_lna1) &&
-                                   (antcomb->rssi_add > antcomb->rssi_sub)) {
-                                       /* set to A+B */
-                                       div_ant_conf.main_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA2;
-                                       div_ant_conf.alt_lna_conf  =
-                                               ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
-                               } else if (antcomb->rssi_sub >
-                                          antcomb->rssi_lna1) {
-                                       /* set to A-B */
-                                       div_ant_conf.main_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA2;
-                                       div_ant_conf.alt_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
-                               } else {
-                                       /* set to LNA1 */
-                                       div_ant_conf.main_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA2;
-                                       div_ant_conf.alt_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA1;
-                               }
-                       } else {
-                               /* use LNA1 as main LNA */
-                               if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
-                                   (antcomb->rssi_add > antcomb->rssi_sub)) {
-                                       /* set to A+B */
-                                       div_ant_conf.main_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA1;
-                                       div_ant_conf.alt_lna_conf  =
-                                               ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
-                               } else if (antcomb->rssi_sub >
-                                          antcomb->rssi_lna1) {
-                                       /* set to A-B */
-                                       div_ant_conf.main_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA1;
-                                       div_ant_conf.alt_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
-                               } else {
-                                       /* set to LNA2 */
-                                       div_ant_conf.main_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA1;
-                                       div_ant_conf.alt_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA2;
-                               }
-                       }
-                       break;
-               default:
-                       break;
-               }
+               ath_ant_try_scan(antcomb, &div_ant_conf, curr_alt_set,
+                                alt_rssi_avg, main_rssi_avg);
        } else {
                if (!antcomb->alt_good) {
                        antcomb->scan_not_start = false;
                        /* Set alt to another LNA */
                        if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) {
                                div_ant_conf.main_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA2;
+                                       ATH_ANT_DIV_COMB_LNA2;
                                div_ant_conf.alt_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA1;
+                                       ATH_ANT_DIV_COMB_LNA1;
                        } else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) {
                                div_ant_conf.main_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA1;
+                                       ATH_ANT_DIV_COMB_LNA1;
                                div_ant_conf.alt_lna_conf =
-                                               ATH_ANT_DIV_COMB_LNA2;
+                                       ATH_ANT_DIV_COMB_LNA2;
                        }
                        goto div_comb_done;
                }
+               ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf,
+                                                  main_rssi_avg, alt_rssi_avg,
+                                                  alt_ratio);
+               antcomb->quick_scan_cnt++;
        }
 
-       ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf,
-                                          main_rssi_avg, alt_rssi_avg,
-                                          alt_ratio);
-
-       antcomb->quick_scan_cnt++;
-
 div_comb_done:
        ath_ant_div_conf_fast_divbias(&div_ant_conf, antcomb, alt_ratio);
        ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf);
+       ath9k_debug_stat_ant(sc, &div_ant_conf, main_rssi_avg, alt_rssi_avg);
 
        antcomb->scan_start_time = jiffies;
        antcomb->total_pkt_count = 0;
index d1acfe98918a2a50689c2760ed6455cf2c239b2a..1576d58291d457612ddeadf0933904bf6f552d3a 100644 (file)
@@ -610,7 +610,15 @@ static void ar5008_hw_override_ini(struct ath_hw *ah,
        REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
 
        if (AR_SREV_9280_20_OR_LATER(ah)) {
-               val = REG_READ(ah, AR_PCU_MISC_MODE2);
+               /*
+                * For AR9280 and above, there is a new feature that allows
+                * Multicast search based on both MAC Address and Key ID.
+                * By default, this feature is enabled. But since the driver
+                * is not using this feature, we switch it off; otherwise
+                * multicast search based on MAC addr only will fail.
+                */
+               val = REG_READ(ah, AR_PCU_MISC_MODE2) &
+                       (~AR_ADHOC_MCAST_KEYID_ENABLE);
 
                if (!AR_SREV_9271(ah))
                        val &= ~AR_PCU_MISC_MODE2_HWWAR1;
index f9eb2c3571692f9517cf70cd7492ebcb1b526436..d3f09287d1d0e0e61c4899bdca72d44aa26862c1 100644 (file)
 #define AR_PHY_9285_ANT_DIV_ALT_GAINTB_S    29
 #define AR_PHY_9285_ANT_DIV_MAIN_GAINTB     0x40000000
 #define AR_PHY_9285_ANT_DIV_MAIN_GAINTB_S   30
-#define AR_PHY_9285_ANT_DIV_LNA1            2
-#define AR_PHY_9285_ANT_DIV_LNA2            1
-#define AR_PHY_9285_ANT_DIV_LNA1_PLUS_LNA2  3
-#define AR_PHY_9285_ANT_DIV_LNA1_MINUS_LNA2 0
 #define AR_PHY_9285_ANT_DIV_GAINTB_0        0
 #define AR_PHY_9285_ANT_DIV_GAINTB_1        1
 
index d105e43d22e165bc632d9fd41f9edabd04afaa8b..a98e6a3dd8a1ad911c0ae674119e7efabcd6282f 100644 (file)
@@ -3673,9 +3673,9 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
                                     AR_PHY_ANT_DIV_ALT_GAINTB |
                                     AR_PHY_ANT_DIV_MAIN_GAINTB));
                        /* by default use LNA1 for the main antenna */
-                       regval |= (AR_PHY_ANT_DIV_LNA1 <<
+                       regval |= (ATH_ANT_DIV_COMB_LNA1 <<
                                   AR_PHY_ANT_DIV_MAIN_LNACONF_S);
-                       regval |= (AR_PHY_ANT_DIV_LNA2 <<
+                       regval |= (ATH_ANT_DIV_COMB_LNA2 <<
                                   AR_PHY_ANT_DIV_ALT_LNACONF_S);
                        REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
                }
index 1f694ab3cc78ba2ede3f7ca4b192c2e7dded96ab..3ec33ce7be6600b2023ae60ae1acb7f037238010 100644 (file)
@@ -632,6 +632,22 @@ static void ar9003_hw_override_ini(struct ath_hw *ah)
 
        REG_SET_BIT(ah, AR_PHY_CCK_DETECT,
                    AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV);
+
+       if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
+               REG_WRITE(ah, AR_GLB_SWREG_DISCONT_MODE,
+                         AR_GLB_SWREG_DISCONT_EN_BT_WLAN);
+
+               if (REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_0,
+                                  AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL))
+                       ah->enabled_cals |= TX_IQ_CAL;
+               else
+                       ah->enabled_cals &= ~TX_IQ_CAL;
+
+               if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE)
+                       ah->enabled_cals |= TX_CL_CAL;
+               else
+                       ah->enabled_cals &= ~TX_CL_CAL;
+       }
 }
 
 static void ar9003_hw_prog_ini(struct ath_hw *ah,
@@ -814,29 +830,12 @@ static int ar9003_hw_process_ini(struct ath_hw *ah,
        if (chan->channel == 2484)
                ar9003_hw_prog_ini(ah, &ah->iniCckfirJapan2484, 1);
 
-       if (AR_SREV_9462(ah) || AR_SREV_9565(ah))
-               REG_WRITE(ah, AR_GLB_SWREG_DISCONT_MODE,
-                         AR_GLB_SWREG_DISCONT_EN_BT_WLAN);
-
        ah->modes_index = modesIndex;
        ar9003_hw_override_ini(ah);
        ar9003_hw_set_channel_regs(ah, chan);
        ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
        ath9k_hw_apply_txpower(ah, chan, false);
 
-       if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
-               if (REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_0,
-                                  AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL))
-                       ah->enabled_cals |= TX_IQ_CAL;
-               else
-                       ah->enabled_cals &= ~TX_IQ_CAL;
-
-               if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE)
-                       ah->enabled_cals |= TX_CL_CAL;
-               else
-                       ah->enabled_cals &= ~TX_CL_CAL;
-       }
-
        return 0;
 }
 
@@ -1466,8 +1465,8 @@ static void ar9003_hw_antctrl_shared_chain_lnadiv(struct ath_hw *ah,
                        AR_PHY_ANT_DIV_ALT_LNACONF |
                        AR_PHY_ANT_DIV_MAIN_GAINTB |
                        AR_PHY_ANT_DIV_ALT_GAINTB);
-               regval |= (AR_PHY_ANT_DIV_LNA1 << AR_PHY_ANT_DIV_MAIN_LNACONF_S);
-               regval |= (AR_PHY_ANT_DIV_LNA2 << AR_PHY_ANT_DIV_ALT_LNACONF_S);
+               regval |= (ATH_ANT_DIV_COMB_LNA1 << AR_PHY_ANT_DIV_MAIN_LNACONF_S);
+               regval |= (ATH_ANT_DIV_COMB_LNA2 << AR_PHY_ANT_DIV_ALT_LNACONF_S);
                REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
        }
 }
@@ -1518,6 +1517,18 @@ static int ar9003_hw_fast_chan_change(struct ath_hw *ah,
 
        REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites);
 
+       if (AR_SREV_9462_20_OR_LATER(ah)) {
+               /*
+                * CUS217 mix LNA mode.
+                */
+               if (ar9003_hw_get_rx_gain_idx(ah) == 2) {
+                       REG_WRITE_ARRAY(&ah->ini_modes_rxgain_bb_core,
+                                       1, regWrites);
+                       REG_WRITE_ARRAY(&ah->ini_modes_rxgain_bb_postamble,
+                                       modesIndex, regWrites);
+               }
+       }
+
        /*
         * For 5GHz channels requiring Fast Clock, apply
         * different modal values.
@@ -1528,7 +1539,11 @@ static int ar9003_hw_fast_chan_change(struct ath_hw *ah,
        if (AR_SREV_9565(ah))
                REG_WRITE_ARRAY(&ah->iniModesFastClock, 1, regWrites);
 
-       REG_WRITE_ARRAY(&ah->iniAdditional, 1, regWrites);
+       /*
+        * JAPAN regulatory.
+        */
+       if (chan->channel == 2484)
+               ar9003_hw_prog_ini(ah, &ah->iniCckfirJapan2484, 1);
 
        ah->modes_index = modesIndex;
        *ini_reloaded = true;
index d4d39f305a0b0177fbb7289a360f6d75849a58ea..23c019d0d9aa9f31e47e2ee50e23858130b1add8 100644 (file)
 #define AR_PHY_ANT_DIV_MAIN_GAINTB              0x40000000
 #define AR_PHY_ANT_DIV_MAIN_GAINTB_S            30
 
-#define AR_PHY_ANT_DIV_LNA1_MINUS_LNA2          0x0
-#define AR_PHY_ANT_DIV_LNA2                     0x1
-#define AR_PHY_ANT_DIV_LNA1                     0x2
-#define AR_PHY_ANT_DIV_LNA1_PLUS_LNA2           0x3
-
 #define AR_PHY_EXTCHN_PWRTHR1   (AR_AGC_BASE + 0x2c)
 #define AR_PHY_EXT_CHN_WIN      (AR_AGC_BASE + 0x30)
 #define AR_PHY_20_40_DET_THR    (AR_AGC_BASE + 0x34)
index c1224b5a257b86e6d9ab3ee8b7a38fa7d72fe7b3..ed8f8efb6ecf37243624e40176bf13e317e318b7 100644 (file)
@@ -591,13 +591,6 @@ static inline void ath_fill_led_pin(struct ath_softc *sc)
 #define ATH_ANT_DIV_COMB_LNA1_DELTA_MID -2
 #define ATH_ANT_DIV_COMB_LNA1_DELTA_LOW 2
 
-enum ath9k_ant_div_comb_lna_conf {
-       ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2,
-       ATH_ANT_DIV_COMB_LNA2,
-       ATH_ANT_DIV_COMB_LNA1,
-       ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2,
-};
-
 struct ath_ant_comb {
        u16 count;
        u16 total_pkt_count;
@@ -616,7 +609,7 @@ struct ath_ant_comb {
        int rssi_third;
        bool alt_good;
        int quick_scan_cnt;
-       int main_conf;
+       enum ath9k_ant_div_comb_lna_conf main_conf;
        enum ath9k_ant_div_comb_lna_conf first_quick_scan_conf;
        enum ath9k_ant_div_comb_lna_conf second_quick_scan_conf;
        bool first_ratio;
index 87454f6c7b4f0b1af790d8cab084e108f44f1d8c..e744d97476970dbb5b39309119747a851bfcd154 100644 (file)
@@ -321,6 +321,125 @@ static const struct file_operations fops_ant_diversity = {
        .llseek = default_llseek,
 };
 
+void ath9k_debug_stat_ant(struct ath_softc *sc,
+                         struct ath_hw_antcomb_conf *div_ant_conf,
+                         int main_rssi_avg, int alt_rssi_avg)
+{
+       struct ath_antenna_stats *as_main = &sc->debug.stats.ant_stats[ANT_MAIN];
+       struct ath_antenna_stats *as_alt = &sc->debug.stats.ant_stats[ANT_ALT];
+
+       as_main->lna_attempt_cnt[div_ant_conf->main_lna_conf]++;
+       as_alt->lna_attempt_cnt[div_ant_conf->alt_lna_conf]++;
+
+       as_main->rssi_avg = main_rssi_avg;
+       as_alt->rssi_avg = alt_rssi_avg;
+}
+
+static ssize_t read_file_antenna_diversity(struct file *file,
+                                          char __user *user_buf,
+                                          size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath9k_hw_capabilities *pCap = &ah->caps;
+       struct ath_antenna_stats *as_main = &sc->debug.stats.ant_stats[ANT_MAIN];
+       struct ath_antenna_stats *as_alt = &sc->debug.stats.ant_stats[ANT_ALT];
+       struct ath_hw_antcomb_conf div_ant_conf;
+       unsigned int len = 0, size = 1024;
+       ssize_t retval = 0;
+       char *buf;
+       char *lna_conf_str[4] = {"LNA1_MINUS_LNA2",
+                                "LNA2",
+                                "LNA1",
+                                "LNA1_PLUS_LNA2"};
+
+       buf = kzalloc(size, GFP_KERNEL);
+       if (buf == NULL)
+               return -ENOMEM;
+
+       if (!(pCap->hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB)) {
+               len += snprintf(buf + len, size - len, "%s\n",
+                               "Antenna Diversity Combining is disabled");
+               goto exit;
+       }
+
+       ath9k_ps_wakeup(sc);
+       ath9k_hw_antdiv_comb_conf_get(ah, &div_ant_conf);
+       len += snprintf(buf + len, size - len, "Current MAIN config : %s\n",
+                       lna_conf_str[div_ant_conf.main_lna_conf]);
+       len += snprintf(buf + len, size - len, "Current ALT config  : %s\n",
+                       lna_conf_str[div_ant_conf.alt_lna_conf]);
+       len += snprintf(buf + len, size - len, "Average MAIN RSSI   : %d\n",
+                       as_main->rssi_avg);
+       len += snprintf(buf + len, size - len, "Average ALT RSSI    : %d\n\n",
+                       as_alt->rssi_avg);
+       ath9k_ps_restore(sc);
+
+       len += snprintf(buf + len, size - len, "Packet Receive Cnt:\n");
+       len += snprintf(buf + len, size - len, "-------------------\n");
+
+       len += snprintf(buf + len, size - len, "%30s%15s\n",
+                       "MAIN", "ALT");
+       len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
+                       "TOTAL COUNT",
+                       as_main->recv_cnt,
+                       as_alt->recv_cnt);
+       len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
+                       "LNA1",
+                       as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1],
+                       as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1]);
+       len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
+                       "LNA2",
+                       as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA2],
+                       as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA2]);
+       len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
+                       "LNA1 + LNA2",
+                       as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2],
+                       as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2]);
+       len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
+                       "LNA1 - LNA2",
+                       as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2],
+                       as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2]);
+
+       len += snprintf(buf + len, size - len, "\nLNA Config Attempts:\n");
+       len += snprintf(buf + len, size - len, "--------------------\n");
+
+       len += snprintf(buf + len, size - len, "%30s%15s\n",
+                       "MAIN", "ALT");
+       len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
+                       "LNA1",
+                       as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1],
+                       as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1]);
+       len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
+                       "LNA2",
+                       as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA2],
+                       as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA2]);
+       len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
+                       "LNA1 + LNA2",
+                       as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2],
+                       as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2]);
+       len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
+                       "LNA1 - LNA2",
+                       as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2],
+                       as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2]);
+
+exit:
+       if (len > size)
+               len = size;
+
+       retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+       kfree(buf);
+
+       return retval;
+}
+
+static const struct file_operations fops_antenna_diversity = {
+       .read = read_file_antenna_diversity,
+       .open = simple_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
 static ssize_t read_file_dma(struct file *file, char __user *user_buf,
                             size_t count, loff_t *ppos)
 {
@@ -1816,6 +1935,8 @@ int ath9k_init_debug(struct ath_hw *ah)
                           sc->debug.debugfs_phy, &sc->sc_ah->gpio_val);
        debugfs_create_file("diversity", S_IRUSR | S_IWUSR,
                            sc->debug.debugfs_phy, sc, &fops_ant_diversity);
+       debugfs_create_file("antenna_diversity", S_IRUSR,
+                           sc->debug.debugfs_phy, sc, &fops_antenna_diversity);
 #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
        debugfs_create_file("btcoex", S_IRUSR, sc->debug.debugfs_phy, sc,
                            &fops_btcoex);
index fc679198a0f38049a385fb53ab25209b23945827..01c5c6a22e1bbbb146c424766939ae26cd98f983 100644 (file)
@@ -28,9 +28,13 @@ struct fft_sample_tlv;
 #ifdef CONFIG_ATH9K_DEBUGFS
 #define TX_STAT_INC(q, c) sc->debug.stats.txstats[q].c++
 #define RESET_STAT_INC(sc, type) sc->debug.stats.reset[type]++
+#define ANT_STAT_INC(i, c) sc->debug.stats.ant_stats[i].c++
+#define ANT_LNA_INC(i, c) sc->debug.stats.ant_stats[i].lna_recv_cnt[c]++;
 #else
 #define TX_STAT_INC(q, c) do { } while (0)
 #define RESET_STAT_INC(sc, type) do { } while (0)
+#define ANT_STAT_INC(i, c) do { } while (0)
+#define ANT_LNA_INC(i, c) do { } while (0)
 #endif
 
 enum ath_reset_type {
@@ -243,11 +247,22 @@ struct ath_rx_stats {
        u32 rx_spectral;
 };
 
+#define ANT_MAIN 0
+#define ANT_ALT  1
+
+struct ath_antenna_stats {
+       u32 recv_cnt;
+       u32 rssi_avg;
+       u32 lna_recv_cnt[4];
+       u32 lna_attempt_cnt[4];
+};
+
 struct ath_stats {
        struct ath_interrupt_stats istats;
        struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES];
        struct ath_rx_stats rxstats;
        struct ath_dfs_stats dfs_stats;
+       struct ath_antenna_stats ant_stats[2];
        u32 reset[__RESET_TYPE_MAX];
 };
 
@@ -281,10 +296,11 @@ void ath9k_sta_remove_debugfs(struct ieee80211_hw *hw,
                              struct ieee80211_vif *vif,
                              struct ieee80211_sta *sta,
                              struct dentry *dir);
-
 void ath_debug_send_fft_sample(struct ath_softc *sc,
                               struct fft_sample_tlv *fft_sample);
-
+void ath9k_debug_stat_ant(struct ath_softc *sc,
+                         struct ath_hw_antcomb_conf *div_ant_conf,
+                         int main_rssi_avg, int alt_rssi_avg);
 #else
 
 #define RX_STAT_INC(c) /* NOP */
@@ -297,12 +313,10 @@ static inline int ath9k_init_debug(struct ath_hw *ah)
 static inline void ath9k_deinit_debug(struct ath_softc *sc)
 {
 }
-
 static inline void ath_debug_stat_interrupt(struct ath_softc *sc,
                                            enum ath9k_int status)
 {
 }
-
 static inline void ath_debug_stat_tx(struct ath_softc *sc,
                                     struct ath_buf *bf,
                                     struct ath_tx_status *ts,
@@ -310,10 +324,15 @@ static inline void ath_debug_stat_tx(struct ath_softc *sc,
                                     unsigned int flags)
 {
 }
-
 static inline void ath_debug_stat_rx(struct ath_softc *sc,
                                     struct ath_rx_status *rs)
 {
+}
+static inline void ath9k_debug_stat_ant(struct ath_softc *sc,
+                                       struct ath_hw_antcomb_conf *div_ant_conf,
+                                       int main_rssi_avg, int alt_rssi_avg)
+{
+
 }
 
 #endif /* CONFIG_ATH9K_DEBUGFS */
index c2bfd748eed81a99a150743985e4d6b1eef45621..9ea8e4b779c97c99b329619616e1ed232a1f5044 100644 (file)
@@ -812,6 +812,7 @@ static void ath9k_hw_4k_set_gain(struct ath_hw *ah,
 static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,
                                         struct ath9k_channel *chan)
 {
+       struct ath9k_hw_capabilities *pCap = &ah->caps;
        struct modal_eep_4k_header *pModal;
        struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
        struct base_eep_header_4k *pBase = &eep->baseEepHeader;
@@ -858,6 +859,24 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,
 
                REG_WRITE(ah, AR_PHY_CCK_DETECT, regVal);
                regVal = REG_READ(ah, AR_PHY_CCK_DETECT);
+
+               if (pCap->hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) {
+                       /*
+                        * If diversity combining is enabled,
+                        * set MAIN to LNA1 and ALT to LNA2 initially.
+                        */
+                       regVal = REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL);
+                       regVal &= (~(AR_PHY_9285_ANT_DIV_MAIN_LNACONF |
+                                    AR_PHY_9285_ANT_DIV_ALT_LNACONF));
+
+                       regVal |= (ATH_ANT_DIV_COMB_LNA1 <<
+                                  AR_PHY_9285_ANT_DIV_MAIN_LNACONF_S);
+                       regVal |= (ATH_ANT_DIV_COMB_LNA2 <<
+                                  AR_PHY_9285_ANT_DIV_ALT_LNACONF_S);
+                       regVal &= (~(AR_PHY_9285_FAST_DIV_BIAS));
+                       regVal |= (0 << AR_PHY_9285_FAST_DIV_BIAS_S);
+                       REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regVal);
+               }
        }
 
        if (pModal->version >= 2) {
index 9e582e14da74609361b689e5f5741d425fd14659..5205a3625e849f3f6d3d775bb7b4b8f866aebca4 100644 (file)
@@ -1082,7 +1082,7 @@ static void ath9k_hif_usb_firmware_fail(struct hif_device_usb *hif_dev)
        struct device *dev = &hif_dev->udev->dev;
        struct device *parent = dev->parent;
 
-       complete(&hif_dev->fw_done);
+       complete_all(&hif_dev->fw_done);
 
        if (parent)
                device_lock(parent);
@@ -1131,7 +1131,7 @@ static void ath9k_hif_usb_firmware_cb(const struct firmware *fw, void *context)
 
        release_firmware(fw);
        hif_dev->flags |= HIF_USB_READY;
-       complete(&hif_dev->fw_done);
+       complete_all(&hif_dev->fw_done);
 
        return;
 
@@ -1295,7 +1295,9 @@ static void ath9k_hif_usb_disconnect(struct usb_interface *interface)
 
        usb_set_intfdata(interface, NULL);
 
-       if (!unplugged && (hif_dev->flags & HIF_USB_START))
+       /* If firmware was loaded we should drop it
+        * go back to first stage bootloader. */
+       if (!unplugged && (hif_dev->flags & HIF_USB_READY))
                ath9k_hif_usb_reboot(udev);
 
        kfree(hif_dev);
@@ -1316,7 +1318,10 @@ static int ath9k_hif_usb_suspend(struct usb_interface *interface,
        if (!(hif_dev->flags & HIF_USB_START))
                ath9k_htc_suspend(hif_dev->htc_handle);
 
-       ath9k_hif_usb_dealloc_urbs(hif_dev);
+       wait_for_completion(&hif_dev->fw_done);
+
+       if (hif_dev->flags & HIF_USB_READY)
+               ath9k_hif_usb_dealloc_urbs(hif_dev);
 
        return 0;
 }
index 71a183ffc77faf04f590b3d9454d1fb3c798ccaf..c3676bf1d6c45ab92d8a161d18ad5f3f0c586d18 100644 (file)
@@ -861,6 +861,7 @@ static int ath9k_init_device(struct ath9k_htc_priv *priv,
        if (error != 0)
                goto err_rx;
 
+       ath9k_hw_disable(priv->ah);
 #ifdef CONFIG_MAC80211_LEDS
        /* must be initialized before ieee80211_register_hw */
        priv->led_cdev.default_trigger = ieee80211_create_tpt_led_trigger(priv->hw,
index 4ca0cb06010609ca490bfe4404883bde2ac85d66..d55d97c8596460e57ad0d78917a854fcef0a21fa 100644 (file)
@@ -1496,16 +1496,18 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
                                    struct ath9k_channel *chan)
 {
        struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_hw_capabilities *pCap = &ah->caps;
+       bool band_switch = false, mode_diff = false;
+       u8 ini_reloaded = 0;
        u32 qnum;
        int r;
-       bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
-       bool band_switch, mode_diff;
-       u8 ini_reloaded;
 
-       band_switch = (chan->channelFlags & (CHANNEL_2GHZ | CHANNEL_5GHZ)) !=
-                     (ah->curchan->channelFlags & (CHANNEL_2GHZ |
-                                                   CHANNEL_5GHZ));
-       mode_diff = (chan->chanmode != ah->curchan->chanmode);
+       if (pCap->hw_caps & ATH9K_HW_CAP_FCC_BAND_SWITCH) {
+               u32 cur = ah->curchan->channelFlags & (CHANNEL_2GHZ | CHANNEL_5GHZ);
+               u32 new = chan->channelFlags & (CHANNEL_2GHZ | CHANNEL_5GHZ);
+               band_switch = (cur != new);
+               mode_diff = (chan->chanmode != ah->curchan->chanmode);
+       }
 
        for (qnum = 0; qnum < AR_NUM_QCU; qnum++) {
                if (ath9k_hw_numtxpending(ah, qnum)) {
@@ -1520,11 +1522,12 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
                return false;
        }
 
-       if (edma && (band_switch || mode_diff)) {
+       if (band_switch || mode_diff) {
                ath9k_hw_mark_phy_inactive(ah);
                udelay(5);
 
-               ath9k_hw_init_pll(ah, NULL);
+               if (band_switch)
+                       ath9k_hw_init_pll(ah, chan);
 
                if (ath9k_hw_fast_chan_change(ah, chan, &ini_reloaded)) {
                        ath_err(common, "Failed to do fast channel change\n");
@@ -1541,22 +1544,21 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
        }
        ath9k_hw_set_clockrate(ah);
        ath9k_hw_apply_txpower(ah, chan, false);
-       ath9k_hw_rfbus_done(ah);
 
        if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan))
                ath9k_hw_set_delta_slope(ah, chan);
 
        ath9k_hw_spur_mitigate_freq(ah, chan);
 
-       if (edma && (band_switch || mode_diff)) {
-               ah->ah_flags |= AH_FASTCC;
-               if (band_switch || ini_reloaded)
-                       ah->eep_ops->set_board_values(ah, chan);
+       if (band_switch || ini_reloaded)
+               ah->eep_ops->set_board_values(ah, chan);
 
-               ath9k_hw_init_bb(ah, chan);
+       ath9k_hw_init_bb(ah, chan);
+       ath9k_hw_rfbus_done(ah);
 
-               if (band_switch || ini_reloaded)
-                       ath9k_hw_init_cal(ah, chan);
+       if (band_switch || ini_reloaded) {
+               ah->ah_flags |= AH_FASTCC;
+               ath9k_hw_init_cal(ah, chan);
                ah->ah_flags &= ~AH_FASTCC;
        }
 
@@ -1778,16 +1780,11 @@ static void ath9k_hw_init_desc(struct ath_hw *ah)
 /*
  * Fast channel change:
  * (Change synthesizer based on channel freq without resetting chip)
- *
- * Don't do FCC when
- *   - Flag is not set
- *   - Chip is just coming out of full sleep
- *   - Channel to be set is same as current channel
- *   - Channel flags are different, (eg.,moving from 2GHz to 5GHz channel)
  */
 static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan)
 {
        struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_hw_capabilities *pCap = &ah->caps;
        int ret;
 
        if (AR_SREV_9280(ah) && common->bus_ops->ath_bus_type == ATH_PCI)
@@ -1806,9 +1803,21 @@ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan)
            (CHANNEL_HALF | CHANNEL_QUARTER))
                goto fail;
 
-       if ((chan->channelFlags & CHANNEL_ALL) !=
-           (ah->curchan->channelFlags & CHANNEL_ALL))
-               goto fail;
+       /*
+        * If cross-band fcc is not supoprted, bail out if
+        * either channelFlags or chanmode differ.
+        *
+        * chanmode will be different if the HT operating mode
+        * changes because of CSA.
+        */
+       if (!(pCap->hw_caps & ATH9K_HW_CAP_FCC_BAND_SWITCH)) {
+               if ((chan->channelFlags & CHANNEL_ALL) !=
+                   (ah->curchan->channelFlags & CHANNEL_ALL))
+                       goto fail;
+
+               if (chan->chanmode != ah->curchan->chanmode)
+                       goto fail;
+       }
 
        if (!ath9k_hw_check_alive(ah))
                goto fail;
@@ -2504,7 +2513,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
        else
                pCap->rts_aggr_limit = (8 * 1024);
 
-#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
+#ifdef CONFIG_ATH9K_RFKILL
        ah->rfsilent = ah->eep_ops->get_eeprom(ah, EEP_RF_SILENT);
        if (ah->rfsilent & EEP_RFSILENT_ENABLED) {
                ah->rfkill_gpio =
@@ -2610,6 +2619,13 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
            ah->eep_ops->get_eeprom(ah, EEP_PAPRD))
                        pCap->hw_caps |= ATH9K_HW_CAP_PAPRD;
 
+       /*
+        * Fast channel change across bands is available
+        * only for AR9462 and AR9565.
+        */
+       if (AR_SREV_9462(ah) || AR_SREV_9565(ah))
+               pCap->hw_caps |= ATH9K_HW_CAP_FCC_BAND_SWITCH;
+
        return 0;
 }
 
index cd74b3afef7db179fc4fcedc23eaa509722da52c..fd009e593b69570aaf4d8b3d9d680124444dd855 100644 (file)
@@ -247,6 +247,7 @@ enum ath9k_hw_caps {
        ATH9K_HW_CAP_DFS                        = BIT(16),
        ATH9K_HW_WOW_DEVICE_CAPABLE             = BIT(17),
        ATH9K_HW_CAP_PAPRD                      = BIT(18),
+       ATH9K_HW_CAP_FCC_BAND_SWITCH            = BIT(19),
 };
 
 /*
index 1737a3e336859013e2b9aeb6d49d61da1b35a688..1adb803a9d86e4cf587aa31f5fafc800d4f0057f 100644 (file)
@@ -2094,7 +2094,7 @@ static void ath9k_wow_add_pattern(struct ath_softc *sc,
 {
        struct ath_hw *ah = sc->sc_ah;
        struct ath9k_wow_pattern *wow_pattern = NULL;
-       struct cfg80211_wowlan_trig_pkt_pattern *patterns = wowlan->patterns;
+       struct cfg80211_pkt_pattern *patterns = wowlan->patterns;
        int mask_len;
        s8 i = 0;
 
index 8b380305b0fc1acf8c2593acd474daa52f7eb6c9..4a1b99238ec225af3aef646f14021d94df3792c7 100644 (file)
 #define AR_PHY_PLL_CONTROL 0x16180
 #define AR_PHY_PLL_MODE 0x16184
 
+enum ath9k_ant_div_comb_lna_conf {
+       ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2,
+       ATH_ANT_DIV_COMB_LNA2,
+       ATH_ANT_DIV_COMB_LNA1,
+       ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2,
+};
+
 #endif
index 7eb1f4b458e4fb1f3c096fd297bb60b273d9c686..a3c4ca0c94bfa43877f84b2e5baeb61353ece266 100644 (file)
@@ -1275,6 +1275,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
 }
 
 static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
+                         struct cfg80211_chan_def *chandef,
                           struct ieee80211_sta *sta, void *priv_sta)
 {
        struct ath_softc *sc = priv;
@@ -1313,6 +1314,7 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
 }
 
 static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband,
+                           struct cfg80211_chan_def *chandef,
                            struct ieee80211_sta *sta, void *priv_sta,
                            u32 changed)
 {
index c59ae43b9b35aeba9356f499a83f73ae02e96a8b..52cd5219aba90f98b5b800f8370b14bbb6f2d49a 100644 (file)
@@ -146,6 +146,28 @@ static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta,
                               ARRAY_SIZE(bf->rates));
 }
 
+static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
+                            struct sk_buff *skb)
+{
+       int q;
+
+       q = skb_get_queue_mapping(skb);
+       if (txq == sc->tx.uapsdq)
+               txq = sc->tx.txq_map[q];
+
+       if (txq != sc->tx.txq_map[q])
+               return;
+
+       if (WARN_ON(--txq->pending_frames < 0))
+               txq->pending_frames = 0;
+
+       if (txq->stopped &&
+           txq->pending_frames < sc->tx.txq_max_pending[q]) {
+               ieee80211_wake_queue(sc->hw, q);
+               txq->stopped = false;
+       }
+}
+
 static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
 {
        struct ath_txq *txq = tid->ac->txq;
@@ -167,6 +189,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
                if (!bf) {
                        bf = ath_tx_setup_buffer(sc, txq, tid, skb);
                        if (!bf) {
+                               ath_txq_skb_done(sc, txq, skb);
                                ieee80211_free_txskb(sc->hw, skb);
                                continue;
                        }
@@ -811,6 +834,7 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
 
                if (!bf) {
                        __skb_unlink(skb, &tid->buf_q);
+                       ath_txq_skb_done(sc, txq, skb);
                        ieee80211_free_txskb(sc->hw, skb);
                        continue;
                }
@@ -999,7 +1023,7 @@ void ath_update_max_aggr_framelen(struct ath_softc *sc, int queue, int txop)
 }
 
 static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
-                            struct ath_tx_info *info, int len)
+                            struct ath_tx_info *info, int len, bool rts)
 {
        struct ath_hw *ah = sc->sc_ah;
        struct sk_buff *skb;
@@ -1008,6 +1032,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
        const struct ieee80211_rate *rate;
        struct ieee80211_hdr *hdr;
        struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu);
+       u32 rts_thresh = sc->hw->wiphy->rts_threshold;
        int i;
        u8 rix = 0;
 
@@ -1030,7 +1055,17 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
                rix = rates[i].idx;
                info->rates[i].Tries = rates[i].count;
 
-                   if (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
+               /*
+                * Handle RTS threshold for unaggregated HT frames.
+                */
+               if (bf_isampdu(bf) && !bf_isaggr(bf) &&
+                   (rates[i].flags & IEEE80211_TX_RC_MCS) &&
+                   unlikely(rts_thresh != (u32) -1)) {
+                       if (!rts_thresh || (len > rts_thresh))
+                               rts = true;
+               }
+
+               if (rts || rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
                        info->rates[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
                        info->flags |= ATH9K_TXDESC_RTSENA;
                } else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
@@ -1123,6 +1158,8 @@ static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf,
        struct ath_hw *ah = sc->sc_ah;
        struct ath_buf *bf_first = NULL;
        struct ath_tx_info info;
+       u32 rts_thresh = sc->hw->wiphy->rts_threshold;
+       bool rts = false;
 
        memset(&info, 0, sizeof(info));
        info.is_first = true;
@@ -1159,7 +1196,22 @@ static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf,
                                info.flags |= (u32) bf->bf_state.bfs_paprd <<
                                              ATH9K_TXDESC_PAPRD_S;
 
-                       ath_buf_set_rate(sc, bf, &info, len);
+                       /*
+                        * mac80211 doesn't handle RTS threshold for HT because
+                        * the decision has to be taken based on AMPDU length
+                        * and aggregation is done entirely inside ath9k.
+                        * Set the RTS/CTS flag for the first subframe based
+                        * on the threshold.
+                        */
+                       if (aggr && (bf == bf_first) &&
+                           unlikely(rts_thresh != (u32) -1)) {
+                               /*
+                                * "len" is the size of the entire AMPDU.
+                                */
+                               if (!rts_thresh || (len > rts_thresh))
+                                       rts = true;
+                       }
+                       ath_buf_set_rate(sc, bf, &info, len, rts);
                }
 
                info.buf_addr[0] = bf->bf_buf_addr;
@@ -1824,6 +1876,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_txq *txq,
 
        bf = ath_tx_setup_buffer(sc, txq, tid, skb);
        if (!bf) {
+               ath_txq_skb_done(sc, txq, skb);
                ieee80211_free_txskb(sc->hw, skb);
                return;
        }
@@ -2090,6 +2143,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
 
        bf = ath_tx_setup_buffer(sc, txq, tid, skb);
        if (!bf) {
+               ath_txq_skb_done(sc, txq, skb);
                if (txctl->paprd)
                        dev_kfree_skb_any(skb);
                else
@@ -2142,7 +2196,7 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 
                bf->bf_lastbf = bf;
                ath_set_rates(vif, NULL, bf);
-               ath_buf_set_rate(sc, bf, &info, fi->framelen);
+               ath_buf_set_rate(sc, bf, &info, fi->framelen, false);
                duration += info.rates[0].PktDuration;
                if (bf_tail)
                        bf_tail->bf_next = bf;
@@ -2189,7 +2243,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
-       int q, padpos, padsize;
+       int padpos, padsize;
        unsigned long flags;
 
        ath_dbg(common, XMIT, "TX complete: skb: %p\n", skb);
@@ -2225,21 +2279,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
        spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
 
        __skb_queue_tail(&txq->complete_q, skb);
-
-       q = skb_get_queue_mapping(skb);
-       if (txq == sc->tx.uapsdq)
-               txq = sc->tx.txq_map[q];
-
-       if (txq == sc->tx.txq_map[q]) {
-               if (WARN_ON(--txq->pending_frames < 0))
-                       txq->pending_frames = 0;
-
-               if (txq->stopped &&
-                   txq->pending_frames < sc->tx.txq_max_pending[q]) {
-                       ieee80211_wake_queue(sc->hw, q);
-                       txq->stopped = false;
-               }
-       }
+       ath_txq_skb_done(sc, txq, skb);
 }
 
 static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
index f891d514d88175ba055588f85a9adf7507195c4e..990dd42ae79ed312652a336f46fc1ab4c9ad7ad8 100644 (file)
@@ -11,9 +11,6 @@ wil6210-y += txrx.o
 wil6210-y += debug.o
 wil6210-$(CONFIG_WIL6210_TRACING) += trace.o
 
-ifeq (, $(findstring -W,$(EXTRA_CFLAGS)))
-       subdir-ccflags-y += -Werror
-endif
 # for tracing framework to find trace.h
 CFLAGS_trace.o := -I$(src)
 
index e8308ec309704958b1754c06dbeb7b3fef9f452b..1caa31992a7e1ecc25b03d32d78aaf12894fcd78 100644 (file)
@@ -51,7 +51,7 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,
                        if ((i % 64) == 0 && (i != 0))
                                seq_printf(s, "\n");
                        seq_printf(s, "%s", (d->dma.status & BIT(0)) ?
-                                       "S" : (vring->ctx[i] ? "H" : "h"));
+                                       "S" : (vring->ctx[i].skb ? "H" : "h"));
                }
                seq_printf(s, "\n");
        }
@@ -145,7 +145,7 @@ static void wil_print_ring(struct seq_file *s, const char *prefix,
                                   le16_to_cpu(hdr.type), hdr.flags);
                        if (len <= MAX_MBOXITEM_SIZE) {
                                int n = 0;
-                               unsigned char printbuf[16 * 3 + 2];
+                               char printbuf[16 * 3 + 2];
                                unsigned char databuf[MAX_MBOXITEM_SIZE];
                                void __iomem *src = wmi_buffer(wil, d.addr) +
                                        sizeof(struct wil6210_mbox_hdr);
@@ -406,7 +406,7 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
                volatile struct vring_tx_desc *d =
                                &(vring->va[dbg_txdesc_index].tx);
                volatile u32 *u = (volatile u32 *)d;
-               struct sk_buff *skb = vring->ctx[dbg_txdesc_index];
+               struct sk_buff *skb = vring->ctx[dbg_txdesc_index].skb;
 
                seq_printf(s, "Tx[%3d] = {\n", dbg_txdesc_index);
                seq_printf(s, "  MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n",
@@ -416,7 +416,7 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
                seq_printf(s, "  SKB = %p\n", skb);
 
                if (skb) {
-                       unsigned char printbuf[16 * 3 + 2];
+                       char printbuf[16 * 3 + 2];
                        int i = 0;
                        int len = le16_to_cpu(d->dma.length);
                        void *p = skb->data;
index 29dd1e58cb170b20c36ff215ae64412a74e88266..717178f09aa8e0a2f9eb5196eb1c8654d2295cb2 100644 (file)
@@ -127,6 +127,8 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr)
 
        ndev->netdev_ops = &wil_netdev_ops;
        ndev->ieee80211_ptr = wdev;
+       ndev->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM;
+       ndev->features |= NETIF_F_HW_CSUM | NETIF_F_RXCSUM;
        SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
        wdev->netdev = ndev;
 
index eff1239be53adc93d1e9dcbe2ac290951e902e12..e59239d22b9493cee2cb1bdc2f2d6066a86e94e2 100644 (file)
@@ -37,36 +37,40 @@ static inline void trace_ ## name(proto) {}
 #endif /* !CONFIG_WIL6210_TRACING || defined(__CHECKER__) */
 
 DECLARE_EVENT_CLASS(wil6210_wmi,
-       TP_PROTO(u16 id, void *buf, u16 buf_len),
+       TP_PROTO(struct wil6210_mbox_hdr_wmi *wmi, void *buf, u16 buf_len),
 
-       TP_ARGS(id, buf, buf_len),
+       TP_ARGS(wmi, buf, buf_len),
 
        TP_STRUCT__entry(
+               __field(u8, mid)
                __field(u16, id)
+               __field(u32, timestamp)
                __field(u16, buf_len)
                __dynamic_array(u8, buf, buf_len)
        ),
 
        TP_fast_assign(
-               __entry->id = id;
+               __entry->mid = wmi->mid;
+               __entry->id = le16_to_cpu(wmi->id);
+               __entry->timestamp = le32_to_cpu(wmi->timestamp);
                __entry->buf_len = buf_len;
                memcpy(__get_dynamic_array(buf), buf, buf_len);
        ),
 
        TP_printk(
-               "id 0x%04x len %d",
-               __entry->id, __entry->buf_len
+               "MID %d id 0x%04x len %d timestamp %d",
+               __entry->mid, __entry->id, __entry->buf_len, __entry->timestamp
        )
 );
 
 DEFINE_EVENT(wil6210_wmi, wil6210_wmi_cmd,
-       TP_PROTO(u16 id, void *buf, u16 buf_len),
-       TP_ARGS(id, buf, buf_len)
+       TP_PROTO(struct wil6210_mbox_hdr_wmi *wmi, void *buf, u16 buf_len),
+       TP_ARGS(wmi, buf, buf_len)
 );
 
 DEFINE_EVENT(wil6210_wmi, wil6210_wmi_event,
-       TP_PROTO(u16 id, void *buf, u16 buf_len),
-       TP_ARGS(id, buf, buf_len)
+       TP_PROTO(struct wil6210_mbox_hdr_wmi *wmi, void *buf, u16 buf_len),
+       TP_ARGS(wmi, buf, buf_len)
 );
 
 #define WIL6210_MSG_MAX (200)
index d240b24e1ccfafdd7d809c4b45951cbe2747a31a..ea1abeb18e5be8ef0045c3f41f6da287714d9b9c 100644 (file)
@@ -18,6 +18,9 @@
 #include <net/ieee80211_radiotap.h>
 #include <linux/if_arp.h>
 #include <linux/moduleparam.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <net/ipv6.h>
 
 #include "wil6210.h"
 #include "wmi.h"
@@ -70,7 +73,7 @@ static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring)
 
        vring->swhead = 0;
        vring->swtail = 0;
-       vring->ctx = kzalloc(vring->size * sizeof(vring->ctx[0]), GFP_KERNEL);
+       vring->ctx = kcalloc(vring->size, sizeof(vring->ctx[0]), GFP_KERNEL);
        if (!vring->ctx) {
                vring->va = NULL;
                return -ENOMEM;
@@ -108,39 +111,39 @@ static void wil_vring_free(struct wil6210_priv *wil, struct vring *vring,
 
        while (!wil_vring_is_empty(vring)) {
                dma_addr_t pa;
-               struct sk_buff *skb;
                u16 dmalen;
+               struct wil_ctx *ctx;
 
                if (tx) {
                        struct vring_tx_desc dd, *d = &dd;
                        volatile struct vring_tx_desc *_d =
                                        &vring->va[vring->swtail].tx;
 
+                       ctx = &vring->ctx[vring->swtail];
                        *d = *_d;
                        pa = wil_desc_addr(&d->dma.addr);
                        dmalen = le16_to_cpu(d->dma.length);
-                       skb = vring->ctx[vring->swtail];
-                       if (skb) {
-                               dma_unmap_single(dev, pa, dmalen,
-                                                DMA_TO_DEVICE);
-                               dev_kfree_skb_any(skb);
-                               vring->ctx[vring->swtail] = NULL;
-                       } else {
+                       if (vring->ctx[vring->swtail].mapped_as_page) {
                                dma_unmap_page(dev, pa, dmalen,
                                               DMA_TO_DEVICE);
+                       } else {
+                               dma_unmap_single(dev, pa, dmalen,
+                                                DMA_TO_DEVICE);
                        }
+                       if (ctx->skb)
+                               dev_kfree_skb_any(ctx->skb);
                        vring->swtail = wil_vring_next_tail(vring);
                } else { /* rx */
                        struct vring_rx_desc dd, *d = &dd;
                        volatile struct vring_rx_desc *_d =
-                                       &vring->va[vring->swtail].rx;
+                                       &vring->va[vring->swhead].rx;
 
+                       ctx = &vring->ctx[vring->swhead];
                        *d = *_d;
                        pa = wil_desc_addr(&d->dma.addr);
                        dmalen = le16_to_cpu(d->dma.length);
-                       skb = vring->ctx[vring->swhead];
                        dma_unmap_single(dev, pa, dmalen, DMA_FROM_DEVICE);
-                       kfree_skb(skb);
+                       kfree_skb(ctx->skb);
                        wil_vring_advance_head(vring, 1);
                }
        }
@@ -187,7 +190,7 @@ static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring,
        d->dma.status = 0; /* BIT(0) should be 0 for HW_OWNED */
        d->dma.length = cpu_to_le16(sz);
        *_d = *d;
-       vring->ctx[i] = skb;
+       vring->ctx[i].skb = skb;
 
        return 0;
 }
@@ -352,11 +355,11 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
                return NULL;
        }
 
-       skb = vring->ctx[vring->swhead];
+       skb = vring->ctx[vring->swhead].skb;
        d = wil_skb_rxdesc(skb);
        *d = *_d;
        pa = wil_desc_addr(&d->dma.addr);
-       vring->ctx[vring->swhead] = NULL;
+       vring->ctx[vring->swhead].skb = NULL;
        wil_vring_advance_head(vring, 1);
 
        dma_unmap_single(dev, pa, sz, DMA_FROM_DEVICE);
@@ -407,6 +410,21 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
                return NULL;
        }
 
+       /* L4 IDENT is on when HW calculated checksum, check status
+        * and in case of error drop the packet
+        * higher stack layers will handle retransmission (if required)
+        */
+       if (d->dma.status & RX_DMA_STATUS_L4_IDENT) {
+               /* L4 protocol identified, csum calculated */
+               if ((d->dma.error & RX_DMA_ERROR_L4_ERR) == 0) {
+                       skb->ip_summed = CHECKSUM_UNNECESSARY;
+               } else {
+                       wil_err(wil, "Incorrect checksum reported\n");
+                       kfree_skb(skb);
+                       return NULL;
+               }
+       }
+
        ds_bits = wil_rxdesc_ds_bits(d);
        if (ds_bits == 1) {
                /*
@@ -646,6 +664,53 @@ static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len,
        return 0;
 }
 
+static int wil_tx_desc_offload_cksum_set(struct wil6210_priv *wil,
+                               struct vring_tx_desc *d,
+                               struct sk_buff *skb)
+{
+       int protocol;
+
+       if (skb->ip_summed != CHECKSUM_PARTIAL)
+               return 0;
+
+       switch (skb->protocol) {
+       case cpu_to_be16(ETH_P_IP):
+               protocol = ip_hdr(skb)->protocol;
+               break;
+       case cpu_to_be16(ETH_P_IPV6):
+               protocol = ipv6_hdr(skb)->nexthdr;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (protocol) {
+       case IPPROTO_TCP:
+               d->dma.d0 |= (2 << DMA_CFG_DESC_TX_0_L4_TYPE_POS);
+               /* L4 header len: TCP header length */
+               d->dma.d0 |=
+               (tcp_hdrlen(skb) & DMA_CFG_DESC_TX_0_L4_LENGTH_MSK);
+               break;
+       case IPPROTO_UDP:
+               /* L4 header len: UDP header length */
+               d->dma.d0 |=
+               (sizeof(struct udphdr) & DMA_CFG_DESC_TX_0_L4_LENGTH_MSK);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       d->dma.ip_length = skb_network_header_len(skb);
+       d->dma.b11 = ETH_HLEN; /* MAC header length */
+       d->dma.b11 |= BIT(DMA_CFG_DESC_TX_OFFLOAD_CFG_L3T_IPV4_POS);
+       /* Enable TCP/UDP checksum */
+       d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_TCP_UDP_CHECKSUM_EN_POS);
+       /* Calculate pseudo-header */
+       d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_PSEUDO_HEADER_CALC_EN_POS);
+
+       return 0;
+}
+
 static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
                        struct sk_buff *skb)
 {
@@ -655,7 +720,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
        u32 swhead = vring->swhead;
        int avail = wil_vring_avail_tx(vring);
        int nr_frags = skb_shinfo(skb)->nr_frags;
-       uint f;
+       uint f = 0;
        int vring_index = vring - wil->vring_tx;
        uint i = swhead;
        dma_addr_t pa;
@@ -686,13 +751,20 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
                return -EINVAL;
        /* 1-st segment */
        wil_tx_desc_map(d, pa, skb_headlen(skb), vring_index);
+       /* Process TCP/UDP checksum offloading */
+       if (wil_tx_desc_offload_cksum_set(wil, d, skb)) {
+               wil_err(wil, "VRING #%d Failed to set cksum, drop packet\n",
+                       vring_index);
+               goto dma_error;
+       }
+
        d->mac.d[2] |= ((nr_frags + 1) <<
                       MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS);
        if (nr_frags)
                *_d = *d;
 
        /* middle segments */
-       for (f = 0; f < nr_frags; f++) {
+       for (; f < nr_frags; f++) {
                const struct skb_frag_struct *frag =
                                &skb_shinfo(skb)->frags[f];
                int len = skb_frag_size(frag);
@@ -703,7 +775,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
                if (unlikely(dma_mapping_error(dev, pa)))
                        goto dma_error;
                wil_tx_desc_map(d, pa, len, vring_index);
-               vring->ctx[i] = NULL;
+               vring->ctx[i].mapped_as_page = 1;
                *_d = *d;
        }
        /* for the last seg only */
@@ -712,6 +784,12 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
        d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS);
        *_d = *d;
 
+       /* hold reference to skb
+        * to prevent skb release before accounting
+        * in case of immediate "tx done"
+        */
+       vring->ctx[i].skb = skb_get(skb);
+
        wil_hex_dump_txrx("Tx ", DUMP_PREFIX_NONE, 32, 4,
                          (const void *)d, sizeof(*d), false);
 
@@ -720,29 +798,31 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
        wil_dbg_txrx(wil, "Tx swhead %d -> %d\n", swhead, vring->swhead);
        trace_wil6210_tx(vring_index, swhead, skb->len, nr_frags);
        iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail));
-       /* hold reference to skb
-        * to prevent skb release before accounting
-        * in case of immediate "tx done"
-        */
-       vring->ctx[i] = skb_get(skb);
 
        return 0;
  dma_error:
        /* unmap what we have mapped */
-       /* Note: increment @f to operate with positive index */
-       for (f++; f > 0; f--) {
+       nr_frags = f + 1; /* frags mapped + one for skb head */
+       for (f = 0; f < nr_frags; f++) {
                u16 dmalen;
+               struct wil_ctx *ctx;
 
                i = (swhead + f) % vring->size;
+               ctx = &vring->ctx[i];
                _d = &(vring->va[i].tx);
                *d = *_d;
                _d->dma.status = TX_DMA_STATUS_DU;
                pa = wil_desc_addr(&d->dma.addr);
                dmalen = le16_to_cpu(d->dma.length);
-               if (vring->ctx[i])
-                       dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE);
-               else
+               if (ctx->mapped_as_page)
                        dma_unmap_page(dev, pa, dmalen, DMA_TO_DEVICE);
+               else
+                       dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE);
+
+               if (ctx->skb)
+                       dev_kfree_skb_any(ctx->skb);
+
+               memset(ctx, 0, sizeof(*ctx));
        }
 
        return -EINVAL;
@@ -821,8 +901,9 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid)
                                              &vring->va[vring->swtail].tx;
                struct vring_tx_desc dd, *d = &dd;
                dma_addr_t pa;
-               struct sk_buff *skb;
                u16 dmalen;
+               struct wil_ctx *ctx = &vring->ctx[vring->swtail];
+               struct sk_buff *skb = ctx->skb;
 
                *d = *_d;
 
@@ -840,7 +921,11 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid)
                                  (const void *)d, sizeof(*d), false);
 
                pa = wil_desc_addr(&d->dma.addr);
-               skb = vring->ctx[vring->swtail];
+               if (ctx->mapped_as_page)
+                       dma_unmap_page(dev, pa, dmalen, DMA_TO_DEVICE);
+               else
+                       dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE);
+
                if (skb) {
                        if (d->dma.error == 0) {
                                ndev->stats.tx_packets++;
@@ -849,16 +934,15 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid)
                                ndev->stats.tx_errors++;
                        }
 
-                       dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE);
                        dev_kfree_skb_any(skb);
-                       vring->ctx[vring->swtail] = NULL;
-               } else {
-                       dma_unmap_page(dev, pa, dmalen, DMA_TO_DEVICE);
                }
-               d->dma.addr.addr_low = 0;
-               d->dma.addr.addr_high = 0;
-               d->dma.length = 0;
-               d->dma.status = TX_DMA_STATUS_DU;
+               memset(ctx, 0, sizeof(*ctx));
+               /*
+                * There is no need to touch HW descriptor:
+                * - ststus bit TX_DMA_STATUS_DU is set by design,
+                *   so hardware will not try to process this desc.,
+                * - rest of descriptor will be initialized on Tx.
+                */
                vring->swtail = wil_vring_next_tail(vring);
                done++;
        }
index 859aea68a1faa72169f3578a43bd4b1abb607dce..b3828279204c97d4057c7fc8253b5c54d43deed5 100644 (file)
@@ -235,7 +235,16 @@ struct vring_tx_mac {
 
 #define DMA_CFG_DESC_TX_0_L4_TYPE_POS 30
 #define DMA_CFG_DESC_TX_0_L4_TYPE_LEN 2
-#define DMA_CFG_DESC_TX_0_L4_TYPE_MSK 0xC0000000
+#define DMA_CFG_DESC_TX_0_L4_TYPE_MSK 0xC0000000 /* L4 type: 0-UDP, 2-TCP */
+
+
+#define DMA_CFG_DESC_TX_OFFLOAD_CFG_MAC_LEN_POS 0
+#define DMA_CFG_DESC_TX_OFFLOAD_CFG_MAC_LEN_LEN 7
+#define DMA_CFG_DESC_TX_OFFLOAD_CFG_MAC_LEN_MSK 0x7F /* MAC hdr len */
+
+#define DMA_CFG_DESC_TX_OFFLOAD_CFG_L3T_IPV4_POS 7
+#define DMA_CFG_DESC_TX_OFFLOAD_CFG_L3T_IPV4_LEN 1
+#define DMA_CFG_DESC_TX_OFFLOAD_CFG_L3T_IPV4_MSK 0x80 /* 1-IPv4, 0-IPv6 */
 
 
 #define TX_DMA_STATUS_DU         BIT(0)
@@ -334,8 +343,17 @@ struct vring_rx_mac {
 
 #define RX_DMA_D0_CMD_DMA_IT     BIT(10)
 
+/* Error field, offload bits */
+#define RX_DMA_ERROR_L3_ERR   BIT(4)
+#define RX_DMA_ERROR_L4_ERR   BIT(5)
+
+
+/* Status field */
 #define RX_DMA_STATUS_DU         BIT(0)
 #define RX_DMA_STATUS_ERROR      BIT(2)
+
+#define RX_DMA_STATUS_L3_IDENT   BIT(4)
+#define RX_DMA_STATUS_L4_IDENT   BIT(5)
 #define RX_DMA_STATUS_PHY_INFO   BIT(6)
 
 struct vring_rx_dma {
index 44fdab51de7e52b9c9565c318c2b6eac2df3527e..c4a51638736a27ab4a41ffe1e3e5026400e4e249 100644 (file)
@@ -156,11 +156,22 @@ struct wil6210_mbox_hdr {
 /* max. value for wil6210_mbox_hdr.len */
 #define MAX_MBOXITEM_SIZE   (240)
 
+/**
+ * struct wil6210_mbox_hdr_wmi - WMI header
+ *
+ * @mid: MAC ID
+ *     00 - default, created by FW
+ *     01..0f - WiFi ports, driver to create
+ *     10..fe - debug
+ *     ff - broadcast
+ * @id: command/event ID
+ * @timestamp: FW fills for events, free-running msec timer
+ */
 struct wil6210_mbox_hdr_wmi {
-       u8 reserved0[2];
+       u8 mid;
+       u8 reserved;
        __le16 id;
-       __le16 info1; /* bits [0..3] - device_id, rest - unused */
-       u8 reserved1[2];
+       __le32 timestamp;
 } __packed;
 
 struct pending_wmi_event {
@@ -172,6 +183,14 @@ struct pending_wmi_event {
        } __packed event;
 };
 
+/**
+ * struct wil_ctx - software context for Vring descriptor
+ */
+struct wil_ctx {
+       struct sk_buff *skb;
+       u8 mapped_as_page:1;
+};
+
 union vring_desc;
 
 struct vring {
@@ -181,7 +200,7 @@ struct vring {
        u32 swtail;
        u32 swhead;
        u32 hwtail; /* write here to inform hw */
-       void **ctx; /* void *ctx[size] - software context */
+       struct wil_ctx *ctx; /* ctx[size] - software context */
 };
 
 enum { /* for wil6210_priv.status */
index dc8059ad4bab0d6d979d298d22d3bbf913211e85..5220f158b8f5d77bdf9d07db5b9261d1780551d1 100644 (file)
@@ -172,8 +172,8 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
                        .len = cpu_to_le16(sizeof(cmd.wmi) + len),
                },
                .wmi = {
+                       .mid = 0,
                        .id = cpu_to_le16(cmdid),
-                       .info1 = 0,
                },
        };
        struct wil6210_mbox_ring *r = &wil->mbox_ctl.tx;
@@ -248,7 +248,7 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
        iowrite32(r->head = next_head, wil->csr + HOST_MBOX +
                  offsetof(struct wil6210_mbox_ctl, tx.head));
 
-       trace_wil6210_wmi_cmd(cmdid, buf, len);
+       trace_wil6210_wmi_cmd(&cmd.wmi, buf, len);
 
        /* interrupt to FW */
        iowrite32(SW_INT_MBOX, wil->csr + HOST_SW_INT);
@@ -640,9 +640,13 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
                            hdr.flags);
                if ((hdr.type == WIL_MBOX_HDR_TYPE_WMI) &&
                    (len >= sizeof(struct wil6210_mbox_hdr_wmi))) {
-                       u16 id = le16_to_cpu(evt->event.wmi.id);
-                       wil_dbg_wmi(wil, "WMI event 0x%04x\n", id);
-                       trace_wil6210_wmi_event(id, &evt->event.wmi, len);
+                       struct wil6210_mbox_hdr_wmi *wmi = &evt->event.wmi;
+                       u16 id = le16_to_cpu(wmi->id);
+                       u32 tstamp = le32_to_cpu(wmi->timestamp);
+                       wil_dbg_wmi(wil, "WMI event 0x%04x MID %d @%d msec\n",
+                                   id, wmi->mid, tstamp);
+                       trace_wil6210_wmi_event(wmi, &wmi[1],
+                                               len - sizeof(*wmi));
                }
                wil_hex_dump_wmi("evt ", DUMP_PREFIX_OFFSET, 16, 1,
                                 &evt->event.hdr, sizeof(hdr) + len, true);
@@ -920,6 +924,12 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
                cmd.sniffer_cfg.phy_support =
                        cpu_to_le32((wil->monitor_flags & MONITOR_FLAG_CONTROL)
                                    ? WMI_SNIFFER_CP : WMI_SNIFFER_DP);
+       } else {
+               /* Initialize offload (in non-sniffer mode).
+                * Linux IP stack always calculates IP checksum
+                * HW always calculate TCP/UDP checksum
+                */
+               cmd.l3_l4_ctrl |= (1 << L3_L4_CTRL_TCPIP_CHECKSUM_EN_POS);
        }
        /* typical time for secure PCP is 840ms */
        rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd),
index 8e8975562ec3b819ff20b32de938a3b012b6671b..80099016d21f4a04cb22b5e3b98ccd84608e658a 100644 (file)
@@ -242,7 +242,7 @@ void brcmf_txflowblock_if(struct brcmf_if *ifp,
 {
        unsigned long flags;
 
-       if (!ifp)
+       if (!ifp || !ifp->ndev)
                return;
 
        brcmf_dbg(TRACE, "enter: idx=%d stop=0x%X reason=%d state=%d\n",
index f0d9f7f6c83d70fbd677175b43ebe70f306795eb..29b1f24c2d0f92c86a55dade5e0e61a943004608 100644 (file)
@@ -1744,13 +1744,14 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
        ulong flags;
        int fifo = BRCMF_FWS_FIFO_BCMC;
        bool multicast = is_multicast_ether_addr(eh->h_dest);
+       bool pae = eh->h_proto == htons(ETH_P_PAE);
 
        /* determine the priority */
        if (!skb->priority)
                skb->priority = cfg80211_classify8021d(skb);
 
        drvr->tx_multicast += !!multicast;
-       if (ntohs(eh->h_proto) == ETH_P_PAE)
+       if (pae)
                atomic_inc(&ifp->pend_8021x_cnt);
 
        if (!brcmf_fws_fc_active(fws)) {
@@ -1781,6 +1782,11 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
                brcmf_fws_schedule_deq(fws);
        } else {
                brcmf_err("drop skb: no hanger slot\n");
+               if (pae) {
+                       atomic_dec(&ifp->pend_8021x_cnt);
+                       if (waitqueue_active(&ifp->pend_8021x_wait))
+                               wake_up(&ifp->pend_8021x_wait);
+               }
                brcmu_pkt_buf_free_skb(skb);
        }
        brcmf_fws_unlock(drvr, flags);
index 277b37ae71267a194d6ebcc541b93cc786ef9078..7fa71f73cfe89c5bfb5f2fca8e1e83c4d7124045 100644 (file)
@@ -1093,8 +1093,11 @@ static void brcmf_link_down(struct brcmf_cfg80211_vif *vif)
                brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n ");
                err = brcmf_fil_cmd_data_set(vif->ifp,
                                             BRCMF_C_DISASSOC, NULL, 0);
-               if (err)
+               if (err) {
                        brcmf_err("WLC_DISASSOC failed (%d)\n", err);
+                       cfg80211_disconnected(vif->wdev.netdev, 0,
+                                             NULL, 0, GFP_KERNEL);
+               }
                clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state);
        }
        clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
index bd982856d3853b4c6415b43c137d76b3eb4eeabf..fa391e4eb09893019bdc515bf61f03eeb66179f0 100644 (file)
@@ -928,9 +928,9 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
                        }
                } else if (txs->phyerr) {
                        update_rate = false;
-                       brcms_err(wlc->hw->d11core,
-                                 "%s: ampdu tx phy error (0x%x)\n",
-                                 __func__, txs->phyerr);
+                       brcms_dbg_ht(wlc->hw->d11core,
+                                    "%s: ampdu tx phy error (0x%x)\n",
+                                    __func__, txs->phyerr);
                }
        }
 
index 9fd6f2fef11bfe546126c86ec857507d8fe8d9eb..7ca10bf4a4d3f81cee965a9045d725dd898e6c58 100644 (file)
@@ -882,8 +882,8 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs)
        mcl = le16_to_cpu(txh->MacTxControlLow);
 
        if (txs->phyerr)
-               brcms_err(wlc->hw->d11core, "phyerr 0x%x, rate 0x%x\n",
-                         txs->phyerr, txh->MainRates);
+               brcms_dbg_tx(wlc->hw->d11core, "phyerr 0x%x, rate 0x%x\n",
+                            txs->phyerr, txh->MainRates);
 
        if (txs->frameid != le16_to_cpu(txh->TxFrameID)) {
                brcms_err(wlc->hw->d11core, "frameid != txh->TxFrameID\n");
index 5862c373d7148851816a5b16bfeb9c1acaebb191..e824d4d4a18d7e1d385d9d95f8fea195766a3ae8 100644 (file)
@@ -1165,7 +1165,7 @@ void cw1200_rx_cb(struct cw1200_common *priv,
                if (cw1200_handle_action_rx(priv, skb))
                        return;
        } else if (ieee80211_is_beacon(frame->frame_control) &&
-                  !arg->status &&
+                  !arg->status && priv->vif &&
                   !memcmp(ieee80211_get_SA(frame), priv->vif->bss_conf.bssid,
                           ETH_ALEN)) {
                const u8 *tim_ie;
index 7afc613c37068cd23eced45680bfdfc3bc8635c0..48086e849515bfe43815971e1d4586c57e4c6ed6 100644 (file)
@@ -832,7 +832,7 @@ struct wsm_tx {
        /* the MSDU shall be terminated. Overrides the global */
        /* dot11MaxTransmitMsduLifeTime setting [optional] */
        /* Device will set the default value if this is 0. */
-       u32 expire_time;
+       __le32 expire_time;
 
        /* WSM_HT_TX_... */
        __le32 ht_tx_parameters;
index fe31590a51b2d81b41b40b2f862c96c5b2e10980..aea667b430c3ac7e70295562f33de2227813a198 100644 (file)
@@ -887,6 +887,7 @@ il3945_remove_debugfs(void *il, void *il_sta)
  */
 static void
 il3945_rs_rate_init_stub(void *il_r, struct ieee80211_supported_band *sband,
+                        struct cfg80211_chan_def *chandef,
                         struct ieee80211_sta *sta, void *il_sta)
 {
 }
index c092033945cc460022e1c8ea28e2622a9db0a79f..f09e257759d5a930cfdaa1c2a69484355677403f 100644 (file)
@@ -475,6 +475,8 @@ il3945_is_network_packet(struct il_priv *il, struct ieee80211_hdr *header)
        }
 }
 
+#define SMALL_PACKET_SIZE 256
+
 static void
 il3945_pass_packet_to_mac80211(struct il_priv *il, struct il_rx_buf *rxb,
                               struct ieee80211_rx_status *stats)
@@ -483,14 +485,13 @@ il3945_pass_packet_to_mac80211(struct il_priv *il, struct il_rx_buf *rxb,
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IL_RX_DATA(pkt);
        struct il3945_rx_frame_hdr *rx_hdr = IL_RX_HDR(pkt);
        struct il3945_rx_frame_end *rx_end = IL_RX_END(pkt);
-       u16 len = le16_to_cpu(rx_hdr->len);
+       u32 len = le16_to_cpu(rx_hdr->len);
        struct sk_buff *skb;
        __le16 fc = hdr->frame_control;
+       u32 fraglen = PAGE_SIZE << il->hw_params.rx_page_order;
 
        /* We received data from the HW, so stop the watchdog */
-       if (unlikely
-           (len + IL39_RX_FRAME_SIZE >
-            PAGE_SIZE << il->hw_params.rx_page_order)) {
+       if (unlikely(len + IL39_RX_FRAME_SIZE > fraglen)) {
                D_DROP("Corruption detected!\n");
                return;
        }
@@ -506,26 +507,32 @@ il3945_pass_packet_to_mac80211(struct il_priv *il, struct il_rx_buf *rxb,
                D_INFO("Woke queues - frame received on passive channel\n");
        }
 
-       skb = dev_alloc_skb(128);
+       skb = dev_alloc_skb(SMALL_PACKET_SIZE);
        if (!skb) {
                IL_ERR("dev_alloc_skb failed\n");
                return;
        }
 
        if (!il3945_mod_params.sw_crypto)
-               il_set_decrypted_flag(il, (struct ieee80211_hdr *)rxb_addr(rxb),
+               il_set_decrypted_flag(il, (struct ieee80211_hdr *)pkt,
                                      le32_to_cpu(rx_end->status), stats);
 
-       skb_add_rx_frag(skb, 0, rxb->page,
-                       (void *)rx_hdr->payload - (void *)pkt, len,
-                       len);
-
+       /* If frame is small enough to fit into skb->head, copy it
+        * and do not consume a full page
+        */
+       if (len <= SMALL_PACKET_SIZE) {
+               memcpy(skb_put(skb, len), rx_hdr->payload, len);
+       } else {
+               skb_add_rx_frag(skb, 0, rxb->page,
+                               (void *)rx_hdr->payload - (void *)pkt, len,
+                               fraglen);
+               il->alloc_rxb_page--;
+               rxb->page = NULL;
+       }
        il_update_stats(il, false, fc, len);
        memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
 
        ieee80211_rx(il->hw, skb);
-       il->alloc_rxb_page--;
-       rxb->page = NULL;
 }
 
 #define IL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6)
index b9b2bb51e60590ab7dfb91d4e284a6a0c6c259a7..c4b22e190a54f61ba99c01031a4456b1e5cf223e 100644 (file)
@@ -574,9 +574,11 @@ il4965_translate_rx_status(struct il_priv *il, u32 decrypt_in)
        return decrypt_out;
 }
 
+#define SMALL_PACKET_SIZE 256
+
 static void
 il4965_pass_packet_to_mac80211(struct il_priv *il, struct ieee80211_hdr *hdr,
-                              u16 len, u32 ampdu_status, struct il_rx_buf *rxb,
+                              u32 len, u32 ampdu_status, struct il_rx_buf *rxb,
                               struct ieee80211_rx_status *stats)
 {
        struct sk_buff *skb;
@@ -598,21 +600,25 @@ il4965_pass_packet_to_mac80211(struct il_priv *il, struct ieee80211_hdr *hdr,
            il_set_decrypted_flag(il, hdr, ampdu_status, stats))
                return;
 
-       skb = dev_alloc_skb(128);
+       skb = dev_alloc_skb(SMALL_PACKET_SIZE);
        if (!skb) {
                IL_ERR("dev_alloc_skb failed\n");
                return;
        }
 
-       skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len,
-                       len);
+       if (len <= SMALL_PACKET_SIZE) {
+               memcpy(skb_put(skb, len), hdr, len);
+       } else {
+               skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb),
+                               len, PAGE_SIZE << il->hw_params.rx_page_order);
+               il->alloc_rxb_page--;
+               rxb->page = NULL;
+       }
 
        il_update_stats(il, false, fc, len);
        memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
 
        ieee80211_rx(il->hw, skb);
-       il->alloc_rxb_page--;
-       rxb->page = NULL;
 }
 
 /* Called for N_RX (legacy ABG frames), or
index ed3c42a63a4369678f2764049f0b7e257f535fb4..3ccbaf791b48bfea34d3053d4d7d3cce6e165b22 100644 (file)
@@ -2803,6 +2803,7 @@ il4965_rs_remove_debugfs(void *il, void *il_sta)
  */
 static void
 il4965_rs_rate_init_stub(void *il_r, struct ieee80211_supported_band *sband,
+                        struct cfg80211_chan_def *chandef,
                         struct ieee80211_sta *sta, void *il_sta)
 {
 }
index 3952ddf2ddb2bb596ffca3d0ff951238774bdb98..1531a4fc09601bd101fde1e20a528d7631f8baf8 100644 (file)
@@ -758,7 +758,7 @@ int iwl_alive_start(struct iwl_priv *priv)
                                         BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
                if (ret)
                        return ret;
-       } else {
+       } else if (priv->lib->bt_params) {
                /*
                 * default is 2-wire BT coexexistence support
                 */
index 1b693944123b5b0eda877f8d93a4c64775cc04ec..91eb09b9b56f38d357039cf28c681cfbdfa5e925 100644 (file)
@@ -3319,7 +3319,8 @@ static void rs_remove_debugfs(void *priv, void *priv_sta)
  * station is added we ignore it.
  */
 static void rs_rate_init_stub(void *priv_r, struct ieee80211_supported_band *sband,
-                        struct ieee80211_sta *sta, void *priv_sta)
+                             struct cfg80211_chan_def *chandef,
+                             struct ieee80211_sta *sta, void *priv_sta)
 {
 }
 static struct rate_control_ops rs_ops = {
index ff8cc75c189d4d842abf8611fb8c5e7c7a63bf38..a70c7b9d9bad897345fb1e1e89d5c421e0d8a3da 100644 (file)
@@ -97,6 +97,8 @@
 
 #define APMG_PCIDEV_STT_VAL_L1_ACT_DIS         (0x00000800)
 
+#define APMG_RTC_INT_STT_RFKILL                (0x10000000)
+
 /* Device system time */
 #define DEVICE_SYSTEM_TIME_REG 0xA0206C
 
index 7e5e5c2f9f87316f5319605b1d9c6814c2940dc0..83da884cf3032564df37a96be42c1601496fbc52 100644 (file)
@@ -134,7 +134,7 @@ struct wowlan_key_data {
        struct iwl_wowlan_rsc_tsc_params_cmd *rsc_tsc;
        struct iwl_wowlan_tkip_params_cmd *tkip;
        bool error, use_rsc_tsc, use_tkip;
-       int gtk_key_idx;
+       int wep_key_idx;
 };
 
 static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
@@ -188,8 +188,8 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
                        wkc.wep_key.key_offset = 0;
                } else {
                        /* others start at 1 */
-                       data->gtk_key_idx++;
-                       wkc.wep_key.key_offset = data->gtk_key_idx;
+                       data->wep_key_idx++;
+                       wkc.wep_key.key_offset = data->wep_key_idx;
                }
 
                ret = iwl_mvm_send_cmd_pdu(mvm, WEP_KEY, CMD_SYNC,
@@ -316,8 +316,13 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
                mvm->ptk_ivlen = key->iv_len;
                mvm->ptk_icvlen = key->icv_len;
        } else {
-               data->gtk_key_idx++;
-               key->hw_key_idx = data->gtk_key_idx;
+               /*
+                * firmware only supports TSC/RSC for a single key,
+                * so if there are multiple keep overwriting them
+                * with new ones -- this relies on mac80211 doing
+                * list_add_tail().
+                */
+               key->hw_key_idx = 1;
                mvm->gtk_ivlen = key->iv_len;
                mvm->gtk_icvlen = key->icv_len;
        }
index e56ed2a848886ce6c9001ef9a69a12d54c5f102b..c24a744910acd447c0b7376670e5e97b038cb09c 100644 (file)
@@ -988,7 +988,11 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        char buf[100];
 
-       if (!dbgfs_dir)
+       /*
+        * Check if debugfs directory already exist before creating it.
+        * This may happen when, for example, resetting hw or suspend-resume
+        */
+       if (!dbgfs_dir || mvmvif->dbgfs_dir)
                return;
 
        mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir);
index b60d14151721da3cb141b9b74ac0e3aee2d43a92..365095a0c3b3101e3c87b76036dbd82b352b9deb 100644 (file)
@@ -69,7 +69,6 @@
 /* Scan Commands, Responses, Notifications */
 
 /* Masks for iwl_scan_channel.type flags */
-#define SCAN_CHANNEL_TYPE_PASSIVE      0
 #define SCAN_CHANNEL_TYPE_ACTIVE       BIT(0)
 #define SCAN_CHANNEL_NARROW_BAND       BIT(22)
 
index e08683b2053183f7e7ea9df370a37bdb4b70c2e4..f19baf0dea6b9c84dac1a86d393c8ddb68aa5f53 100644 (file)
@@ -257,7 +257,11 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
        if (ret)
                return ret;
 
-       return ieee80211_register_hw(mvm->hw);
+       ret = ieee80211_register_hw(mvm->hw);
+       if (ret)
+               iwl_mvm_leds_exit(mvm);
+
+       return ret;
 }
 
 static void iwl_mvm_mac_tx(struct ieee80211_hw *hw,
@@ -385,6 +389,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
        ieee80211_wake_queues(mvm->hw);
 
        mvm->vif_count = 0;
+       mvm->rx_ba_sessions = 0;
 }
 
 static int iwl_mvm_mac_start(struct ieee80211_hw *hw)
@@ -506,6 +511,27 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
        if (ret)
                goto out_unlock;
 
+       /*
+        * TODO: remove this temporary code.
+        * Currently MVM FW supports power management only on single MAC.
+        * If new interface added, disable PM on existing interface.
+        * P2P device is a special case, since it is handled by FW similary to
+        * scan. If P2P deviced is added, PM remains enabled on existing
+        * interface.
+        * Note: the method below does not count the new interface being added
+        * at this moment.
+        */
+       if (vif->type != NL80211_IFTYPE_P2P_DEVICE)
+               mvm->vif_count++;
+       if (mvm->vif_count > 1) {
+               IWL_DEBUG_MAC80211(mvm,
+                                  "Disable power on existing interfaces\n");
+               ieee80211_iterate_active_interfaces_atomic(
+                                           mvm->hw,
+                                           IEEE80211_IFACE_ITER_NORMAL,
+                                           iwl_mvm_pm_disable_iterator, mvm);
+       }
+
        /*
         * The AP binding flow can be done only after the beacon
         * template is configured (which happens only in the mac80211
@@ -529,27 +555,6 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
                goto out_unlock;
        }
 
-       /*
-        * TODO: remove this temporary code.
-        * Currently MVM FW supports power management only on single MAC.
-        * If new interface added, disable PM on existing interface.
-        * P2P device is a special case, since it is handled by FW similary to
-        * scan. If P2P deviced is added, PM remains enabled on existing
-        * interface.
-        * Note: the method below does not count the new interface being added
-        * at this moment.
-        */
-       if (vif->type != NL80211_IFTYPE_P2P_DEVICE)
-               mvm->vif_count++;
-       if (mvm->vif_count > 1) {
-               IWL_DEBUG_MAC80211(mvm,
-                                  "Disable power on existing interfaces\n");
-               ieee80211_iterate_active_interfaces_atomic(
-                                           mvm->hw,
-                                           IEEE80211_IFACE_ITER_NORMAL,
-                                           iwl_mvm_pm_disable_iterator, mvm);
-       }
-
        ret = iwl_mvm_mac_ctxt_add(mvm, vif);
        if (ret)
                goto out_release;
@@ -1006,6 +1011,21 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
        mutex_lock(&mvm->mutex);
        if (old_state == IEEE80211_STA_NOTEXIST &&
            new_state == IEEE80211_STA_NONE) {
+               /*
+                * Firmware bug - it'll crash if the beacon interval is less
+                * than 16. We can't avoid connecting at all, so refuse the
+                * station state change, this will cause mac80211 to abandon
+                * attempts to connect to this AP, and eventually wpa_s will
+                * blacklist the AP...
+                */
+               if (vif->type == NL80211_IFTYPE_STATION &&
+                   vif->bss_conf.beacon_int < 16) {
+                       IWL_ERR(mvm,
+                               "AP %pM beacon interval is %d, refusing due to firmware bug!\n",
+                               sta->addr, vif->bss_conf.beacon_int);
+                       ret = -EINVAL;
+                       goto out_unlock;
+               }
                ret = iwl_mvm_add_sta(mvm, vif, sta);
        } else if (old_state == IEEE80211_STA_NONE &&
                   new_state == IEEE80211_STA_AUTH) {
@@ -1038,6 +1058,7 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
        } else {
                ret = -EIO;
        }
+ out_unlock:
        mutex_unlock(&mvm->mutex);
 
        return ret;
index d40d7db185d6cdbb22ca2a2d1fefef0794970971..420e82d379d9826690d297de690c3e84a2307f87 100644 (file)
@@ -419,6 +419,7 @@ struct iwl_mvm {
        struct work_struct sta_drained_wk;
        unsigned long sta_drained[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)];
        atomic_t pending_frames[IWL_MVM_STATION_COUNT];
+       u8 rx_ba_sessions;
 
        /* configured by mac80211 */
        u32 rts_threshold;
index b328a988c130ec6136f5198d78225870877aa1a4..376ea2112de2949ec36b606dc56a4d5e2254e5f9 100644 (file)
@@ -3159,8 +3159,9 @@ static void rs_remove_debugfs(void *mvm, void *mvm_sta)
  * station is added we ignore it.
  */
 static void rs_rate_init_stub(void *mvm_r,
-                                struct ieee80211_supported_band *sband,
-                                struct ieee80211_sta *sta, void *mvm_sta)
+                             struct ieee80211_supported_band *sband,
+                             struct cfg80211_chan_def *chandef,
+                             struct ieee80211_sta *sta, void *mvm_sta)
 {
 }
 static struct rate_control_ops rs_mvm_ops = {
index 2157b0f8ced5cc7c314a246d758a869128e57c59..acdff6b67e0460e669e5c25192af245df93ac4b5 100644 (file)
@@ -137,8 +137,8 @@ static void iwl_mvm_scan_fill_ssids(struct iwl_scan_cmd *cmd,
 {
        int fw_idx, req_idx;
 
-       fw_idx = 0;
-       for (req_idx = req->n_ssids - 1; req_idx > 0; req_idx--) {
+       for (req_idx = req->n_ssids - 1, fw_idx = 0; req_idx > 0;
+            req_idx--, fw_idx++) {
                cmd->direct_scan[fw_idx].id = WLAN_EID_SSID;
                cmd->direct_scan[fw_idx].len = req->ssids[req_idx].ssid_len;
                memcpy(cmd->direct_scan[fw_idx].ssid,
@@ -153,7 +153,9 @@ static void iwl_mvm_scan_fill_ssids(struct iwl_scan_cmd *cmd,
  * just to notify that this scan is active and not passive.
  * In order to notify the FW of the number of SSIDs we wish to scan (including
  * the zero-length one), we need to set the corresponding bits in chan->type,
- * one for each SSID, and set the active bit (first).
+ * one for each SSID, and set the active bit (first). The first SSID is already
+ * included in the probe template, so we need to set only req->n_ssids - 1 bits
+ * in addition to the first bit.
  */
 static u16 iwl_mvm_get_active_dwell(enum ieee80211_band band, int n_ssids)
 {
@@ -176,19 +178,12 @@ static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd,
        struct iwl_scan_channel *chan = (struct iwl_scan_channel *)
                (cmd->data + le16_to_cpu(cmd->tx_cmd.len));
        int i;
-       __le32 chan_type_value;
-
-       if (req->n_ssids > 0)
-               chan_type_value = cpu_to_le32(BIT(req->n_ssids + 1) - 1);
-       else
-               chan_type_value = SCAN_CHANNEL_TYPE_PASSIVE;
 
        for (i = 0; i < cmd->channel_count; i++) {
                chan->channel = cpu_to_le16(req->channels[i]->hw_value);
+               chan->type = cpu_to_le32(BIT(req->n_ssids) - 1);
                if (req->channels[i]->flags & IEEE80211_CHAN_PASSIVE_SCAN)
-                       chan->type = SCAN_CHANNEL_TYPE_PASSIVE;
-               else
-                       chan->type = chan_type_value;
+                       chan->type &= cpu_to_le32(~SCAN_CHANNEL_TYPE_ACTIVE);
                chan->active_dwell = cpu_to_le16(active_dwell);
                chan->passive_dwell = cpu_to_le16(passive_dwell);
                chan->iteration_count = cpu_to_le16(1);
index 62fe5209093bf7637cb024b2c81dfd301cfd4649..563f559b902da8560f7cbdd06726872d7849b34b 100644 (file)
@@ -608,6 +608,8 @@ int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *bsta)
        return ret;
 }
 
+#define IWL_MAX_RX_BA_SESSIONS 16
+
 int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                       int tid, u16 ssn, bool start)
 {
@@ -618,11 +620,20 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
 
        lockdep_assert_held(&mvm->mutex);
 
+       if (start && mvm->rx_ba_sessions >= IWL_MAX_RX_BA_SESSIONS) {
+               IWL_WARN(mvm, "Not enough RX BA SESSIONS\n");
+               return -ENOSPC;
+       }
+
        cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color);
        cmd.sta_id = mvm_sta->sta_id;
        cmd.add_modify = STA_MODE_MODIFY;
-       cmd.add_immediate_ba_tid = (u8) tid;
-       cmd.add_immediate_ba_ssn = cpu_to_le16(ssn);
+       if (start) {
+               cmd.add_immediate_ba_tid = (u8) tid;
+               cmd.add_immediate_ba_ssn = cpu_to_le16(ssn);
+       } else {
+               cmd.remove_immediate_ba_tid = (u8) tid;
+       }
        cmd.modify_mask = start ? STA_MODIFY_ADD_BA_TID :
                                  STA_MODIFY_REMOVE_BA_TID;
 
@@ -648,6 +659,14 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                break;
        }
 
+       if (!ret) {
+               if (start)
+                       mvm->rx_ba_sessions++;
+               else if (mvm->rx_ba_sessions > 0)
+                       /* check that restart flow didn't zero the counter */
+                       mvm->rx_ba_sessions--;
+       }
+
        return ret;
 }
 
@@ -896,6 +915,7 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
        struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
        u16 txq_id;
+       enum iwl_mvm_agg_state old_state;
 
        /*
         * First set the agg state to OFF to avoid calling
@@ -905,13 +925,17 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        txq_id = tid_data->txq_id;
        IWL_DEBUG_TX_QUEUES(mvm, "Flush AGG: sta %d tid %d q %d state %d\n",
                            mvmsta->sta_id, tid, txq_id, tid_data->state);
+       old_state = tid_data->state;
        tid_data->state = IWL_AGG_OFF;
        spin_unlock_bh(&mvmsta->lock);
 
-       if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), true))
-               IWL_ERR(mvm, "Couldn't flush the AGG queue\n");
+       if (old_state >= IWL_AGG_ON) {
+               if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), true))
+                       IWL_ERR(mvm, "Couldn't flush the AGG queue\n");
+
+               iwl_trans_txq_disable(mvm->trans, tid_data->txq_id);
+       }
 
-       iwl_trans_txq_disable(mvm->trans, tid_data->txq_id);
        mvm->queue_to_mac80211[tid_data->txq_id] =
                                IWL_INVALID_MAC80211_QUEUE;
 
index 81f3ea5b09a4b7f26d0f4bb7877e50dedea6cd38..ff13458efc27096343f17e5c408465d9dce1253a 100644 (file)
@@ -130,6 +130,7 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
        {IWL_PCI_DEVICE(0x423C, 0x1306, iwl5150_abg_cfg)}, /* Half Mini Card */
        {IWL_PCI_DEVICE(0x423C, 0x1221, iwl5150_agn_cfg)}, /* Mini Card */
        {IWL_PCI_DEVICE(0x423C, 0x1321, iwl5150_agn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x423C, 0x1326, iwl5150_abg_cfg)}, /* Half Mini Card */
 
        {IWL_PCI_DEVICE(0x423D, 0x1211, iwl5150_agn_cfg)}, /* Mini Card */
        {IWL_PCI_DEVICE(0x423D, 0x1311, iwl5150_agn_cfg)}, /* Half Mini Card */
index fd848cd1583ebeb3372792911849a0eec25d9667..f600e68a410a1abe454170bd65d29b5937df41a9 100644 (file)
@@ -888,6 +888,14 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
 
                iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
                if (hw_rfkill) {
+                       /*
+                        * Clear the interrupt in APMG if the NIC is going down.
+                        * Note that when the NIC exits RFkill (else branch), we
+                        * can't access prph and the NIC will be reset in
+                        * start_hw anyway.
+                        */
+                       iwl_write_prph(trans, APMG_RTC_INT_STT_REG,
+                                      APMG_RTC_INT_STT_RFKILL);
                        set_bit(STATUS_RFKILL, &trans_pcie->status);
                        if (test_and_clear_bit(STATUS_HCMD_ACTIVE,
                                               &trans_pcie->status))
index 826c15602c469a524b857c135f7b38cb4e5782a1..96cfcdd390794060ee6c72c3951984f33da5ff38 100644 (file)
@@ -670,6 +670,11 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
                return err;
        }
 
+       /* Reset the entire device */
+       iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+
+       usleep_range(10, 15);
+
        iwl_pcie_apm_init(trans);
 
        /* From now on, the op_mode will be kept updated about RF kill state */
index cb34c7895f2a299b8c6b8f6c094f79cd9ab88c85..7b2a6229eedb2bfcb30e0f742e2c0108951bfade 100644 (file)
@@ -867,7 +867,7 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
 
        if (WARN_ON(skb->len < 10)) {
                /* Should not happen; just a sanity check for addr1 use */
-               dev_kfree_skb(skb);
+               ieee80211_free_txskb(hw, skb);
                return;
        }
 
@@ -884,13 +884,13 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
        }
 
        if (WARN(!channel, "TX w/o channel - queue = %d\n", txi->hw_queue)) {
-               dev_kfree_skb(skb);
+               ieee80211_free_txskb(hw, skb);
                return;
        }
 
        if (data->idle && !data->tmp_chan) {
                wiphy_debug(hw->wiphy, "Trying to TX when idle - reject\n");
-               dev_kfree_skb(skb);
+               ieee80211_free_txskb(hw, skb);
                return;
        }
 
@@ -2309,7 +2309,9 @@ static int __init init_mac80211_hwsim(void)
                        hw->flags |= IEEE80211_HW_SUPPORTS_RC_TABLE;
 
                hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |
-                                   WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+                                   WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
+                                   WIPHY_FLAG_AP_UAPSD;
+               hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
 
                /* ask mac80211 to reserve space for magic */
                hw->vif_data_size = sizeof(struct hwsim_vif_priv);
index a78e0651409c66e8f521bfe1842e2bd04f48f745..8f9f54231a1c416a3f47ee7346b0ca026c143aab 100644 (file)
@@ -189,7 +189,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
 
                skb_src = skb_dequeue(&pra_list->skb_head);
 
-               pra_list->total_pkts_size -= skb_src->len;
+               pra_list->total_pkt_count--;
 
                atomic_dec(&priv->wmm.tx_pkts_queued);
 
@@ -268,7 +268,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
 
                skb_queue_tail(&pra_list->skb_head, skb_aggr);
 
-               pra_list->total_pkts_size += skb_aggr->len;
+               pra_list->total_pkt_count++;
 
                atomic_inc(&priv->wmm.tx_pkts_queued);
 
index ef5fa890a28628666398f39624f83e1bfe6aa1f5..c5e21ede60f2f832796f71fd8effd46c5417e297 100644 (file)
@@ -25,7 +25,9 @@ module_param(reg_alpha2, charp, 0);
 
 static const struct ieee80211_iface_limit mwifiex_ap_sta_limits[] = {
        {
-               .max = 2, .types = BIT(NL80211_IFTYPE_STATION),
+               .max = 2, .types = BIT(NL80211_IFTYPE_STATION) |
+                                  BIT(NL80211_IFTYPE_P2P_GO) |
+                                  BIT(NL80211_IFTYPE_P2P_CLIENT),
        },
        {
                .max = 1, .types = BIT(NL80211_IFTYPE_AP),
@@ -189,6 +191,7 @@ mwifiex_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
        struct sk_buff *skb;
        u16 pkt_len;
        const struct ieee80211_mgmt *mgmt;
+       struct mwifiex_txinfo *tx_info;
        struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);
 
        if (!buf || !len) {
@@ -216,6 +219,10 @@ mwifiex_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
                return -ENOMEM;
        }
 
+       tx_info = MWIFIEX_SKB_TXCB(skb);
+       tx_info->bss_num = priv->bss_num;
+       tx_info->bss_type = priv->bss_type;
+
        mwifiex_form_mgmt_frame(skb, buf, len);
        mwifiex_queue_tx_pkt(priv, skb);
 
@@ -235,16 +242,20 @@ mwifiex_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
                                     u16 frame_type, bool reg)
 {
        struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);
+       u32 mask;
 
        if (reg)
-               priv->mgmt_frame_mask |= BIT(frame_type >> 4);
+               mask = priv->mgmt_frame_mask | BIT(frame_type >> 4);
        else
-               priv->mgmt_frame_mask &= ~BIT(frame_type >> 4);
-
-       mwifiex_send_cmd_async(priv, HostCmd_CMD_MGMT_FRAME_REG,
-                              HostCmd_ACT_GEN_SET, 0, &priv->mgmt_frame_mask);
+               mask = priv->mgmt_frame_mask & ~BIT(frame_type >> 4);
 
-       wiphy_dbg(wiphy, "info: mgmt frame registered\n");
+       if (mask != priv->mgmt_frame_mask) {
+               priv->mgmt_frame_mask = mask;
+               mwifiex_send_cmd_async(priv, HostCmd_CMD_MGMT_FRAME_REG,
+                                      HostCmd_ACT_GEN_SET, 0,
+                                      &priv->mgmt_frame_mask);
+               wiphy_dbg(wiphy, "info: mgmt frame registered\n");
+       }
 }
 
 /*
@@ -1716,9 +1727,9 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
        struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
        int ret;
 
-       if (priv->bss_mode != NL80211_IFTYPE_STATION) {
+       if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA) {
                wiphy_err(wiphy,
-                         "%s: reject infra assoc request in non-STA mode\n",
+                         "%s: reject infra assoc request in non-STA role\n",
                          dev->name);
                return -EINVAL;
        }
@@ -2298,8 +2309,7 @@ EXPORT_SYMBOL_GPL(mwifiex_del_virtual_intf);
 
 #ifdef CONFIG_PM
 static bool
-mwifiex_is_pattern_supported(struct cfg80211_wowlan_trig_pkt_pattern *pat,
-                            s8 *byte_seq)
+mwifiex_is_pattern_supported(struct cfg80211_pkt_pattern *pat, s8 *byte_seq)
 {
        int j, k, valid_byte_cnt = 0;
        bool dont_care_byte = false;
index 988552dece75d49ab3af4628dec68bd6a9627030..9eefacbc844bfab2eae14777c70719db377b3f7d 100644 (file)
@@ -404,18 +404,51 @@ mwifiex_is_rate_auto(struct mwifiex_private *priv)
                return false;
 }
 
-/*
- * This function gets the supported data rates.
- *
- * The function works in both Ad-Hoc and infra mode by printing the
- * band and returning the data rates.
+/* This function gets the supported data rates from bitmask inside
+ * cfg80211_scan_request.
+ */
+u32 mwifiex_get_rates_from_cfg80211(struct mwifiex_private *priv,
+                                   u8 *rates, u8 radio_type)
+{
+       struct wiphy *wiphy = priv->adapter->wiphy;
+       struct cfg80211_scan_request *request = priv->scan_request;
+       u32 num_rates, rate_mask;
+       struct ieee80211_supported_band *sband;
+       int i;
+
+       if (radio_type) {
+               sband = wiphy->bands[IEEE80211_BAND_5GHZ];
+               if (WARN_ON_ONCE(!sband))
+                       return 0;
+               rate_mask = request->rates[IEEE80211_BAND_5GHZ];
+       } else {
+               sband = wiphy->bands[IEEE80211_BAND_2GHZ];
+               if (WARN_ON_ONCE(!sband))
+                       return 0;
+               rate_mask = request->rates[IEEE80211_BAND_2GHZ];
+       }
+
+       num_rates = 0;
+       for (i = 0; i < sband->n_bitrates; i++) {
+               if ((BIT(i) & rate_mask) == 0)
+                       continue; /* skip rate */
+               rates[num_rates++] = (u8)(sband->bitrates[i].bitrate / 5);
+       }
+
+       return num_rates;
+}
+
+/* This function gets the supported data rates. The function works in
+ * both Ad-Hoc and infra mode by printing the band and returning the
+ * data rates.
  */
 u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates)
 {
        u32 k = 0;
        struct mwifiex_adapter *adapter = priv->adapter;
 
-       if (priv->bss_mode == NL80211_IFTYPE_STATION) {
+       if (priv->bss_mode == NL80211_IFTYPE_STATION ||
+           priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) {
                switch (adapter->config_bands) {
                case BAND_B:
                        dev_dbg(adapter->dev, "info: infra band=%d "
index 94cc09d48444600129620a247c3e227d10865e59..a5993475daef17b0aa09da324559bd8ea2789efa 100644 (file)
@@ -75,7 +75,8 @@
 #define MWIFIEX_BUF_FLAG_REQUEUED_PKT      BIT(0)
 #define MWIFIEX_BUF_FLAG_BRIDGED_PKT      BIT(1)
 
-#define MWIFIEX_BRIDGED_PKTS_THRESHOLD     1024
+#define MWIFIEX_BRIDGED_PKTS_THR_HIGH      1024
+#define MWIFIEX_BRIDGED_PKTS_THR_LOW        128
 
 enum mwifiex_bss_type {
        MWIFIEX_BSS_TYPE_STA = 0,
index 1b45aa5333008c9475595f91123c1bcb2f81e018..c0dfc4dea75a9e8d6776e90f9243a08dd8a1b8d8 100644 (file)
@@ -85,9 +85,6 @@ enum KEY_TYPE_ID {
 #define WAPI_KEY_LEN                   50
 
 #define MAX_POLL_TRIES                 100
-
-#define MAX_MULTI_INTERFACE_POLL_TRIES  1000
-
 #define MAX_FIRMWARE_POLL_TRIES                        100
 
 #define FIRMWARE_READY_SDIO                            0xfedc
@@ -1369,11 +1366,6 @@ struct host_cmd_ds_802_11_eeprom_access {
        u8 value;
 } __packed;
 
-struct host_cmd_tlv {
-       __le16 type;
-       __le16 len;
-} __packed;
-
 struct mwifiex_assoc_event {
        u8 sta_addr[ETH_ALEN];
        __le16 type;
@@ -1399,99 +1391,99 @@ struct host_cmd_11ac_vht_cfg {
 } __packed;
 
 struct host_cmd_tlv_akmp {
-       struct host_cmd_tlv tlv;
+       struct mwifiex_ie_types_header header;
        __le16 key_mgmt;
        __le16 key_mgmt_operation;
 } __packed;
 
 struct host_cmd_tlv_pwk_cipher {
-       struct host_cmd_tlv tlv;
+       struct mwifiex_ie_types_header header;
        __le16 proto;
        u8 cipher;
        u8 reserved;
 } __packed;
 
 struct host_cmd_tlv_gwk_cipher {
-       struct host_cmd_tlv tlv;
+       struct mwifiex_ie_types_header header;
        u8 cipher;
        u8 reserved;
 } __packed;
 
 struct host_cmd_tlv_passphrase {
-       struct host_cmd_tlv tlv;
+       struct mwifiex_ie_types_header header;
        u8 passphrase[0];
 } __packed;
 
 struct host_cmd_tlv_wep_key {
-       struct host_cmd_tlv tlv;
+       struct mwifiex_ie_types_header header;
        u8 key_index;
        u8 is_default;
        u8 key[1];
 };
 
 struct host_cmd_tlv_auth_type {
-       struct host_cmd_tlv tlv;
+       struct mwifiex_ie_types_header header;
        u8 auth_type;
 } __packed;
 
 struct host_cmd_tlv_encrypt_protocol {
-       struct host_cmd_tlv tlv;
+       struct mwifiex_ie_types_header header;
        __le16 proto;
 } __packed;
 
 struct host_cmd_tlv_ssid {
-       struct host_cmd_tlv tlv;
+       struct mwifiex_ie_types_header header;
        u8 ssid[0];
 } __packed;
 
 struct host_cmd_tlv_rates {
-       struct host_cmd_tlv tlv;
+       struct mwifiex_ie_types_header header;
        u8 rates[0];
 } __packed;
 
 struct host_cmd_tlv_bcast_ssid {
-       struct host_cmd_tlv tlv;
+       struct mwifiex_ie_types_header header;
        u8 bcast_ctl;
 } __packed;
 
 struct host_cmd_tlv_beacon_period {
-       struct host_cmd_tlv tlv;
+       struct mwifiex_ie_types_header header;
        __le16 period;
 } __packed;
 
 struct host_cmd_tlv_dtim_period {
-       struct host_cmd_tlv tlv;
+       struct mwifiex_ie_types_header header;
        u8 period;
 } __packed;
 
 struct host_cmd_tlv_frag_threshold {
-       struct host_cmd_tlv tlv;
+       struct mwifiex_ie_types_header header;
        __le16 frag_thr;
 } __packed;
 
 struct host_cmd_tlv_rts_threshold {
-       struct host_cmd_tlv tlv;
+       struct mwifiex_ie_types_header header;
        __le16 rts_thr;
 } __packed;
 
 struct host_cmd_tlv_retry_limit {
-       struct host_cmd_tlv tlv;
+       struct mwifiex_ie_types_header header;
        u8 limit;
 } __packed;
 
 struct host_cmd_tlv_mac_addr {
-       struct host_cmd_tlv tlv;
+       struct mwifiex_ie_types_header header;
        u8 mac_addr[ETH_ALEN];
 } __packed;
 
 struct host_cmd_tlv_channel_band {
-       struct host_cmd_tlv tlv;
+       struct mwifiex_ie_types_header header;
        u8 band_config;
        u8 channel;
 } __packed;
 
 struct host_cmd_tlv_ageout_timer {
-       struct host_cmd_tlv tlv;
+       struct mwifiex_ie_types_header header;
        __le32 sta_ao_timer;
 } __packed;
 
index e38342f86c515e6e574fbae572e7c51dbe7c8fa8..220af4fe0fc65b18b575c81025c436d303f01bbd 100644 (file)
@@ -87,7 +87,7 @@ mwifiex_update_autoindex_ies(struct mwifiex_private *priv,
        u8 *tmp;
 
        input_len = le16_to_cpu(ie_list->len);
-       travel_len = sizeof(struct host_cmd_tlv);
+       travel_len = sizeof(struct mwifiex_ie_types_header);
 
        ie_list->len = 0;
 
index caaf4bd56b3062ea4c9a11028233c1517f69296c..e021a581a143872d231d6c77de60dad877bcfa2a 100644 (file)
@@ -135,6 +135,7 @@ int mwifiex_init_priv(struct mwifiex_private *priv)
 
        priv->csa_chan = 0;
        priv->csa_expire_time = 0;
+       priv->del_list_idx = 0;
 
        return mwifiex_add_bss_prio_tbl(priv);
 }
@@ -377,18 +378,11 @@ static void mwifiex_free_lock_list(struct mwifiex_adapter *adapter)
 static void
 mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter)
 {
-       int i;
-
        if (!adapter) {
                pr_err("%s: adapter is NULL\n", __func__);
                return;
        }
 
-       for (i = 0; i < adapter->priv_num; i++) {
-               if (adapter->priv[i])
-                       del_timer_sync(&adapter->priv[i]->scan_delay_timer);
-       }
-
        mwifiex_cancel_all_pending_cmd(adapter);
 
        /* Free lock variables */
@@ -398,13 +392,8 @@ mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter)
        dev_dbg(adapter->dev, "info: free cmd buffer\n");
        mwifiex_free_cmd_buffer(adapter);
 
-       del_timer(&adapter->cmd_timer);
-
        dev_dbg(adapter->dev, "info: free scan table\n");
 
-       if (adapter->if_ops.cleanup_if)
-               adapter->if_ops.cleanup_if(adapter);
-
        if (adapter->sleep_cfm)
                dev_kfree_skb_any(adapter->sleep_cfm);
 }
@@ -693,7 +682,7 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter,
                if (!ret) {
                        dev_notice(adapter->dev,
                                   "WLAN FW already running! Skip FW dnld\n");
-                       goto done;
+                       return 0;
                }
 
                poll_num = MAX_FIRMWARE_POLL_TRIES;
@@ -702,7 +691,6 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter,
                if (!adapter->winner) {
                        dev_notice(adapter->dev,
                                   "FW already running! Skip FW dnld\n");
-                       poll_num = MAX_MULTI_INTERFACE_POLL_TRIES;
                        goto poll_fw;
                }
        }
@@ -719,14 +707,8 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter,
 poll_fw:
        /* Check if the firmware is downloaded successfully or not */
        ret = adapter->if_ops.check_fw_status(adapter, poll_num);
-       if (ret) {
+       if (ret)
                dev_err(adapter->dev, "FW failed to be active in time\n");
-               return -1;
-       }
-done:
-       /* re-enable host interrupt for mwifiex after fw dnld is successful */
-       if (adapter->if_ops.enable_int)
-               adapter->if_ops.enable_int(adapter);
 
        return ret;
 }
index 1c8a771e8e8127e666265d10447b88f884a4c5fa..9d7c0e6c4fc7419facd68a3c61f251fbedb86143 100644 (file)
@@ -1291,8 +1291,10 @@ int mwifiex_associate(struct mwifiex_private *priv,
 {
        u8 current_bssid[ETH_ALEN];
 
-       /* Return error if the adapter or table entry is not marked as infra */
-       if ((priv->bss_mode != NL80211_IFTYPE_STATION) ||
+       /* Return error if the adapter is not STA role or table entry
+        * is not marked as infra.
+        */
+       if ((GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA) ||
            (bss_desc->bss_mode != NL80211_IFTYPE_STATION))
                return -1;
 
@@ -1425,6 +1427,7 @@ int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac)
 
        switch (priv->bss_mode) {
        case NL80211_IFTYPE_STATION:
+       case NL80211_IFTYPE_P2P_CLIENT:
                return mwifiex_deauthenticate_infra(priv, mac);
        case NL80211_IFTYPE_ADHOC:
                return mwifiex_send_cmd_sync(priv,
index e15ab72fb03ddc1ad6eab8e54aded37de3143253..3402bffdd016ca21ff1ce424d98772d9f24ee3d5 100644 (file)
@@ -191,12 +191,16 @@ static int mwifiex_unregister(struct mwifiex_adapter *adapter)
 {
        s32 i;
 
+       if (adapter->if_ops.cleanup_if)
+               adapter->if_ops.cleanup_if(adapter);
+
        del_timer(&adapter->cmd_timer);
 
        /* Free private structures */
        for (i = 0; i < adapter->priv_num; i++) {
                if (adapter->priv[i]) {
                        mwifiex_free_curr_bcn(adapter->priv[i]);
+                       del_timer_sync(&adapter->priv[i]->scan_delay_timer);
                        kfree(adapter->priv[i]);
                }
        }
@@ -385,6 +389,17 @@ static void mwifiex_free_adapter(struct mwifiex_adapter *adapter)
        pr_debug("info: %s: free adapter\n", __func__);
 }
 
+/*
+ * This function cancels all works in the queue and destroys
+ * the main workqueue.
+ */
+static void mwifiex_terminate_workqueue(struct mwifiex_adapter *adapter)
+{
+       flush_workqueue(adapter->workqueue);
+       destroy_workqueue(adapter->workqueue);
+       adapter->workqueue = NULL;
+}
+
 /*
  * This function gets firmware and initializes it.
  *
@@ -394,16 +409,18 @@ static void mwifiex_free_adapter(struct mwifiex_adapter *adapter)
  */
 static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
 {
-       int ret;
+       int ret, i;
        char fmt[64];
        struct mwifiex_private *priv;
        struct mwifiex_adapter *adapter = context;
        struct mwifiex_fw_image fw;
+       struct semaphore *sem = adapter->card_sem;
+       bool init_failed = false;
 
        if (!firmware) {
                dev_err(adapter->dev,
                        "Failed to get firmware %s\n", adapter->fw_name);
-               goto done;
+               goto err_dnld_fw;
        }
 
        memset(&fw, 0, sizeof(struct mwifiex_fw_image));
@@ -416,7 +433,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
        else
                ret = mwifiex_dnld_fw(adapter, &fw);
        if (ret == -1)
-               goto done;
+               goto err_dnld_fw;
 
        dev_notice(adapter->dev, "WLAN FW is active\n");
 
@@ -427,10 +444,16 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
                                "Cal data request_firmware() failed\n");
        }
 
+       /* enable host interrupt after fw dnld is successful */
+       if (adapter->if_ops.enable_int) {
+               if (adapter->if_ops.enable_int(adapter))
+                       goto err_dnld_fw;
+       }
+
        adapter->init_wait_q_woken = false;
        ret = mwifiex_init_fw(adapter);
        if (ret == -1) {
-               goto done;
+               goto err_init_fw;
        } else if (!ret) {
                adapter->hw_status = MWIFIEX_HW_STATUS_READY;
                goto done;
@@ -439,12 +462,12 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
        wait_event_interruptible(adapter->init_wait_q,
                                 adapter->init_wait_q_woken);
        if (adapter->hw_status != MWIFIEX_HW_STATUS_READY)
-               goto done;
+               goto err_init_fw;
 
        priv = adapter->priv[MWIFIEX_BSS_ROLE_STA];
        if (mwifiex_register_cfg80211(adapter)) {
                dev_err(adapter->dev, "cannot register with cfg80211\n");
-               goto err_init_fw;
+               goto err_register_cfg80211;
        }
 
        rtnl_lock();
@@ -475,18 +498,52 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
        goto done;
 
 err_add_intf:
-       mwifiex_del_virtual_intf(adapter->wiphy, priv->wdev);
+       for (i = 0; i < adapter->priv_num; i++) {
+               priv = adapter->priv[i];
+
+               if (!priv)
+                       continue;
+
+               if (priv->wdev && priv->netdev)
+                       mwifiex_del_virtual_intf(adapter->wiphy, priv->wdev);
+       }
        rtnl_unlock();
+err_register_cfg80211:
+       wiphy_unregister(adapter->wiphy);
+       wiphy_free(adapter->wiphy);
 err_init_fw:
+       if (adapter->if_ops.disable_int)
+               adapter->if_ops.disable_int(adapter);
+err_dnld_fw:
        pr_debug("info: %s: unregister device\n", __func__);
-       adapter->if_ops.unregister_dev(adapter);
+       if (adapter->if_ops.unregister_dev)
+               adapter->if_ops.unregister_dev(adapter);
+
+       if ((adapter->hw_status == MWIFIEX_HW_STATUS_FW_READY) ||
+           (adapter->hw_status == MWIFIEX_HW_STATUS_READY)) {
+               pr_debug("info: %s: shutdown mwifiex\n", __func__);
+               adapter->init_wait_q_woken = false;
+
+               if (mwifiex_shutdown_drv(adapter) == -EINPROGRESS)
+                       wait_event_interruptible(adapter->init_wait_q,
+                                                adapter->init_wait_q_woken);
+       }
+       adapter->surprise_removed = true;
+       mwifiex_terminate_workqueue(adapter);
+       init_failed = true;
 done:
        if (adapter->cal_data) {
                release_firmware(adapter->cal_data);
                adapter->cal_data = NULL;
        }
-       release_firmware(adapter->firmware);
+       if (adapter->firmware) {
+               release_firmware(adapter->firmware);
+               adapter->firmware = NULL;
+       }
        complete(&adapter->fw_load);
+       if (init_failed)
+               mwifiex_free_adapter(adapter);
+       up(sem);
        return;
 }
 
@@ -796,18 +853,6 @@ static void mwifiex_main_work_queue(struct work_struct *work)
        mwifiex_main_process(adapter);
 }
 
-/*
- * This function cancels all works in the queue and destroys
- * the main workqueue.
- */
-static void
-mwifiex_terminate_workqueue(struct mwifiex_adapter *adapter)
-{
-       flush_workqueue(adapter->workqueue);
-       destroy_workqueue(adapter->workqueue);
-       adapter->workqueue = NULL;
-}
-
 /*
  * This function adds the card.
  *
@@ -836,6 +881,7 @@ mwifiex_add_card(void *card, struct semaphore *sem,
        }
 
        adapter->iface_type = iface_type;
+       adapter->card_sem = sem;
 
        adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING;
        adapter->surprise_removed = false;
@@ -855,7 +901,7 @@ mwifiex_add_card(void *card, struct semaphore *sem,
        INIT_WORK(&adapter->main_work, mwifiex_main_work_queue);
 
        /* Register the device. Fill up the private data structure with relevant
-          information from the card and request for the required IRQ. */
+          information from the card. */
        if (adapter->if_ops.register_dev(adapter)) {
                pr_err("%s: failed to register mwifiex device\n", __func__);
                goto err_registerdev;
@@ -866,17 +912,12 @@ mwifiex_add_card(void *card, struct semaphore *sem,
                goto err_init_fw;
        }
 
-       up(sem);
        return 0;
 
 err_init_fw:
        pr_debug("info: %s: unregister device\n", __func__);
        if (adapter->if_ops.unregister_dev)
                adapter->if_ops.unregister_dev(adapter);
-err_registerdev:
-       adapter->surprise_removed = true;
-       mwifiex_terminate_workqueue(adapter);
-err_kmalloc:
        if ((adapter->hw_status == MWIFIEX_HW_STATUS_FW_READY) ||
            (adapter->hw_status == MWIFIEX_HW_STATUS_READY)) {
                pr_debug("info: %s: shutdown mwifiex\n", __func__);
@@ -886,7 +927,10 @@ err_kmalloc:
                        wait_event_interruptible(adapter->init_wait_q,
                                                 adapter->init_wait_q_woken);
        }
-
+err_registerdev:
+       adapter->surprise_removed = true;
+       mwifiex_terminate_workqueue(adapter);
+err_kmalloc:
        mwifiex_free_adapter(adapter);
 
 err_init_sw:
@@ -919,6 +963,11 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem)
        if (!adapter)
                goto exit_remove;
 
+       /* We can no longer handle interrupts once we start doing the teardown
+        * below. */
+       if (adapter->if_ops.disable_int)
+               adapter->if_ops.disable_int(adapter);
+
        adapter->surprise_removed = true;
 
        /* Stop data */
index 3da73d36acdf5e9a5ebe30ce75333704d98a00c0..d2e5ccd891da2eebd7697bd1ac31989ccdc792ad 100644 (file)
@@ -204,11 +204,11 @@ struct mwifiex_ra_list_tbl {
        struct list_head list;
        struct sk_buff_head skb_head;
        u8 ra[ETH_ALEN];
-       u32 total_pkts_size;
        u32 is_11n_enabled;
        u16 max_amsdu;
-       u16 pkt_count;
+       u16 ba_pkt_count;
        u8 ba_packet_thr;
+       u16 total_pkt_count;
 };
 
 struct mwifiex_tid_tbl {
@@ -515,6 +515,7 @@ struct mwifiex_private {
        bool scan_aborting;
        u8 csa_chan;
        unsigned long csa_expire_time;
+       u8 del_list_idx;
 };
 
 enum mwifiex_ba_status {
@@ -601,6 +602,7 @@ struct mwifiex_if_ops {
        int (*register_dev) (struct mwifiex_adapter *);
        void (*unregister_dev) (struct mwifiex_adapter *);
        int (*enable_int) (struct mwifiex_adapter *);
+       void (*disable_int) (struct mwifiex_adapter *);
        int (*process_int_status) (struct mwifiex_adapter *);
        int (*host_to_card) (struct mwifiex_adapter *, u8, struct sk_buff *,
                             struct mwifiex_tx_param *);
@@ -747,6 +749,7 @@ struct mwifiex_adapter {
 
        atomic_t is_tx_received;
        atomic_t pending_bridged_pkts;
+       struct semaphore *card_sem;
 };
 
 int mwifiex_init_lock_list(struct mwifiex_adapter *adapter);
@@ -899,6 +902,8 @@ int mwifiex_cmd_append_vsie_tlv(struct mwifiex_private *priv, u16 vsie_mask,
 u32 mwifiex_get_active_data_rates(struct mwifiex_private *priv,
                                    u8 *rates);
 u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates);
+u32 mwifiex_get_rates_from_cfg80211(struct mwifiex_private *priv,
+                                   u8 *rates, u8 radio_type);
 u8 mwifiex_is_rate_auto(struct mwifiex_private *priv);
 extern u16 region_code_index[MWIFIEX_MAX_REGION_CODE];
 void mwifiex_save_curr_bcn(struct mwifiex_private *priv);
index 20c9c4c7b0b2eb64fa75bd4180fd85015d77b33e..52da8ee7599a041d7922180122c1744d19fe743e 100644 (file)
@@ -76,7 +76,7 @@ static bool mwifiex_pcie_ok_to_access_hw(struct mwifiex_adapter *adapter)
        return false;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*
  * Kernel needs to suspend all functions separately. Therefore all
  * registered functions must have drivers with suspend and resume
@@ -85,11 +85,12 @@ static bool mwifiex_pcie_ok_to_access_hw(struct mwifiex_adapter *adapter)
  * If already not suspended, this function allocates and sends a host
  * sleep activate request to the firmware and turns off the traffic.
  */
-static int mwifiex_pcie_suspend(struct pci_dev *pdev, pm_message_t state)
+static int mwifiex_pcie_suspend(struct device *dev)
 {
        struct mwifiex_adapter *adapter;
        struct pcie_service_card *card;
        int hs_actived;
+       struct pci_dev *pdev = to_pci_dev(dev);
 
        if (pdev) {
                card = (struct pcie_service_card *) pci_get_drvdata(pdev);
@@ -120,10 +121,11 @@ static int mwifiex_pcie_suspend(struct pci_dev *pdev, pm_message_t state)
  * If already not resumed, this function turns on the traffic and
  * sends a host sleep cancel request to the firmware.
  */
-static int mwifiex_pcie_resume(struct pci_dev *pdev)
+static int mwifiex_pcie_resume(struct device *dev)
 {
        struct mwifiex_adapter *adapter;
        struct pcie_service_card *card;
+       struct pci_dev *pdev = to_pci_dev(dev);
 
        if (pdev) {
                card = (struct pcie_service_card *) pci_get_drvdata(pdev);
@@ -211,9 +213,9 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev)
        wait_for_completion(&adapter->fw_load);
 
        if (user_rmmod) {
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
                if (adapter->is_suspended)
-                       mwifiex_pcie_resume(pdev);
+                       mwifiex_pcie_resume(&pdev->dev);
 #endif
 
                for (i = 0; i < adapter->priv_num; i++)
@@ -233,6 +235,14 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev)
        kfree(card);
 }
 
+static void mwifiex_pcie_shutdown(struct pci_dev *pdev)
+{
+       user_rmmod = 1;
+       mwifiex_pcie_remove(pdev);
+
+       return;
+}
+
 static DEFINE_PCI_DEVICE_TABLE(mwifiex_ids) = {
        {
                PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8766P,
@@ -249,17 +259,24 @@ static DEFINE_PCI_DEVICE_TABLE(mwifiex_ids) = {
 
 MODULE_DEVICE_TABLE(pci, mwifiex_ids);
 
+#ifdef CONFIG_PM_SLEEP
+/* Power Management Hooks */
+static SIMPLE_DEV_PM_OPS(mwifiex_pcie_pm_ops, mwifiex_pcie_suspend,
+                               mwifiex_pcie_resume);
+#endif
+
 /* PCI Device Driver */
 static struct pci_driver __refdata mwifiex_pcie = {
        .name     = "mwifiex_pcie",
        .id_table = mwifiex_ids,
        .probe    = mwifiex_pcie_probe,
        .remove   = mwifiex_pcie_remove,
-#ifdef CONFIG_PM
-       /* Power Management Hooks */
-       .suspend  = mwifiex_pcie_suspend,
-       .resume   = mwifiex_pcie_resume,
+#ifdef CONFIG_PM_SLEEP
+       .driver   = {
+               .pm = &mwifiex_pcie_pm_ops,
+       },
 #endif
+       .shutdown = mwifiex_pcie_shutdown,
 };
 
 /*
@@ -1925,7 +1942,7 @@ mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num)
                        ret = 0;
                        break;
                } else {
-                       mdelay(100);
+                       msleep(100);
                        ret = -1;
                }
        }
@@ -1937,12 +1954,10 @@ mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num)
                else if (!winner_status) {
                        dev_err(adapter->dev, "PCI-E is the winner\n");
                        adapter->winner = 1;
-                       ret = -1;
                } else {
                        dev_err(adapter->dev,
                                "PCI-E is not the winner <%#x,%d>, exit dnld\n",
                                ret, adapter->winner);
-                       ret = 0;
                }
        }
 
index c447d9bd1aa93746f5ad68b7c9205e1e85e20810..8cf7d50a7603121682c7f9a9684a64a978de85c9 100644 (file)
@@ -543,6 +543,37 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv,
        return chan_idx;
 }
 
+/* This function appends rate TLV to scan config command. */
+static int
+mwifiex_append_rate_tlv(struct mwifiex_private *priv,
+                       struct mwifiex_scan_cmd_config *scan_cfg_out,
+                       u8 radio)
+{
+       struct mwifiex_ie_types_rates_param_set *rates_tlv;
+       u8 rates[MWIFIEX_SUPPORTED_RATES], *tlv_pos;
+       u32 rates_size;
+
+       memset(rates, 0, sizeof(rates));
+
+       tlv_pos = (u8 *)scan_cfg_out->tlv_buf + scan_cfg_out->tlv_buf_len;
+
+       if (priv->scan_request)
+               rates_size = mwifiex_get_rates_from_cfg80211(priv, rates,
+                                                            radio);
+       else
+               rates_size = mwifiex_get_supported_rates(priv, rates);
+
+       dev_dbg(priv->adapter->dev, "info: SCAN_CMD: Rates size = %d\n",
+               rates_size);
+       rates_tlv = (struct mwifiex_ie_types_rates_param_set *)tlv_pos;
+       rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES);
+       rates_tlv->header.len = cpu_to_le16((u16) rates_size);
+       memcpy(rates_tlv->rates, rates, rates_size);
+       scan_cfg_out->tlv_buf_len += sizeof(rates_tlv->header) + rates_size;
+
+       return rates_size;
+}
+
 /*
  * This function constructs and sends multiple scan config commands to
  * the firmware.
@@ -564,9 +595,10 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv,
        struct mwifiex_chan_scan_param_set *tmp_chan_list;
        struct mwifiex_chan_scan_param_set *start_chan;
 
-       u32 tlv_idx;
+       u32 tlv_idx, rates_size;
        u32 total_scan_time;
        u32 done_early;
+       u8 radio_type;
 
        if (!scan_cfg_out || !chan_tlv_out || !scan_chan_list) {
                dev_dbg(priv->adapter->dev,
@@ -591,6 +623,7 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv,
 
                tlv_idx = 0;
                total_scan_time = 0;
+               radio_type = 0;
                chan_tlv_out->header.len = 0;
                start_chan = tmp_chan_list;
                done_early = false;
@@ -612,6 +645,7 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv,
                                continue;
                        }
 
+                       radio_type = tmp_chan_list->radio_type;
                        dev_dbg(priv->adapter->dev,
                                "info: Scan: Chan(%3d), Radio(%d),"
                                " Mode(%d, %d), Dur(%d)\n",
@@ -692,6 +726,9 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv,
                        break;
                }
 
+               rates_size = mwifiex_append_rate_tlv(priv, scan_cfg_out,
+                                                    radio_type);
+
                priv->adapter->scan_channels = start_chan;
 
                /* Send the scan command to the firmware with the specified
@@ -699,6 +736,14 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv,
                ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_SCAN,
                                             HostCmd_ACT_GEN_SET, 0,
                                             scan_cfg_out);
+
+               /* rate IE is updated per scan command but same starting
+                * pointer is used each time so that rate IE from earlier
+                * scan_cfg_out->buf is overwritten with new one.
+                */
+               scan_cfg_out->tlv_buf_len -=
+                           sizeof(struct mwifiex_ie_types_header) + rates_size;
+
                if (ret)
                        break;
        }
@@ -741,7 +786,6 @@ mwifiex_config_scan(struct mwifiex_private *priv,
        struct mwifiex_adapter *adapter = priv->adapter;
        struct mwifiex_ie_types_num_probes *num_probes_tlv;
        struct mwifiex_ie_types_wildcard_ssid_params *wildcard_ssid_tlv;
-       struct mwifiex_ie_types_rates_param_set *rates_tlv;
        u8 *tlv_pos;
        u32 num_probes;
        u32 ssid_len;
@@ -753,8 +797,6 @@ mwifiex_config_scan(struct mwifiex_private *priv,
        u8 radio_type;
        int i;
        u8 ssid_filter;
-       u8 rates[MWIFIEX_SUPPORTED_RATES];
-       u32 rates_size;
        struct mwifiex_ie_types_htcap *ht_cap;
 
        /* The tlv_buf_len is calculated for each scan command.  The TLVs added
@@ -889,19 +931,6 @@ mwifiex_config_scan(struct mwifiex_private *priv,
 
        }
 
-       /* Append rates tlv */
-       memset(rates, 0, sizeof(rates));
-
-       rates_size = mwifiex_get_supported_rates(priv, rates);
-
-       rates_tlv = (struct mwifiex_ie_types_rates_param_set *) tlv_pos;
-       rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES);
-       rates_tlv->header.len = cpu_to_le16((u16) rates_size);
-       memcpy(rates_tlv->rates, rates, rates_size);
-       tlv_pos += sizeof(rates_tlv->header) + rates_size;
-
-       dev_dbg(adapter->dev, "info: SCAN_CMD: Rates size = %d\n", rates_size);
-
        if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info) &&
            (priv->adapter->config_bands & BAND_GN ||
             priv->adapter->config_bands & BAND_AN)) {
index 5ee5ed02eccd56645c94f8b4972962130f5b305b..0e2070f72fed37457c078390a7b263a8d88a6e7e 100644 (file)
@@ -50,8 +50,6 @@ static struct mwifiex_if_ops sdio_ops;
 
 static struct semaphore add_remove_card_sem;
 
-static int mwifiex_sdio_resume(struct device *dev);
-
 /*
  * SDIO probe.
  *
@@ -111,6 +109,51 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
        return ret;
 }
 
+/*
+ * SDIO resume.
+ *
+ * Kernel needs to suspend all functions separately. Therefore all
+ * registered functions must have drivers with suspend and resume
+ * methods. Failing that the kernel simply removes the whole card.
+ *
+ * If already not resumed, this function turns on the traffic and
+ * sends a host sleep cancel request to the firmware.
+ */
+static int mwifiex_sdio_resume(struct device *dev)
+{
+       struct sdio_func *func = dev_to_sdio_func(dev);
+       struct sdio_mmc_card *card;
+       struct mwifiex_adapter *adapter;
+       mmc_pm_flag_t pm_flag = 0;
+
+       if (func) {
+               pm_flag = sdio_get_host_pm_caps(func);
+               card = sdio_get_drvdata(func);
+               if (!card || !card->adapter) {
+                       pr_err("resume: invalid card or adapter\n");
+                       return 0;
+               }
+       } else {
+               pr_err("resume: sdio_func is not specified\n");
+               return 0;
+       }
+
+       adapter = card->adapter;
+
+       if (!adapter->is_suspended) {
+               dev_warn(adapter->dev, "device already resumed\n");
+               return 0;
+       }
+
+       adapter->is_suspended = false;
+
+       /* Disable Host Sleep */
+       mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA),
+                         MWIFIEX_ASYNC_CMD);
+
+       return 0;
+}
+
 /*
  * SDIO remove.
  *
@@ -211,51 +254,6 @@ static int mwifiex_sdio_suspend(struct device *dev)
        return ret;
 }
 
-/*
- * SDIO resume.
- *
- * Kernel needs to suspend all functions separately. Therefore all
- * registered functions must have drivers with suspend and resume
- * methods. Failing that the kernel simply removes the whole card.
- *
- * If already not resumed, this function turns on the traffic and
- * sends a host sleep cancel request to the firmware.
- */
-static int mwifiex_sdio_resume(struct device *dev)
-{
-       struct sdio_func *func = dev_to_sdio_func(dev);
-       struct sdio_mmc_card *card;
-       struct mwifiex_adapter *adapter;
-       mmc_pm_flag_t pm_flag = 0;
-
-       if (func) {
-               pm_flag = sdio_get_host_pm_caps(func);
-               card = sdio_get_drvdata(func);
-               if (!card || !card->adapter) {
-                       pr_err("resume: invalid card or adapter\n");
-                       return 0;
-               }
-       } else {
-               pr_err("resume: sdio_func is not specified\n");
-               return 0;
-       }
-
-       adapter = card->adapter;
-
-       if (!adapter->is_suspended) {
-               dev_warn(adapter->dev, "device already resumed\n");
-               return 0;
-       }
-
-       adapter->is_suspended = false;
-
-       /* Disable Host Sleep */
-       mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA),
-                         MWIFIEX_ASYNC_CMD);
-
-       return 0;
-}
-
 /* Device ID for SD8786 */
 #define SDIO_DEVICE_ID_MARVELL_8786   (0x9116)
 /* Device ID for SD8787 */
@@ -296,6 +294,15 @@ static struct sdio_driver mwifiex_sdio = {
        }
 };
 
+/* Write data into SDIO card register. Caller claims SDIO device. */
+static int
+mwifiex_write_reg_locked(struct sdio_func *func, u32 reg, u8 data)
+{
+       int ret = -1;
+       sdio_writeb(func, data, reg, &ret);
+       return ret;
+}
+
 /*
  * This function writes data into SDIO card register.
  */
@@ -303,10 +310,10 @@ static int
 mwifiex_write_reg(struct mwifiex_adapter *adapter, u32 reg, u8 data)
 {
        struct sdio_mmc_card *card = adapter->card;
-       int ret = -1;
+       int ret;
 
        sdio_claim_host(card->func);
-       sdio_writeb(card->func, data, reg, &ret);
+       ret = mwifiex_write_reg_locked(card->func, reg, data);
        sdio_release_host(card->func);
 
        return ret;
@@ -685,23 +692,74 @@ mwifiex_sdio_read_fw_status(struct mwifiex_adapter *adapter, u16 *dat)
  * The host interrupt mask is read, the disable bit is reset and
  * written back to the card host interrupt mask register.
  */
-static int mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter)
+static void mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter)
 {
-       u8 host_int_mask, host_int_disable = HOST_INT_DISABLE;
+       struct sdio_mmc_card *card = adapter->card;
+       struct sdio_func *func = card->func;
 
-       /* Read back the host_int_mask register */
-       if (mwifiex_read_reg(adapter, HOST_INT_MASK_REG, &host_int_mask))
-               return -1;
+       sdio_claim_host(func);
+       mwifiex_write_reg_locked(func, HOST_INT_MASK_REG, 0);
+       sdio_release_irq(func);
+       sdio_release_host(func);
+}
 
-       /* Update with the mask and write back to the register */
-       host_int_mask &= ~host_int_disable;
+/*
+ * This function reads the interrupt status from card.
+ */
+static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
+{
+       struct sdio_mmc_card *card = adapter->card;
+       u8 sdio_ireg;
+       unsigned long flags;
 
-       if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, host_int_mask)) {
-               dev_err(adapter->dev, "disable host interrupt failed\n");
-               return -1;
+       if (mwifiex_read_data_sync(adapter, card->mp_regs,
+                                  card->reg->max_mp_regs,
+                                  REG_PORT | MWIFIEX_SDIO_BYTE_MODE_MASK, 0)) {
+               dev_err(adapter->dev, "read mp_regs failed\n");
+               return;
        }
 
-       return 0;
+       sdio_ireg = card->mp_regs[HOST_INTSTATUS_REG];
+       if (sdio_ireg) {
+               /*
+                * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
+                * For SDIO new mode CMD port interrupts
+                *      DN_LD_CMD_PORT_HOST_INT_STATUS and/or
+                *      UP_LD_CMD_PORT_HOST_INT_STATUS
+                * Clear the interrupt status register
+                */
+               dev_dbg(adapter->dev, "int: sdio_ireg = %#x\n", sdio_ireg);
+               spin_lock_irqsave(&adapter->int_lock, flags);
+               adapter->int_status |= sdio_ireg;
+               spin_unlock_irqrestore(&adapter->int_lock, flags);
+       }
+}
+
+/*
+ * SDIO interrupt handler.
+ *
+ * This function reads the interrupt status from firmware and handles
+ * the interrupt in current thread (ksdioirqd) right away.
+ */
+static void
+mwifiex_sdio_interrupt(struct sdio_func *func)
+{
+       struct mwifiex_adapter *adapter;
+       struct sdio_mmc_card *card;
+
+       card = sdio_get_drvdata(func);
+       if (!card || !card->adapter) {
+               pr_debug("int: func=%p card=%p adapter=%p\n",
+                        func, card, card ? card->adapter : NULL);
+               return;
+       }
+       adapter = card->adapter;
+
+       if (!adapter->pps_uapsd_mode && adapter->ps_state == PS_STATE_SLEEP)
+               adapter->ps_state = PS_STATE_AWAKE;
+
+       mwifiex_interrupt_status(adapter);
+       mwifiex_main_process(adapter);
 }
 
 /*
@@ -713,14 +771,29 @@ static int mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter)
 static int mwifiex_sdio_enable_host_int(struct mwifiex_adapter *adapter)
 {
        struct sdio_mmc_card *card = adapter->card;
+       struct sdio_func *func = card->func;
+       int ret;
+
+       sdio_claim_host(func);
+
+       /* Request the SDIO IRQ */
+       ret = sdio_claim_irq(func, mwifiex_sdio_interrupt);
+       if (ret) {
+               dev_err(adapter->dev, "claim irq failed: ret=%d\n", ret);
+               goto out;
+       }
 
        /* Simply write the mask to the register */
-       if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG,
-                             card->reg->host_int_enable)) {
+       ret = mwifiex_write_reg_locked(func, HOST_INT_MASK_REG,
+                                      card->reg->host_int_enable);
+       if (ret) {
                dev_err(adapter->dev, "enable host interrupt failed\n");
-               return -1;
+               sdio_release_irq(func);
        }
-       return 0;
+
+out:
+       sdio_release_host(func);
+       return ret;
 }
 
 /*
@@ -927,7 +1000,7 @@ static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter,
                        ret = 0;
                        break;
                } else {
-                       mdelay(100);
+                       msleep(100);
                        ret = -1;
                }
        }
@@ -945,68 +1018,6 @@ static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter,
        return ret;
 }
 
-/*
- * This function reads the interrupt status from card.
- */
-static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
-{
-       struct sdio_mmc_card *card = adapter->card;
-       u8 sdio_ireg;
-       unsigned long flags;
-
-       if (mwifiex_read_data_sync(adapter, card->mp_regs,
-                                  card->reg->max_mp_regs,
-                                  REG_PORT | MWIFIEX_SDIO_BYTE_MODE_MASK, 0)) {
-               dev_err(adapter->dev, "read mp_regs failed\n");
-               return;
-       }
-
-       sdio_ireg = card->mp_regs[HOST_INTSTATUS_REG];
-       if (sdio_ireg) {
-               /*
-                * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
-                * For SDIO new mode CMD port interrupts
-                *      DN_LD_CMD_PORT_HOST_INT_STATUS and/or
-                *      UP_LD_CMD_PORT_HOST_INT_STATUS
-                * Clear the interrupt status register
-                */
-               dev_dbg(adapter->dev, "int: sdio_ireg = %#x\n", sdio_ireg);
-               spin_lock_irqsave(&adapter->int_lock, flags);
-               adapter->int_status |= sdio_ireg;
-               spin_unlock_irqrestore(&adapter->int_lock, flags);
-       }
-}
-
-/*
- * SDIO interrupt handler.
- *
- * This function reads the interrupt status from firmware and handles
- * the interrupt in current thread (ksdioirqd) right away.
- */
-static void
-mwifiex_sdio_interrupt(struct sdio_func *func)
-{
-       struct mwifiex_adapter *adapter;
-       struct sdio_mmc_card *card;
-
-       card = sdio_get_drvdata(func);
-       if (!card || !card->adapter) {
-               pr_debug("int: func=%p card=%p adapter=%p\n",
-                        func, card, card ? card->adapter : NULL);
-               return;
-       }
-       adapter = card->adapter;
-
-       if (adapter->surprise_removed)
-               return;
-
-       if (!adapter->pps_uapsd_mode && adapter->ps_state == PS_STATE_SLEEP)
-               adapter->ps_state = PS_STATE_AWAKE;
-
-       mwifiex_interrupt_status(adapter);
-       mwifiex_main_process(adapter);
-}
-
 /*
  * This function decodes a received packet.
  *
@@ -1625,8 +1636,8 @@ static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter,
        /* Allocate buffer and copy payload */
        blk_size = MWIFIEX_SDIO_BLOCK_SIZE;
        buf_block_len = (pkt_len + blk_size - 1) / blk_size;
-       *(u16 *) &payload[0] = (u16) pkt_len;
-       *(u16 *) &payload[2] = type;
+       *(__le16 *)&payload[0] = cpu_to_le16((u16)pkt_len);
+       *(__le16 *)&payload[2] = cpu_to_le16(type);
 
        /*
         * This is SDIO specific header
@@ -1728,9 +1739,7 @@ mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
        struct sdio_mmc_card *card = adapter->card;
 
        if (adapter->card) {
-               /* Release the SDIO IRQ */
                sdio_claim_host(card->func);
-               sdio_release_irq(card->func);
                sdio_disable_func(card->func);
                sdio_release_host(card->func);
                sdio_set_drvdata(card->func, NULL);
@@ -1744,7 +1753,7 @@ mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
  */
 static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
 {
-       int ret = 0;
+       int ret;
        struct sdio_mmc_card *card = adapter->card;
        struct sdio_func *func = card->func;
 
@@ -1753,22 +1762,14 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
 
        sdio_claim_host(func);
 
-       /* Request the SDIO IRQ */
-       ret = sdio_claim_irq(func, mwifiex_sdio_interrupt);
-       if (ret) {
-               pr_err("claim irq failed: ret=%d\n", ret);
-               goto disable_func;
-       }
-
        /* Set block size */
        ret = sdio_set_block_size(card->func, MWIFIEX_SDIO_BLOCK_SIZE);
+       sdio_release_host(func);
        if (ret) {
                pr_err("cannot set SDIO block size\n");
-               ret = -1;
-               goto release_irq;
+               return ret;
        }
 
-       sdio_release_host(func);
        sdio_set_drvdata(func, card);
 
        adapter->dev = &func->dev;
@@ -1776,15 +1777,6 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
        strcpy(adapter->fw_name, card->firmware);
 
        return 0;
-
-release_irq:
-       sdio_release_irq(func);
-disable_func:
-       sdio_disable_func(func);
-       sdio_release_host(func);
-       adapter->card = NULL;
-
-       return -1;
 }
 
 /*
@@ -1813,9 +1805,6 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter)
         */
        mwifiex_read_reg(adapter, HOST_INTSTATUS_REG, &sdio_ireg);
 
-       /* Disable host interrupt mask register for SDIO */
-       mwifiex_sdio_disable_host_int(adapter);
-
        /* Get SDIO ioport */
        mwifiex_init_sdio_ioport(adapter);
 
@@ -1957,6 +1946,7 @@ static struct mwifiex_if_ops sdio_ops = {
        .register_dev = mwifiex_register_dev,
        .unregister_dev = mwifiex_unregister_dev,
        .enable_int = mwifiex_sdio_enable_host_int,
+       .disable_int = mwifiex_sdio_disable_host_int,
        .process_int_status = mwifiex_process_int_status,
        .host_to_card = mwifiex_sdio_host_to_card,
        .wakeup = mwifiex_pm_wakeup_card,
index 6d51dfdd8251a515c3f6a17e94029b5c10f6672a..532ae0ac4dfb3e40bb12592db32ec94e702a4c2b 100644 (file)
@@ -92,9 +92,6 @@
 /* Host Control Registers : Download host interrupt mask */
 #define DN_LD_HOST_INT_MASK            (0x2U)
 
-/* Disable Host interrupt mask */
-#define        HOST_INT_DISABLE                0xff
-
 /* Host Control Registers : Host interrupt status */
 #define HOST_INTSTATUS_REG             0x03
 /* Host Control Registers : Upload host interrupt status */
index 8ece48580642b28e92ecf5d28629d8c2585dec05..9b75ed8563b6b1fb8ffee13cb94ab8512fcf9c3d 100644 (file)
@@ -707,8 +707,9 @@ mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv,
                if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP) {
                        tlv_mac = (void *)((u8 *)&key_material->key_param_set +
                                           key_param_len);
-                       tlv_mac->tlv.type = cpu_to_le16(TLV_TYPE_STA_MAC_ADDR);
-                       tlv_mac->tlv.len = cpu_to_le16(ETH_ALEN);
+                       tlv_mac->header.type =
+                                       cpu_to_le16(TLV_TYPE_STA_MAC_ADDR);
+                       tlv_mac->header.len = cpu_to_le16(ETH_ALEN);
                        memcpy(tlv_mac->mac_addr, enc_key->mac_addr, ETH_ALEN);
                        cmd_size = key_param_len + S_DS_GEN +
                                   sizeof(key_material->action) +
index ea265ec0e522333837a13ab43a16d74ccaae7550..8b057524b252e535307644ddaa98e12df75a35cd 100644 (file)
@@ -201,6 +201,11 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
 
        case EVENT_DEAUTHENTICATED:
                dev_dbg(adapter->dev, "event: Deauthenticated\n");
+               if (priv->wps.session_enable) {
+                       dev_dbg(adapter->dev,
+                               "info: receive deauth event in wps session\n");
+                       break;
+               }
                adapter->dbg.num_event_deauth++;
                if (priv->media_connected) {
                        reason_code =
@@ -211,6 +216,11 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
 
        case EVENT_DISASSOCIATED:
                dev_dbg(adapter->dev, "event: Disassociated\n");
+               if (priv->wps.session_enable) {
+                       dev_dbg(adapter->dev,
+                               "info: receive disassoc event in wps session\n");
+                       break;
+               }
                adapter->dbg.num_event_disassoc++;
                if (priv->media_connected) {
                        reason_code =
index 206c3e03807235425ee3c0ad12676cc7c187cad7..f084412eee0b7cdeced4f2b21b4140b01d1b141e 100644 (file)
@@ -257,10 +257,10 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
                        goto done;
        }
 
-       if (priv->bss_mode == NL80211_IFTYPE_STATION) {
+       if (priv->bss_mode == NL80211_IFTYPE_STATION ||
+           priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) {
                u8 config_bands;
 
-               /* Infra mode */
                ret = mwifiex_deauthenticate(priv, NULL);
                if (ret)
                        goto done;
@@ -797,15 +797,16 @@ static int mwifiex_set_wps_ie(struct mwifiex_private *priv,
                               u8 *ie_data_ptr, u16 ie_len)
 {
        if (ie_len) {
-               priv->wps_ie = kzalloc(MWIFIEX_MAX_VSIE_LEN, GFP_KERNEL);
-               if (!priv->wps_ie)
-                       return -ENOMEM;
-               if (ie_len > sizeof(priv->wps_ie)) {
+               if (ie_len > MWIFIEX_MAX_VSIE_LEN) {
                        dev_dbg(priv->adapter->dev,
                                "info: failed to copy WPS IE, too big\n");
-                       kfree(priv->wps_ie);
                        return -1;
                }
+
+               priv->wps_ie = kzalloc(MWIFIEX_MAX_VSIE_LEN, GFP_KERNEL);
+               if (!priv->wps_ie)
+                       return -ENOMEM;
+
                memcpy(priv->wps_ie, ie_data_ptr, ie_len);
                priv->wps_ie_len = ie_len;
                dev_dbg(priv->adapter->dev, "cmd: Set wps_ie_len=%d IE=%#x\n",
index 2de882dead0f879dee34831e0c61adc470d9dd70..64424c81b44f5bf55601e75a8a4d47e51b6bc9b9 100644 (file)
@@ -293,9 +293,9 @@ mwifiex_uap_bss_wpa(u8 **tlv_buf, void *cmd_buf, u16 *param_size)
        u8 *tlv = *tlv_buf;
 
        tlv_akmp = (struct host_cmd_tlv_akmp *)tlv;
-       tlv_akmp->tlv.type = cpu_to_le16(TLV_TYPE_UAP_AKMP);
-       tlv_akmp->tlv.len = cpu_to_le16(sizeof(struct host_cmd_tlv_akmp) -
-                                       sizeof(struct host_cmd_tlv));
+       tlv_akmp->header.type = cpu_to_le16(TLV_TYPE_UAP_AKMP);
+       tlv_akmp->header.len = cpu_to_le16(sizeof(struct host_cmd_tlv_akmp) -
+                                       sizeof(struct mwifiex_ie_types_header));
        tlv_akmp->key_mgmt_operation = cpu_to_le16(bss_cfg->key_mgmt_operation);
        tlv_akmp->key_mgmt = cpu_to_le16(bss_cfg->key_mgmt);
        cmd_size += sizeof(struct host_cmd_tlv_akmp);
@@ -303,10 +303,10 @@ mwifiex_uap_bss_wpa(u8 **tlv_buf, void *cmd_buf, u16 *param_size)
 
        if (bss_cfg->wpa_cfg.pairwise_cipher_wpa & VALID_CIPHER_BITMAP) {
                pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv;
-               pwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_PWK_CIPHER);
-               pwk_cipher->tlv.len =
+               pwk_cipher->header.type = cpu_to_le16(TLV_TYPE_PWK_CIPHER);
+               pwk_cipher->header.len =
                        cpu_to_le16(sizeof(struct host_cmd_tlv_pwk_cipher) -
-                                   sizeof(struct host_cmd_tlv));
+                                   sizeof(struct mwifiex_ie_types_header));
                pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA);
                pwk_cipher->cipher = bss_cfg->wpa_cfg.pairwise_cipher_wpa;
                cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher);
@@ -315,10 +315,10 @@ mwifiex_uap_bss_wpa(u8 **tlv_buf, void *cmd_buf, u16 *param_size)
 
        if (bss_cfg->wpa_cfg.pairwise_cipher_wpa2 & VALID_CIPHER_BITMAP) {
                pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv;
-               pwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_PWK_CIPHER);
-               pwk_cipher->tlv.len =
+               pwk_cipher->header.type = cpu_to_le16(TLV_TYPE_PWK_CIPHER);
+               pwk_cipher->header.len =
                        cpu_to_le16(sizeof(struct host_cmd_tlv_pwk_cipher) -
-                                   sizeof(struct host_cmd_tlv));
+                                   sizeof(struct mwifiex_ie_types_header));
                pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA2);
                pwk_cipher->cipher = bss_cfg->wpa_cfg.pairwise_cipher_wpa2;
                cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher);
@@ -327,10 +327,10 @@ mwifiex_uap_bss_wpa(u8 **tlv_buf, void *cmd_buf, u16 *param_size)
 
        if (bss_cfg->wpa_cfg.group_cipher & VALID_CIPHER_BITMAP) {
                gwk_cipher = (struct host_cmd_tlv_gwk_cipher *)tlv;
-               gwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_GWK_CIPHER);
-               gwk_cipher->tlv.len =
+               gwk_cipher->header.type = cpu_to_le16(TLV_TYPE_GWK_CIPHER);
+               gwk_cipher->header.len =
                        cpu_to_le16(sizeof(struct host_cmd_tlv_gwk_cipher) -
-                                   sizeof(struct host_cmd_tlv));
+                                   sizeof(struct mwifiex_ie_types_header));
                gwk_cipher->cipher = bss_cfg->wpa_cfg.group_cipher;
                cmd_size += sizeof(struct host_cmd_tlv_gwk_cipher);
                tlv += sizeof(struct host_cmd_tlv_gwk_cipher);
@@ -338,13 +338,15 @@ mwifiex_uap_bss_wpa(u8 **tlv_buf, void *cmd_buf, u16 *param_size)
 
        if (bss_cfg->wpa_cfg.length) {
                passphrase = (struct host_cmd_tlv_passphrase *)tlv;
-               passphrase->tlv.type = cpu_to_le16(TLV_TYPE_UAP_WPA_PASSPHRASE);
-               passphrase->tlv.len = cpu_to_le16(bss_cfg->wpa_cfg.length);
+               passphrase->header.type =
+                               cpu_to_le16(TLV_TYPE_UAP_WPA_PASSPHRASE);
+               passphrase->header.len = cpu_to_le16(bss_cfg->wpa_cfg.length);
                memcpy(passphrase->passphrase, bss_cfg->wpa_cfg.passphrase,
                       bss_cfg->wpa_cfg.length);
-               cmd_size += sizeof(struct host_cmd_tlv) +
+               cmd_size += sizeof(struct mwifiex_ie_types_header) +
                            bss_cfg->wpa_cfg.length;
-               tlv += sizeof(struct host_cmd_tlv) + bss_cfg->wpa_cfg.length;
+               tlv += sizeof(struct mwifiex_ie_types_header) +
+                               bss_cfg->wpa_cfg.length;
        }
 
        *param_size = cmd_size;
@@ -403,16 +405,17 @@ mwifiex_uap_bss_wep(u8 **tlv_buf, void *cmd_buf, u16 *param_size)
                    (bss_cfg->wep_cfg[i].length == WLAN_KEY_LEN_WEP40 ||
                     bss_cfg->wep_cfg[i].length == WLAN_KEY_LEN_WEP104)) {
                        wep_key = (struct host_cmd_tlv_wep_key *)tlv;
-                       wep_key->tlv.type = cpu_to_le16(TLV_TYPE_UAP_WEP_KEY);
-                       wep_key->tlv.len =
+                       wep_key->header.type =
+                               cpu_to_le16(TLV_TYPE_UAP_WEP_KEY);
+                       wep_key->header.len =
                                cpu_to_le16(bss_cfg->wep_cfg[i].length + 2);
                        wep_key->key_index = bss_cfg->wep_cfg[i].key_index;
                        wep_key->is_default = bss_cfg->wep_cfg[i].is_default;
                        memcpy(wep_key->key, bss_cfg->wep_cfg[i].key,
                               bss_cfg->wep_cfg[i].length);
-                       cmd_size += sizeof(struct host_cmd_tlv) + 2 +
+                       cmd_size += sizeof(struct mwifiex_ie_types_header) + 2 +
                                    bss_cfg->wep_cfg[i].length;
-                       tlv += sizeof(struct host_cmd_tlv) + 2 +
+                       tlv += sizeof(struct mwifiex_ie_types_header) + 2 +
                                    bss_cfg->wep_cfg[i].length;
                }
        }
@@ -449,16 +452,17 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
 
        if (bss_cfg->ssid.ssid_len) {
                ssid = (struct host_cmd_tlv_ssid *)tlv;
-               ssid->tlv.type = cpu_to_le16(TLV_TYPE_UAP_SSID);
-               ssid->tlv.len = cpu_to_le16((u16)bss_cfg->ssid.ssid_len);
+               ssid->header.type = cpu_to_le16(TLV_TYPE_UAP_SSID);
+               ssid->header.len = cpu_to_le16((u16)bss_cfg->ssid.ssid_len);
                memcpy(ssid->ssid, bss_cfg->ssid.ssid, bss_cfg->ssid.ssid_len);
-               cmd_size += sizeof(struct host_cmd_tlv) +
+               cmd_size += sizeof(struct mwifiex_ie_types_header) +
                            bss_cfg->ssid.ssid_len;
-               tlv += sizeof(struct host_cmd_tlv) + bss_cfg->ssid.ssid_len;
+               tlv += sizeof(struct mwifiex_ie_types_header) +
+                               bss_cfg->ssid.ssid_len;
 
                bcast_ssid = (struct host_cmd_tlv_bcast_ssid *)tlv;
-               bcast_ssid->tlv.type = cpu_to_le16(TLV_TYPE_UAP_BCAST_SSID);
-               bcast_ssid->tlv.len =
+               bcast_ssid->header.type = cpu_to_le16(TLV_TYPE_UAP_BCAST_SSID);
+               bcast_ssid->header.len =
                                cpu_to_le16(sizeof(bcast_ssid->bcast_ctl));
                bcast_ssid->bcast_ctl = bss_cfg->bcast_ssid_ctl;
                cmd_size += sizeof(struct host_cmd_tlv_bcast_ssid);
@@ -466,13 +470,13 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
        }
        if (bss_cfg->rates[0]) {
                tlv_rates = (struct host_cmd_tlv_rates *)tlv;
-               tlv_rates->tlv.type = cpu_to_le16(TLV_TYPE_UAP_RATES);
+               tlv_rates->header.type = cpu_to_le16(TLV_TYPE_UAP_RATES);
 
                for (i = 0; i < MWIFIEX_SUPPORTED_RATES && bss_cfg->rates[i];
                     i++)
                        tlv_rates->rates[i] = bss_cfg->rates[i];
 
-               tlv_rates->tlv.len = cpu_to_le16(i);
+               tlv_rates->header.len = cpu_to_le16(i);
                cmd_size += sizeof(struct host_cmd_tlv_rates) + i;
                tlv += sizeof(struct host_cmd_tlv_rates) + i;
        }
@@ -482,10 +486,10 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
            (bss_cfg->band_cfg == BAND_CONFIG_A &&
             bss_cfg->channel <= MAX_CHANNEL_BAND_A))) {
                chan_band = (struct host_cmd_tlv_channel_band *)tlv;
-               chan_band->tlv.type = cpu_to_le16(TLV_TYPE_CHANNELBANDLIST);
-               chan_band->tlv.len =
+               chan_band->header.type = cpu_to_le16(TLV_TYPE_CHANNELBANDLIST);
+               chan_band->header.len =
                        cpu_to_le16(sizeof(struct host_cmd_tlv_channel_band) -
-                                   sizeof(struct host_cmd_tlv));
+                                   sizeof(struct mwifiex_ie_types_header));
                chan_band->band_config = bss_cfg->band_cfg;
                chan_band->channel = bss_cfg->channel;
                cmd_size += sizeof(struct host_cmd_tlv_channel_band);
@@ -494,11 +498,11 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
        if (bss_cfg->beacon_period >= MIN_BEACON_PERIOD &&
            bss_cfg->beacon_period <= MAX_BEACON_PERIOD) {
                beacon_period = (struct host_cmd_tlv_beacon_period *)tlv;
-               beacon_period->tlv.type =
+               beacon_period->header.type =
                                        cpu_to_le16(TLV_TYPE_UAP_BEACON_PERIOD);
-               beacon_period->tlv.len =
+               beacon_period->header.len =
                        cpu_to_le16(sizeof(struct host_cmd_tlv_beacon_period) -
-                                   sizeof(struct host_cmd_tlv));
+                                   sizeof(struct mwifiex_ie_types_header));
                beacon_period->period = cpu_to_le16(bss_cfg->beacon_period);
                cmd_size += sizeof(struct host_cmd_tlv_beacon_period);
                tlv += sizeof(struct host_cmd_tlv_beacon_period);
@@ -506,21 +510,22 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
        if (bss_cfg->dtim_period >= MIN_DTIM_PERIOD &&
            bss_cfg->dtim_period <= MAX_DTIM_PERIOD) {
                dtim_period = (struct host_cmd_tlv_dtim_period *)tlv;
-               dtim_period->tlv.type = cpu_to_le16(TLV_TYPE_UAP_DTIM_PERIOD);
-               dtim_period->tlv.len =
+               dtim_period->header.type =
+                       cpu_to_le16(TLV_TYPE_UAP_DTIM_PERIOD);
+               dtim_period->header.len =
                        cpu_to_le16(sizeof(struct host_cmd_tlv_dtim_period) -
-                                   sizeof(struct host_cmd_tlv));
+                                   sizeof(struct mwifiex_ie_types_header));
                dtim_period->period = bss_cfg->dtim_period;
                cmd_size += sizeof(struct host_cmd_tlv_dtim_period);
                tlv += sizeof(struct host_cmd_tlv_dtim_period);
        }
        if (bss_cfg->rts_threshold <= MWIFIEX_RTS_MAX_VALUE) {
                rts_threshold = (struct host_cmd_tlv_rts_threshold *)tlv;
-               rts_threshold->tlv.type =
+               rts_threshold->header.type =
                                        cpu_to_le16(TLV_TYPE_UAP_RTS_THRESHOLD);
-               rts_threshold->tlv.len =
+               rts_threshold->header.len =
                        cpu_to_le16(sizeof(struct host_cmd_tlv_rts_threshold) -
-                                   sizeof(struct host_cmd_tlv));
+                                   sizeof(struct mwifiex_ie_types_header));
                rts_threshold->rts_thr = cpu_to_le16(bss_cfg->rts_threshold);
                cmd_size += sizeof(struct host_cmd_tlv_frag_threshold);
                tlv += sizeof(struct host_cmd_tlv_frag_threshold);
@@ -528,21 +533,22 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
        if ((bss_cfg->frag_threshold >= MWIFIEX_FRAG_MIN_VALUE) &&
            (bss_cfg->frag_threshold <= MWIFIEX_FRAG_MAX_VALUE)) {
                frag_threshold = (struct host_cmd_tlv_frag_threshold *)tlv;
-               frag_threshold->tlv.type =
+               frag_threshold->header.type =
                                cpu_to_le16(TLV_TYPE_UAP_FRAG_THRESHOLD);
-               frag_threshold->tlv.len =
+               frag_threshold->header.len =
                        cpu_to_le16(sizeof(struct host_cmd_tlv_frag_threshold) -
-                                   sizeof(struct host_cmd_tlv));
+                                   sizeof(struct mwifiex_ie_types_header));
                frag_threshold->frag_thr = cpu_to_le16(bss_cfg->frag_threshold);
                cmd_size += sizeof(struct host_cmd_tlv_frag_threshold);
                tlv += sizeof(struct host_cmd_tlv_frag_threshold);
        }
        if (bss_cfg->retry_limit <= MWIFIEX_RETRY_LIMIT) {
                retry_limit = (struct host_cmd_tlv_retry_limit *)tlv;
-               retry_limit->tlv.type = cpu_to_le16(TLV_TYPE_UAP_RETRY_LIMIT);
-               retry_limit->tlv.len =
+               retry_limit->header.type =
+                       cpu_to_le16(TLV_TYPE_UAP_RETRY_LIMIT);
+               retry_limit->header.len =
                        cpu_to_le16(sizeof(struct host_cmd_tlv_retry_limit) -
-                                   sizeof(struct host_cmd_tlv));
+                                   sizeof(struct mwifiex_ie_types_header));
                retry_limit->limit = (u8)bss_cfg->retry_limit;
                cmd_size += sizeof(struct host_cmd_tlv_retry_limit);
                tlv += sizeof(struct host_cmd_tlv_retry_limit);
@@ -557,21 +563,21 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
        if ((bss_cfg->auth_mode <= WLAN_AUTH_SHARED_KEY) ||
            (bss_cfg->auth_mode == MWIFIEX_AUTH_MODE_AUTO)) {
                auth_type = (struct host_cmd_tlv_auth_type *)tlv;
-               auth_type->tlv.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
-               auth_type->tlv.len =
+               auth_type->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
+               auth_type->header.len =
                        cpu_to_le16(sizeof(struct host_cmd_tlv_auth_type) -
-                       sizeof(struct host_cmd_tlv));
+                       sizeof(struct mwifiex_ie_types_header));
                auth_type->auth_type = (u8)bss_cfg->auth_mode;
                cmd_size += sizeof(struct host_cmd_tlv_auth_type);
                tlv += sizeof(struct host_cmd_tlv_auth_type);
        }
        if (bss_cfg->protocol) {
                encrypt_protocol = (struct host_cmd_tlv_encrypt_protocol *)tlv;
-               encrypt_protocol->tlv.type =
+               encrypt_protocol->header.type =
                        cpu_to_le16(TLV_TYPE_UAP_ENCRY_PROTOCOL);
-               encrypt_protocol->tlv.len =
+               encrypt_protocol->header.len =
                        cpu_to_le16(sizeof(struct host_cmd_tlv_encrypt_protocol)
-                       - sizeof(struct host_cmd_tlv));
+                       - sizeof(struct mwifiex_ie_types_header));
                encrypt_protocol->proto = cpu_to_le16(bss_cfg->protocol);
                cmd_size += sizeof(struct host_cmd_tlv_encrypt_protocol);
                tlv += sizeof(struct host_cmd_tlv_encrypt_protocol);
@@ -608,9 +614,9 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
 
        if (bss_cfg->sta_ao_timer) {
                ao_timer = (struct host_cmd_tlv_ageout_timer *)tlv;
-               ao_timer->tlv.type = cpu_to_le16(TLV_TYPE_UAP_AO_TIMER);
-               ao_timer->tlv.len = cpu_to_le16(sizeof(*ao_timer) -
-                                               sizeof(struct host_cmd_tlv));
+               ao_timer->header.type = cpu_to_le16(TLV_TYPE_UAP_AO_TIMER);
+               ao_timer->header.len = cpu_to_le16(sizeof(*ao_timer) -
+                                       sizeof(struct mwifiex_ie_types_header));
                ao_timer->sta_ao_timer = cpu_to_le32(bss_cfg->sta_ao_timer);
                cmd_size += sizeof(*ao_timer);
                tlv += sizeof(*ao_timer);
@@ -618,9 +624,10 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
 
        if (bss_cfg->ps_sta_ao_timer) {
                ps_ao_timer = (struct host_cmd_tlv_ageout_timer *)tlv;
-               ps_ao_timer->tlv.type = cpu_to_le16(TLV_TYPE_UAP_PS_AO_TIMER);
-               ps_ao_timer->tlv.len = cpu_to_le16(sizeof(*ps_ao_timer) -
-                                                  sizeof(struct host_cmd_tlv));
+               ps_ao_timer->header.type =
+                               cpu_to_le16(TLV_TYPE_UAP_PS_AO_TIMER);
+               ps_ao_timer->header.len = cpu_to_le16(sizeof(*ps_ao_timer) -
+                               sizeof(struct mwifiex_ie_types_header));
                ps_ao_timer->sta_ao_timer =
                                        cpu_to_le32(bss_cfg->ps_sta_ao_timer);
                cmd_size += sizeof(*ps_ao_timer);
@@ -636,16 +643,17 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
 static int mwifiex_uap_custom_ie_prepare(u8 *tlv, void *cmd_buf, u16 *ie_size)
 {
        struct mwifiex_ie_list *ap_ie = cmd_buf;
-       struct host_cmd_tlv *tlv_ie = (struct host_cmd_tlv *)tlv;
+       struct mwifiex_ie_types_header *tlv_ie = (void *)tlv;
 
        if (!ap_ie || !ap_ie->len || !ap_ie->ie_list)
                return -1;
 
-       *ie_size += le16_to_cpu(ap_ie->len) + sizeof(struct host_cmd_tlv);
+       *ie_size += le16_to_cpu(ap_ie->len) +
+                       sizeof(struct mwifiex_ie_types_header);
 
        tlv_ie->type = cpu_to_le16(TLV_TYPE_MGMT_IE);
        tlv_ie->len = ap_ie->len;
-       tlv += sizeof(struct host_cmd_tlv);
+       tlv += sizeof(struct mwifiex_ie_types_header);
 
        memcpy(tlv, ap_ie->ie_list, le16_to_cpu(ap_ie->len));
 
index a018e42d117eb49b9b89716e70910f299de2ef68..1cfe5a738c479e53e3dd5ba21f460096d2a16e53 100644 (file)
 #include "11n_aggr.h"
 #include "11n_rxreorder.h"
 
+/* This function checks if particular RA list has packets more than low bridge
+ * packet threshold and then deletes packet from this RA list.
+ * Function deletes packets from such RA list and returns true. If no such list
+ * is found, false is returned.
+ */
+static bool
+mwifiex_uap_del_tx_pkts_in_ralist(struct mwifiex_private *priv,
+                                 struct list_head *ra_list_head)
+{
+       struct mwifiex_ra_list_tbl *ra_list;
+       struct sk_buff *skb, *tmp;
+       bool pkt_deleted = false;
+       struct mwifiex_txinfo *tx_info;
+       struct mwifiex_adapter *adapter = priv->adapter;
+
+       list_for_each_entry(ra_list, ra_list_head, list) {
+               if (skb_queue_empty(&ra_list->skb_head))
+                       continue;
+
+               skb_queue_walk_safe(&ra_list->skb_head, skb, tmp) {
+                       tx_info = MWIFIEX_SKB_TXCB(skb);
+                       if (tx_info->flags & MWIFIEX_BUF_FLAG_BRIDGED_PKT) {
+                               __skb_unlink(skb, &ra_list->skb_head);
+                               mwifiex_write_data_complete(adapter, skb, 0,
+                                                           -1);
+                               atomic_dec(&priv->wmm.tx_pkts_queued);
+                               pkt_deleted = true;
+                       }
+                       if ((atomic_read(&adapter->pending_bridged_pkts) <=
+                                            MWIFIEX_BRIDGED_PKTS_THR_LOW))
+                               break;
+               }
+       }
+
+       return pkt_deleted;
+}
+
+/* This function deletes packets from particular RA List. RA list index
+ * from which packets are deleted is preserved so that packets from next RA
+ * list are deleted upon subsequent call thus maintaining fairness.
+ */
+static void mwifiex_uap_cleanup_tx_queues(struct mwifiex_private *priv)
+{
+       unsigned long flags;
+       struct list_head *ra_list;
+       int i;
+
+       spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
+
+       for (i = 0; i < MAX_NUM_TID; i++, priv->del_list_idx++) {
+               if (priv->del_list_idx == MAX_NUM_TID)
+                       priv->del_list_idx = 0;
+               ra_list = &priv->wmm.tid_tbl_ptr[priv->del_list_idx].ra_list;
+               if (mwifiex_uap_del_tx_pkts_in_ralist(priv, ra_list)) {
+                       priv->del_list_idx++;
+                       break;
+               }
+       }
+
+       spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
+}
+
+
 static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv,
                                         struct sk_buff *skb)
 {
@@ -40,10 +103,11 @@ static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv,
        rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset);
 
        if ((atomic_read(&adapter->pending_bridged_pkts) >=
-                                            MWIFIEX_BRIDGED_PKTS_THRESHOLD)) {
+                                            MWIFIEX_BRIDGED_PKTS_THR_HIGH)) {
                dev_err(priv->adapter->dev,
                        "Tx: Bridge packet limit reached. Drop packet!\n");
                kfree_skb(skb);
+               mwifiex_uap_cleanup_tx_queues(priv);
                return;
        }
 
@@ -95,10 +159,6 @@ static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv,
        atomic_inc(&adapter->tx_pending);
        atomic_inc(&adapter->pending_bridged_pkts);
 
-       if ((atomic_read(&adapter->tx_pending) >= MAX_TX_PENDING)) {
-               mwifiex_set_trans_start(priv->netdev);
-               mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter);
-       }
        return;
 }
 
index f90fe21e5bfda65d5bc2a0d6fc6638ac8765e72e..fca98b5d7de49d53ce21bd4cb68bdfcef8352bda 100644 (file)
@@ -786,6 +786,13 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
        return 0;
 }
 
+static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
+{
+       struct usb_card_rec *card = (struct usb_card_rec *)adapter->card;
+
+       usb_set_intfdata(card->intf, NULL);
+}
+
 static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
                                    struct mwifiex_fw_image *fw)
 {
@@ -978,6 +985,7 @@ static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
 
 static struct mwifiex_if_ops usb_ops = {
        .register_dev =         mwifiex_register_dev,
+       .unregister_dev =       mwifiex_unregister_dev,
        .wakeup =               mwifiex_pm_wakeup_card,
        .wakeup_complete =      mwifiex_pm_wakeup_card_complete,
 
index 944e8846f6fc757e8f937f0ece42e243279e9a29..2e8f9cdea54d719cf0f25b4b29d816eb0709ff7a 100644 (file)
@@ -120,7 +120,7 @@ mwifiex_wmm_allocate_ralist_node(struct mwifiex_adapter *adapter, u8 *ra)
 
        memcpy(ra_list->ra, ra, ETH_ALEN);
 
-       ra_list->total_pkts_size = 0;
+       ra_list->total_pkt_count = 0;
 
        dev_dbg(adapter->dev, "info: allocated ra_list %p\n", ra_list);
 
@@ -188,7 +188,7 @@ mwifiex_ralist_add(struct mwifiex_private *priv, u8 *ra)
                        ra_list, ra_list->is_11n_enabled);
 
                if (ra_list->is_11n_enabled) {
-                       ra_list->pkt_count = 0;
+                       ra_list->ba_pkt_count = 0;
                        ra_list->ba_packet_thr =
                                              mwifiex_get_random_ba_threshold();
                }
@@ -679,8 +679,8 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv,
 
        skb_queue_tail(&ra_list->skb_head, skb);
 
-       ra_list->total_pkts_size += skb->len;
-       ra_list->pkt_count++;
+       ra_list->ba_pkt_count++;
+       ra_list->total_pkt_count++;
 
        if (atomic_read(&priv->wmm.highest_queued_prio) <
                                                tos_to_tid_inv[tid_down])
@@ -1037,7 +1037,7 @@ mwifiex_send_single_packet(struct mwifiex_private *priv,
        tx_info = MWIFIEX_SKB_TXCB(skb);
        dev_dbg(adapter->dev, "data: dequeuing the packet %p %p\n", ptr, skb);
 
-       ptr->total_pkts_size -= skb->len;
+       ptr->total_pkt_count--;
 
        if (!skb_queue_empty(&ptr->skb_head))
                skb_next = skb_peek(&ptr->skb_head);
@@ -1062,8 +1062,8 @@ mwifiex_send_single_packet(struct mwifiex_private *priv,
 
                skb_queue_tail(&ptr->skb_head, skb);
 
-               ptr->total_pkts_size += skb->len;
-               ptr->pkt_count++;
+               ptr->total_pkt_count++;
+               ptr->ba_pkt_count++;
                tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT;
                spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
                                       ra_list_flags);
@@ -1224,7 +1224,7 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter)
                   mwifiex_send_single_packet() */
        } else {
                if (mwifiex_is_ampdu_allowed(priv, tid) &&
-                   ptr->pkt_count > ptr->ba_packet_thr) {
+                   ptr->ba_pkt_count > ptr->ba_packet_thr) {
                        if (mwifiex_space_avail_for_new_ba_stream(adapter)) {
                                mwifiex_create_ba_tbl(priv, ptr->ra, tid,
                                                      BA_SETUP_INPROGRESS);
index 9b915d3a44bee4c7d585ca79d8209415c40d7c01..68dbbb9c6d1259eb3d83d7c1458126f6fc69a2f2 100644 (file)
@@ -1,6 +1,6 @@
 menuconfig RT2X00
        tristate "Ralink driver support"
-       depends on MAC80211
+       depends on MAC80211 && HAS_DMA
        ---help---
          This will enable the support for the Ralink drivers,
          developed in the rt2x00 project <http://rt2x00.serialmonkey.com>.
@@ -166,6 +166,12 @@ config RT2800USB_RT35XX
          rt2800usb driver.
          Supported chips: RT3572
 
+config RT2800USB_RT3573
+       bool "rt2800usb - Include support for rt3573 devices (EXPERIMENTAL)"
+       ---help---
+         This enables support for RT3573 chipset based wireless USB devices
+         in the rt2800usb driver.
+
 config RT2800USB_RT53XX
        bool "rt2800usb - Include support for rt53xx devices (EXPERIMENTAL)"
        ---help---
index d78c495a86a0b2eed4f3910d1f911617d6e50877..a3132414ac9f4602454b1294d01c4f34dd01dbc3 100644 (file)
@@ -88,6 +88,7 @@
 #define REV_RT3071E                    0x0211
 #define REV_RT3090E                    0x0211
 #define REV_RT3390E                    0x0211
+#define REV_RT3593E                    0x0211
 #define REV_RT5390F                    0x0502
 #define REV_RT5390R                    0x1502
 #define REV_RT5592C                    0x0221
 #define TX_PWR_CFG_0_9MBS              FIELD32(0x00f00000)
 #define TX_PWR_CFG_0_12MBS             FIELD32(0x0f000000)
 #define TX_PWR_CFG_0_18MBS             FIELD32(0xf0000000)
+/* bits for 3T devices */
+#define TX_PWR_CFG_0_CCK1_CH0          FIELD32(0x0000000f)
+#define TX_PWR_CFG_0_CCK1_CH1          FIELD32(0x000000f0)
+#define TX_PWR_CFG_0_CCK5_CH0          FIELD32(0x00000f00)
+#define TX_PWR_CFG_0_CCK5_CH1          FIELD32(0x0000f000)
+#define TX_PWR_CFG_0_OFDM6_CH0         FIELD32(0x000f0000)
+#define TX_PWR_CFG_0_OFDM6_CH1         FIELD32(0x00f00000)
+#define TX_PWR_CFG_0_OFDM12_CH0                FIELD32(0x0f000000)
+#define TX_PWR_CFG_0_OFDM12_CH1                FIELD32(0xf0000000)
 
 /*
  * TX_PWR_CFG_1:
 #define TX_PWR_CFG_1_MCS1              FIELD32(0x00f00000)
 #define TX_PWR_CFG_1_MCS2              FIELD32(0x0f000000)
 #define TX_PWR_CFG_1_MCS3              FIELD32(0xf0000000)
+/* bits for 3T devices */
+#define TX_PWR_CFG_1_OFDM24_CH0                FIELD32(0x0000000f)
+#define TX_PWR_CFG_1_OFDM24_CH1                FIELD32(0x000000f0)
+#define TX_PWR_CFG_1_OFDM48_CH0                FIELD32(0x00000f00)
+#define TX_PWR_CFG_1_OFDM48_CH1                FIELD32(0x0000f000)
+#define TX_PWR_CFG_1_MCS0_CH0          FIELD32(0x000f0000)
+#define TX_PWR_CFG_1_MCS0_CH1          FIELD32(0x00f00000)
+#define TX_PWR_CFG_1_MCS2_CH0          FIELD32(0x0f000000)
+#define TX_PWR_CFG_1_MCS2_CH1          FIELD32(0xf0000000)
 
 /*
  * TX_PWR_CFG_2:
 #define TX_PWR_CFG_2_MCS9              FIELD32(0x00f00000)
 #define TX_PWR_CFG_2_MCS10             FIELD32(0x0f000000)
 #define TX_PWR_CFG_2_MCS11             FIELD32(0xf0000000)
+/* bits for 3T devices */
+#define TX_PWR_CFG_2_MCS4_CH0          FIELD32(0x0000000f)
+#define TX_PWR_CFG_2_MCS4_CH1          FIELD32(0x000000f0)
+#define TX_PWR_CFG_2_MCS6_CH0          FIELD32(0x00000f00)
+#define TX_PWR_CFG_2_MCS6_CH1          FIELD32(0x0000f000)
+#define TX_PWR_CFG_2_MCS8_CH0          FIELD32(0x000f0000)
+#define TX_PWR_CFG_2_MCS8_CH1          FIELD32(0x00f00000)
+#define TX_PWR_CFG_2_MCS10_CH0         FIELD32(0x0f000000)
+#define TX_PWR_CFG_2_MCS10_CH1         FIELD32(0xf0000000)
 
 /*
  * TX_PWR_CFG_3:
 #define TX_PWR_CFG_3_UKNOWN2           FIELD32(0x00f00000)
 #define TX_PWR_CFG_3_UKNOWN3           FIELD32(0x0f000000)
 #define TX_PWR_CFG_3_UKNOWN4           FIELD32(0xf0000000)
+/* bits for 3T devices */
+#define TX_PWR_CFG_3_MCS12_CH0         FIELD32(0x0000000f)
+#define TX_PWR_CFG_3_MCS12_CH1         FIELD32(0x000000f0)
+#define TX_PWR_CFG_3_MCS14_CH0         FIELD32(0x00000f00)
+#define TX_PWR_CFG_3_MCS14_CH1         FIELD32(0x0000f000)
+#define TX_PWR_CFG_3_STBC0_CH0         FIELD32(0x000f0000)
+#define TX_PWR_CFG_3_STBC0_CH1         FIELD32(0x00f00000)
+#define TX_PWR_CFG_3_STBC2_CH0         FIELD32(0x0f000000)
+#define TX_PWR_CFG_3_STBC2_CH1         FIELD32(0xf0000000)
 
 /*
  * TX_PWR_CFG_4:
 #define TX_PWR_CFG_4_UKNOWN6           FIELD32(0x000000f0)
 #define TX_PWR_CFG_4_UKNOWN7           FIELD32(0x00000f00)
 #define TX_PWR_CFG_4_UKNOWN8           FIELD32(0x0000f000)
+/* bits for 3T devices */
+#define TX_PWR_CFG_3_STBC4_CH0         FIELD32(0x0000000f)
+#define TX_PWR_CFG_3_STBC4_CH1         FIELD32(0x000000f0)
+#define TX_PWR_CFG_3_STBC6_CH0         FIELD32(0x00000f00)
+#define TX_PWR_CFG_3_STBC6_CH1         FIELD32(0x0000f000)
 
 /*
  * TX_PIN_CFG:
  */
 #define EXP_ACK_TIME                   0x1380
 
+/* TX_PWR_CFG_5 */
+#define TX_PWR_CFG_5                   0x1384
+#define TX_PWR_CFG_5_MCS16_CH0         FIELD32(0x0000000f)
+#define TX_PWR_CFG_5_MCS16_CH1         FIELD32(0x000000f0)
+#define TX_PWR_CFG_5_MCS16_CH2         FIELD32(0x00000f00)
+#define TX_PWR_CFG_5_MCS18_CH0         FIELD32(0x000f0000)
+#define TX_PWR_CFG_5_MCS18_CH1         FIELD32(0x00f00000)
+#define TX_PWR_CFG_5_MCS18_CH2         FIELD32(0x0f000000)
+
+/* TX_PWR_CFG_6 */
+#define TX_PWR_CFG_6                   0x1388
+#define TX_PWR_CFG_6_MCS20_CH0         FIELD32(0x0000000f)
+#define TX_PWR_CFG_6_MCS20_CH1         FIELD32(0x000000f0)
+#define TX_PWR_CFG_6_MCS20_CH2         FIELD32(0x00000f00)
+#define TX_PWR_CFG_6_MCS22_CH0         FIELD32(0x000f0000)
+#define TX_PWR_CFG_6_MCS22_CH1         FIELD32(0x00f00000)
+#define TX_PWR_CFG_6_MCS22_CH2         FIELD32(0x0f000000)
+
+/* TX_PWR_CFG_0_EXT */
+#define TX_PWR_CFG_0_EXT               0x1390
+#define TX_PWR_CFG_0_EXT_CCK1_CH2      FIELD32(0x0000000f)
+#define TX_PWR_CFG_0_EXT_CCK5_CH2      FIELD32(0x00000f00)
+#define TX_PWR_CFG_0_EXT_OFDM6_CH2     FIELD32(0x000f0000)
+#define TX_PWR_CFG_0_EXT_OFDM12_CH2    FIELD32(0x0f000000)
+
+/* TX_PWR_CFG_1_EXT */
+#define TX_PWR_CFG_1_EXT               0x1394
+#define TX_PWR_CFG_1_EXT_OFDM24_CH2    FIELD32(0x0000000f)
+#define TX_PWR_CFG_1_EXT_OFDM48_CH2    FIELD32(0x00000f00)
+#define TX_PWR_CFG_1_EXT_MCS0_CH2      FIELD32(0x000f0000)
+#define TX_PWR_CFG_1_EXT_MCS2_CH2      FIELD32(0x0f000000)
+
+/* TX_PWR_CFG_2_EXT */
+#define TX_PWR_CFG_2_EXT               0x1398
+#define TX_PWR_CFG_2_EXT_MCS4_CH2      FIELD32(0x0000000f)
+#define TX_PWR_CFG_2_EXT_MCS6_CH2      FIELD32(0x00000f00)
+#define TX_PWR_CFG_2_EXT_MCS8_CH2      FIELD32(0x000f0000)
+#define TX_PWR_CFG_2_EXT_MCS10_CH2     FIELD32(0x0f000000)
+
+/* TX_PWR_CFG_3_EXT */
+#define TX_PWR_CFG_3_EXT               0x139c
+#define TX_PWR_CFG_3_EXT_MCS12_CH2     FIELD32(0x0000000f)
+#define TX_PWR_CFG_3_EXT_MCS14_CH2     FIELD32(0x00000f00)
+#define TX_PWR_CFG_3_EXT_STBC0_CH2     FIELD32(0x000f0000)
+#define TX_PWR_CFG_3_EXT_STBC2_CH2     FIELD32(0x0f000000)
+
+/* TX_PWR_CFG_4_EXT */
+#define TX_PWR_CFG_4_EXT               0x13a0
+#define TX_PWR_CFG_4_EXT_STBC4_CH2     FIELD32(0x0000000f)
+#define TX_PWR_CFG_4_EXT_STBC6_CH2     FIELD32(0x00000f00)
+
+/* TX_PWR_CFG_7 */
+#define TX_PWR_CFG_7                   0x13d4
+#define TX_PWR_CFG_7_OFDM54_CH0                FIELD32(0x0000000f)
+#define TX_PWR_CFG_7_OFDM54_CH1                FIELD32(0x000000f0)
+#define TX_PWR_CFG_7_OFDM54_CH2                FIELD32(0x00000f00)
+#define TX_PWR_CFG_7_MCS7_CH0          FIELD32(0x000f0000)
+#define TX_PWR_CFG_7_MCS7_CH1          FIELD32(0x00f00000)
+#define TX_PWR_CFG_7_MCS7_CH2          FIELD32(0x0f000000)
+
+/* TX_PWR_CFG_8 */
+#define TX_PWR_CFG_8                   0x13d8
+#define TX_PWR_CFG_8_MCS15_CH0         FIELD32(0x0000000f)
+#define TX_PWR_CFG_8_MCS15_CH1         FIELD32(0x000000f0)
+#define TX_PWR_CFG_8_MCS15_CH2         FIELD32(0x00000f00)
+#define TX_PWR_CFG_8_MCS23_CH0         FIELD32(0x000f0000)
+#define TX_PWR_CFG_8_MCS23_CH1         FIELD32(0x00f00000)
+#define TX_PWR_CFG_8_MCS23_CH2         FIELD32(0x0f000000)
+
+/* TX_PWR_CFG_9 */
+#define TX_PWR_CFG_9                   0x13dc
+#define TX_PWR_CFG_9_STBC7_CH0         FIELD32(0x0000000f)
+#define TX_PWR_CFG_9_STBC7_CH1         FIELD32(0x000000f0)
+#define TX_PWR_CFG_9_STBC7_CH2         FIELD32(0x00000f00)
+
 /*
  * RX_FILTER_CFG: RX configuration register.
  */
@@ -1975,6 +2092,10 @@ struct mac_iveiv_entry {
 #define BBP109_TX0_POWER               FIELD8(0x0f)
 #define BBP109_TX1_POWER               FIELD8(0xf0)
 
+/* BBP 110 */
+#define BBP110_TX2_POWER               FIELD8(0x0f)
+
+
 /*
  * BBP 138: Unknown
  */
@@ -2024,6 +2145,12 @@ struct mac_iveiv_entry {
 #define RFCSR3_PA2_CASCODE_BIAS_CCKK   FIELD8(0x80)
 /* Bits for RF3290/RF5360/RF5370/RF5372/RF5390/RF5392 */
 #define RFCSR3_VCOCAL_EN               FIELD8(0x80)
+/* Bits for RF3050 */
+#define RFCSR3_BIT1                    FIELD8(0x02)
+#define RFCSR3_BIT2                    FIELD8(0x04)
+#define RFCSR3_BIT3                    FIELD8(0x08)
+#define RFCSR3_BIT4                    FIELD8(0x10)
+#define RFCSR3_BIT5                    FIELD8(0x20)
 
 /*
  * FRCSR 5:
@@ -2036,6 +2163,8 @@ struct mac_iveiv_entry {
 #define RFCSR6_R1                      FIELD8(0x03)
 #define RFCSR6_R2                      FIELD8(0x40)
 #define RFCSR6_TXDIV           FIELD8(0x0c)
+/* bits for RF3053 */
+#define RFCSR6_VCO_IC                  FIELD8(0xc0)
 
 /*
  * RFCSR 7:
@@ -2060,7 +2189,12 @@ struct mac_iveiv_entry {
  * RFCSR 11:
  */
 #define RFCSR11_R                      FIELD8(0x03)
+#define RFCSR11_PLL_MOD                        FIELD8(0x0c)
 #define RFCSR11_MOD                    FIELD8(0xc0)
+/* bits for RF3053 */
+/* TODO: verify RFCSR11_MOD usage on other chips */
+#define RFCSR11_PLL_IDOH               FIELD8(0x40)
+
 
 /*
  * RFCSR 12:
@@ -2092,6 +2226,10 @@ struct mac_iveiv_entry {
 #define RFCSR17_R                      FIELD8(0x20)
 #define RFCSR17_CODE                   FIELD8(0x7f)
 
+/* RFCSR 18 */
+#define RFCSR18_XO_TUNE_BYPASS         FIELD8(0x40)
+
+
 /*
  * RFCSR 20:
  */
@@ -2152,6 +2290,12 @@ struct mac_iveiv_entry {
 #define RFCSR31_RX_H20M                        FIELD8(0x20)
 #define RFCSR31_RX_CALIB               FIELD8(0x7f)
 
+/* RFCSR 32 bits for RF3053 */
+#define RFCSR32_TX_AGC_FC              FIELD8(0xf8)
+
+/* RFCSR 36 bits for RF3053 */
+#define RFCSR36_RF_BS                  FIELD8(0x80)
+
 /*
  * RFCSR 38:
  */
@@ -2160,6 +2304,7 @@ struct mac_iveiv_entry {
 /*
  * RFCSR 39:
  */
+#define RFCSR39_RX_DIV                 FIELD8(0x40)
 #define RFCSR39_RX_LO2_EN              FIELD8(0x80)
 
 /*
@@ -2167,12 +2312,36 @@ struct mac_iveiv_entry {
  */
 #define RFCSR49_TX                     FIELD8(0x3f)
 #define RFCSR49_EP                     FIELD8(0xc0)
+/* bits for RT3593 */
+#define RFCSR49_TX_LO1_IC              FIELD8(0x1c)
+#define RFCSR49_TX_DIV                 FIELD8(0x20)
 
 /*
  * RFCSR 50:
  */
 #define RFCSR50_TX                     FIELD8(0x3f)
 #define RFCSR50_EP                     FIELD8(0xc0)
+/* bits for RT3593 */
+#define RFCSR50_TX_LO1_EN              FIELD8(0x20)
+#define RFCSR50_TX_LO2_EN              FIELD8(0x10)
+
+/* RFCSR 51 */
+/* bits for RT3593 */
+#define RFCSR51_BITS01                 FIELD8(0x03)
+#define RFCSR51_BITS24                 FIELD8(0x1c)
+#define RFCSR51_BITS57                 FIELD8(0xe0)
+
+#define RFCSR53_TX_POWER               FIELD8(0x3f)
+#define RFCSR53_UNKNOWN                        FIELD8(0xc0)
+
+#define RFCSR54_TX_POWER               FIELD8(0x3f)
+#define RFCSR54_UNKNOWN                        FIELD8(0xc0)
+
+#define RFCSR55_TX_POWER               FIELD8(0x3f)
+#define RFCSR55_UNKNOWN                        FIELD8(0xc0)
+
+#define RFCSR57_DRV_CC                 FIELD8(0xfc)
+
 
 /*
  * RF registers
@@ -2206,28 +2375,67 @@ struct mac_iveiv_entry {
  * The wordsize of the EEPROM is 16 bits.
  */
 
-/*
- * Chip ID
- */
-#define EEPROM_CHIP_ID                 0x0000
+enum rt2800_eeprom_word {
+       EEPROM_CHIP_ID = 0,
+       EEPROM_VERSION,
+       EEPROM_MAC_ADDR_0,
+       EEPROM_MAC_ADDR_1,
+       EEPROM_MAC_ADDR_2,
+       EEPROM_NIC_CONF0,
+       EEPROM_NIC_CONF1,
+       EEPROM_FREQ,
+       EEPROM_LED_AG_CONF,
+       EEPROM_LED_ACT_CONF,
+       EEPROM_LED_POLARITY,
+       EEPROM_NIC_CONF2,
+       EEPROM_LNA,
+       EEPROM_RSSI_BG,
+       EEPROM_RSSI_BG2,
+       EEPROM_TXMIXER_GAIN_BG,
+       EEPROM_RSSI_A,
+       EEPROM_RSSI_A2,
+       EEPROM_TXMIXER_GAIN_A,
+       EEPROM_EIRP_MAX_TX_POWER,
+       EEPROM_TXPOWER_DELTA,
+       EEPROM_TXPOWER_BG1,
+       EEPROM_TXPOWER_BG2,
+       EEPROM_TSSI_BOUND_BG1,
+       EEPROM_TSSI_BOUND_BG2,
+       EEPROM_TSSI_BOUND_BG3,
+       EEPROM_TSSI_BOUND_BG4,
+       EEPROM_TSSI_BOUND_BG5,
+       EEPROM_TXPOWER_A1,
+       EEPROM_TXPOWER_A2,
+       EEPROM_TSSI_BOUND_A1,
+       EEPROM_TSSI_BOUND_A2,
+       EEPROM_TSSI_BOUND_A3,
+       EEPROM_TSSI_BOUND_A4,
+       EEPROM_TSSI_BOUND_A5,
+       EEPROM_TXPOWER_BYRATE,
+       EEPROM_BBP_START,
+
+       /* IDs for extended EEPROM format used by three-chain devices */
+       EEPROM_EXT_LNA2,
+       EEPROM_EXT_TXPOWER_BG3,
+       EEPROM_EXT_TXPOWER_A3,
+
+       /* New values must be added before this */
+       EEPROM_WORD_COUNT
+};
 
 /*
  * EEPROM Version
  */
-#define EEPROM_VERSION                 0x0001
 #define EEPROM_VERSION_FAE             FIELD16(0x00ff)
 #define EEPROM_VERSION_VERSION         FIELD16(0xff00)
 
 /*
  * HW MAC address.
  */
-#define EEPROM_MAC_ADDR_0              0x0002
 #define EEPROM_MAC_ADDR_BYTE0          FIELD16(0x00ff)
 #define EEPROM_MAC_ADDR_BYTE1          FIELD16(0xff00)
-#define EEPROM_MAC_ADDR_1              0x0003
 #define EEPROM_MAC_ADDR_BYTE2          FIELD16(0x00ff)
 #define EEPROM_MAC_ADDR_BYTE3          FIELD16(0xff00)
-#define EEPROM_MAC_ADDR_2              0x0004
 #define EEPROM_MAC_ADDR_BYTE4          FIELD16(0x00ff)
 #define EEPROM_MAC_ADDR_BYTE5          FIELD16(0xff00)
 
@@ -2237,7 +2445,6 @@ struct mac_iveiv_entry {
  * TXPATH: 1: 1T, 2: 2T, 3: 3T
  * RF_TYPE: RFIC type
  */
-#define        EEPROM_NIC_CONF0                0x001a
 #define EEPROM_NIC_CONF0_RXPATH                FIELD16(0x000f)
 #define EEPROM_NIC_CONF0_TXPATH                FIELD16(0x00f0)
 #define EEPROM_NIC_CONF0_RF_TYPE               FIELD16(0x0f00)
@@ -2261,7 +2468,6 @@ struct mac_iveiv_entry {
  * BT_COEXIST: 0: disable, 1: enable
  * DAC_TEST: 0: disable, 1: enable
  */
-#define        EEPROM_NIC_CONF1                0x001b
 #define EEPROM_NIC_CONF1_HW_RADIO              FIELD16(0x0001)
 #define EEPROM_NIC_CONF1_EXTERNAL_TX_ALC               FIELD16(0x0002)
 #define EEPROM_NIC_CONF1_EXTERNAL_LNA_2G               FIELD16(0x0004)
@@ -2281,7 +2487,6 @@ struct mac_iveiv_entry {
 /*
  * EEPROM frequency
  */
-#define        EEPROM_FREQ                     0x001d
 #define EEPROM_FREQ_OFFSET             FIELD16(0x00ff)
 #define EEPROM_FREQ_LED_MODE           FIELD16(0x7f00)
 #define EEPROM_FREQ_LED_POLARITY       FIELD16(0x1000)
@@ -2298,9 +2503,6 @@ struct mac_iveiv_entry {
  * POLARITY_GPIO_4: Polarity GPIO4 setting.
  * LED_MODE: Led mode.
  */
-#define EEPROM_LED_AG_CONF             0x001e
-#define EEPROM_LED_ACT_CONF            0x001f
-#define EEPROM_LED_POLARITY            0x0020
 #define EEPROM_LED_POLARITY_RDY_BG     FIELD16(0x0001)
 #define EEPROM_LED_POLARITY_RDY_A      FIELD16(0x0002)
 #define EEPROM_LED_POLARITY_ACT                FIELD16(0x0004)
@@ -2317,7 +2519,6 @@ struct mac_iveiv_entry {
  * TX_STREAM: 0: Reserved, 1: 1 Stream, 2: 2 Stream
  * CRYSTAL: 00: Reserved, 01: One crystal, 10: Two crystal, 11: Reserved
  */
-#define EEPROM_NIC_CONF2               0x0021
 #define EEPROM_NIC_CONF2_RX_STREAM             FIELD16(0x000f)
 #define EEPROM_NIC_CONF2_TX_STREAM             FIELD16(0x00f0)
 #define EEPROM_NIC_CONF2_CRYSTAL               FIELD16(0x0600)
@@ -2325,54 +2526,46 @@ struct mac_iveiv_entry {
 /*
  * EEPROM LNA
  */
-#define EEPROM_LNA                     0x0022
 #define EEPROM_LNA_BG                  FIELD16(0x00ff)
 #define EEPROM_LNA_A0                  FIELD16(0xff00)
 
 /*
  * EEPROM RSSI BG offset
  */
-#define EEPROM_RSSI_BG                 0x0023
 #define EEPROM_RSSI_BG_OFFSET0         FIELD16(0x00ff)
 #define EEPROM_RSSI_BG_OFFSET1         FIELD16(0xff00)
 
 /*
  * EEPROM RSSI BG2 offset
  */
-#define EEPROM_RSSI_BG2                        0x0024
 #define EEPROM_RSSI_BG2_OFFSET2                FIELD16(0x00ff)
 #define EEPROM_RSSI_BG2_LNA_A1         FIELD16(0xff00)
 
 /*
  * EEPROM TXMIXER GAIN BG offset (note overlaps with EEPROM RSSI BG2).
  */
-#define EEPROM_TXMIXER_GAIN_BG         0x0024
 #define EEPROM_TXMIXER_GAIN_BG_VAL     FIELD16(0x0007)
 
 /*
  * EEPROM RSSI A offset
  */
-#define EEPROM_RSSI_A                  0x0025
 #define EEPROM_RSSI_A_OFFSET0          FIELD16(0x00ff)
 #define EEPROM_RSSI_A_OFFSET1          FIELD16(0xff00)
 
 /*
  * EEPROM RSSI A2 offset
  */
-#define EEPROM_RSSI_A2                 0x0026
 #define EEPROM_RSSI_A2_OFFSET2         FIELD16(0x00ff)
 #define EEPROM_RSSI_A2_LNA_A2          FIELD16(0xff00)
 
 /*
  * EEPROM TXMIXER GAIN A offset (note overlaps with EEPROM RSSI A2).
  */
-#define EEPROM_TXMIXER_GAIN_A          0x0026
 #define EEPROM_TXMIXER_GAIN_A_VAL      FIELD16(0x0007)
 
 /*
  * EEPROM EIRP Maximum TX power values(unit: dbm)
  */
-#define EEPROM_EIRP_MAX_TX_POWER       0x0027
 #define EEPROM_EIRP_MAX_TX_POWER_2GHZ  FIELD16(0x00ff)
 #define EEPROM_EIRP_MAX_TX_POWER_5GHZ  FIELD16(0xff00)
 
@@ -2383,7 +2576,6 @@ struct mac_iveiv_entry {
  * TYPE: 1: Plus the delta value, 0: minus the delta value
  * ENABLE: enable tx power compensation for 40BW
  */
-#define EEPROM_TXPOWER_DELTA           0x0028
 #define EEPROM_TXPOWER_DELTA_VALUE_2G  FIELD16(0x003f)
 #define EEPROM_TXPOWER_DELTA_TYPE_2G   FIELD16(0x0040)
 #define EEPROM_TXPOWER_DELTA_ENABLE_2G FIELD16(0x0080)
@@ -2394,8 +2586,6 @@ struct mac_iveiv_entry {
 /*
  * EEPROM TXPOWER 802.11BG
  */
-#define        EEPROM_TXPOWER_BG1              0x0029
-#define        EEPROM_TXPOWER_BG2              0x0030
 #define EEPROM_TXPOWER_BG_SIZE         7
 #define EEPROM_TXPOWER_BG_1            FIELD16(0x00ff)
 #define EEPROM_TXPOWER_BG_2            FIELD16(0xff00)
@@ -2407,7 +2597,6 @@ struct mac_iveiv_entry {
  * MINUS3: If the actual TSSI is below this boundary, tx power needs to be
  *         reduced by (agc_step * -3)
  */
-#define EEPROM_TSSI_BOUND_BG1          0x0037
 #define EEPROM_TSSI_BOUND_BG1_MINUS4   FIELD16(0x00ff)
 #define EEPROM_TSSI_BOUND_BG1_MINUS3   FIELD16(0xff00)
 
@@ -2418,7 +2607,6 @@ struct mac_iveiv_entry {
  * MINUS1: If the actual TSSI is below this boundary, tx power needs to be
  *         reduced by (agc_step * -1)
  */
-#define EEPROM_TSSI_BOUND_BG2          0x0038
 #define EEPROM_TSSI_BOUND_BG2_MINUS2   FIELD16(0x00ff)
 #define EEPROM_TSSI_BOUND_BG2_MINUS1   FIELD16(0xff00)
 
@@ -2428,7 +2616,6 @@ struct mac_iveiv_entry {
  * PLUS1: If the actual TSSI is above this boundary, tx power needs to be
  *        increased by (agc_step * 1)
  */
-#define EEPROM_TSSI_BOUND_BG3          0x0039
 #define EEPROM_TSSI_BOUND_BG3_REF      FIELD16(0x00ff)
 #define EEPROM_TSSI_BOUND_BG3_PLUS1    FIELD16(0xff00)
 
@@ -2439,7 +2626,6 @@ struct mac_iveiv_entry {
  * PLUS3: If the actual TSSI is above this boundary, tx power needs to be
  *        increased by (agc_step * 3)
  */
-#define EEPROM_TSSI_BOUND_BG4          0x003a
 #define EEPROM_TSSI_BOUND_BG4_PLUS2    FIELD16(0x00ff)
 #define EEPROM_TSSI_BOUND_BG4_PLUS3    FIELD16(0xff00)
 
@@ -2449,19 +2635,20 @@ struct mac_iveiv_entry {
  *        increased by (agc_step * 4)
  * AGC_STEP: Temperature compensation step.
  */
-#define EEPROM_TSSI_BOUND_BG5          0x003b
 #define EEPROM_TSSI_BOUND_BG5_PLUS4    FIELD16(0x00ff)
 #define EEPROM_TSSI_BOUND_BG5_AGC_STEP FIELD16(0xff00)
 
 /*
  * EEPROM TXPOWER 802.11A
  */
-#define EEPROM_TXPOWER_A1              0x003c
-#define EEPROM_TXPOWER_A2              0x0053
 #define EEPROM_TXPOWER_A_SIZE          6
 #define EEPROM_TXPOWER_A_1             FIELD16(0x00ff)
 #define EEPROM_TXPOWER_A_2             FIELD16(0xff00)
 
+/* EEPROM_TXPOWER_{A,G} fields for RT3593 */
+#define EEPROM_TXPOWER_ALC             FIELD8(0x1f)
+#define EEPROM_TXPOWER_FINE_CTRL       FIELD8(0xe0)
+
 /*
  * EEPROM temperature compensation boundaries 802.11A
  * MINUS4: If the actual TSSI is below this boundary, tx power needs to be
@@ -2469,7 +2656,6 @@ struct mac_iveiv_entry {
  * MINUS3: If the actual TSSI is below this boundary, tx power needs to be
  *         reduced by (agc_step * -3)
  */
-#define EEPROM_TSSI_BOUND_A1           0x006a
 #define EEPROM_TSSI_BOUND_A1_MINUS4    FIELD16(0x00ff)
 #define EEPROM_TSSI_BOUND_A1_MINUS3    FIELD16(0xff00)
 
@@ -2480,7 +2666,6 @@ struct mac_iveiv_entry {
  * MINUS1: If the actual TSSI is below this boundary, tx power needs to be
  *         reduced by (agc_step * -1)
  */
-#define EEPROM_TSSI_BOUND_A2           0x006b
 #define EEPROM_TSSI_BOUND_A2_MINUS2    FIELD16(0x00ff)
 #define EEPROM_TSSI_BOUND_A2_MINUS1    FIELD16(0xff00)
 
@@ -2490,7 +2675,6 @@ struct mac_iveiv_entry {
  * PLUS1: If the actual TSSI is above this boundary, tx power needs to be
  *        increased by (agc_step * 1)
  */
-#define EEPROM_TSSI_BOUND_A3           0x006c
 #define EEPROM_TSSI_BOUND_A3_REF       FIELD16(0x00ff)
 #define EEPROM_TSSI_BOUND_A3_PLUS1     FIELD16(0xff00)
 
@@ -2501,7 +2685,6 @@ struct mac_iveiv_entry {
  * PLUS3: If the actual TSSI is above this boundary, tx power needs to be
  *        increased by (agc_step * 3)
  */
-#define EEPROM_TSSI_BOUND_A4           0x006d
 #define EEPROM_TSSI_BOUND_A4_PLUS2     FIELD16(0x00ff)
 #define EEPROM_TSSI_BOUND_A4_PLUS3     FIELD16(0xff00)
 
@@ -2511,14 +2694,12 @@ struct mac_iveiv_entry {
  *        increased by (agc_step * 4)
  * AGC_STEP: Temperature compensation step.
  */
-#define EEPROM_TSSI_BOUND_A5           0x006e
 #define EEPROM_TSSI_BOUND_A5_PLUS4     FIELD16(0x00ff)
 #define EEPROM_TSSI_BOUND_A5_AGC_STEP  FIELD16(0xff00)
 
 /*
  * EEPROM TXPOWER by rate: tx power per tx rate for HT20 mode
  */
-#define EEPROM_TXPOWER_BYRATE          0x006f
 #define EEPROM_TXPOWER_BYRATE_SIZE     9
 
 #define EEPROM_TXPOWER_BYRATE_RATE0    FIELD16(0x000f)
@@ -2529,11 +2710,14 @@ struct mac_iveiv_entry {
 /*
  * EEPROM BBP.
  */
-#define        EEPROM_BBP_START                0x0078
 #define EEPROM_BBP_SIZE                        16
 #define EEPROM_BBP_VALUE               FIELD16(0x00ff)
 #define EEPROM_BBP_REG_ID              FIELD16(0xff00)
 
+/* EEPROM_EXT_LNA2 */
+#define EEPROM_EXT_LNA2_A1             FIELD16(0x00ff)
+#define EEPROM_EXT_LNA2_A2             FIELD16(0xff00)
+
 /*
  * EEPROM IQ Calibration, unlike other entries those are byte addresses.
  */
@@ -2630,6 +2814,7 @@ struct mac_iveiv_entry {
 #define TXWI_DESC_SIZE_5WORDS          (5 * sizeof(__le32))
 
 #define RXWI_DESC_SIZE_4WORDS          (4 * sizeof(__le32))
+#define RXWI_DESC_SIZE_5WORDS          (5 * sizeof(__le32))
 #define RXWI_DESC_SIZE_6WORDS          (6 * sizeof(__le32))
 
 /*
@@ -2750,18 +2935,15 @@ struct mac_iveiv_entry {
 #define MAX_A_TXPOWER  15
 #define DEFAULT_TXPOWER        5
 
+#define MIN_A_TXPOWER_3593     0
+#define MAX_A_TXPOWER_3593     31
+
 #define TXPOWER_G_FROM_DEV(__txpower) \
        ((__txpower) > MAX_G_TXPOWER) ? DEFAULT_TXPOWER : (__txpower)
 
-#define TXPOWER_G_TO_DEV(__txpower) \
-       clamp_t(char, __txpower, MIN_G_TXPOWER, MAX_G_TXPOWER)
-
 #define TXPOWER_A_FROM_DEV(__txpower) \
        ((__txpower) > MAX_A_TXPOWER) ? DEFAULT_TXPOWER : (__txpower)
 
-#define TXPOWER_A_TO_DEV(__txpower) \
-       clamp_t(char, __txpower, MIN_A_TXPOWER, MAX_A_TXPOWER)
-
 /*
  *  Board's maximun TX power limitation
  */
index 1f80ea5e29dde51068a2ad0815bbd2e4a49b6fcb..dedc3d4ae3659e7e525c71b710b0e22af98e9f10 100644 (file)
@@ -221,6 +221,157 @@ static void rt2800_rf_write(struct rt2x00_dev *rt2x00dev,
        mutex_unlock(&rt2x00dev->csr_mutex);
 }
 
+static const unsigned int rt2800_eeprom_map[EEPROM_WORD_COUNT] = {
+       [EEPROM_CHIP_ID]                = 0x0000,
+       [EEPROM_VERSION]                = 0x0001,
+       [EEPROM_MAC_ADDR_0]             = 0x0002,
+       [EEPROM_MAC_ADDR_1]             = 0x0003,
+       [EEPROM_MAC_ADDR_2]             = 0x0004,
+       [EEPROM_NIC_CONF0]              = 0x001a,
+       [EEPROM_NIC_CONF1]              = 0x001b,
+       [EEPROM_FREQ]                   = 0x001d,
+       [EEPROM_LED_AG_CONF]            = 0x001e,
+       [EEPROM_LED_ACT_CONF]           = 0x001f,
+       [EEPROM_LED_POLARITY]           = 0x0020,
+       [EEPROM_NIC_CONF2]              = 0x0021,
+       [EEPROM_LNA]                    = 0x0022,
+       [EEPROM_RSSI_BG]                = 0x0023,
+       [EEPROM_RSSI_BG2]               = 0x0024,
+       [EEPROM_TXMIXER_GAIN_BG]        = 0x0024, /* overlaps with RSSI_BG2 */
+       [EEPROM_RSSI_A]                 = 0x0025,
+       [EEPROM_RSSI_A2]                = 0x0026,
+       [EEPROM_TXMIXER_GAIN_A]         = 0x0026, /* overlaps with RSSI_A2 */
+       [EEPROM_EIRP_MAX_TX_POWER]      = 0x0027,
+       [EEPROM_TXPOWER_DELTA]          = 0x0028,
+       [EEPROM_TXPOWER_BG1]            = 0x0029,
+       [EEPROM_TXPOWER_BG2]            = 0x0030,
+       [EEPROM_TSSI_BOUND_BG1]         = 0x0037,
+       [EEPROM_TSSI_BOUND_BG2]         = 0x0038,
+       [EEPROM_TSSI_BOUND_BG3]         = 0x0039,
+       [EEPROM_TSSI_BOUND_BG4]         = 0x003a,
+       [EEPROM_TSSI_BOUND_BG5]         = 0x003b,
+       [EEPROM_TXPOWER_A1]             = 0x003c,
+       [EEPROM_TXPOWER_A2]             = 0x0053,
+       [EEPROM_TSSI_BOUND_A1]          = 0x006a,
+       [EEPROM_TSSI_BOUND_A2]          = 0x006b,
+       [EEPROM_TSSI_BOUND_A3]          = 0x006c,
+       [EEPROM_TSSI_BOUND_A4]          = 0x006d,
+       [EEPROM_TSSI_BOUND_A5]          = 0x006e,
+       [EEPROM_TXPOWER_BYRATE]         = 0x006f,
+       [EEPROM_BBP_START]              = 0x0078,
+};
+
+static const unsigned int rt2800_eeprom_map_ext[EEPROM_WORD_COUNT] = {
+       [EEPROM_CHIP_ID]                = 0x0000,
+       [EEPROM_VERSION]                = 0x0001,
+       [EEPROM_MAC_ADDR_0]             = 0x0002,
+       [EEPROM_MAC_ADDR_1]             = 0x0003,
+       [EEPROM_MAC_ADDR_2]             = 0x0004,
+       [EEPROM_NIC_CONF0]              = 0x001a,
+       [EEPROM_NIC_CONF1]              = 0x001b,
+       [EEPROM_NIC_CONF2]              = 0x001c,
+       [EEPROM_EIRP_MAX_TX_POWER]      = 0x0020,
+       [EEPROM_FREQ]                   = 0x0022,
+       [EEPROM_LED_AG_CONF]            = 0x0023,
+       [EEPROM_LED_ACT_CONF]           = 0x0024,
+       [EEPROM_LED_POLARITY]           = 0x0025,
+       [EEPROM_LNA]                    = 0x0026,
+       [EEPROM_EXT_LNA2]               = 0x0027,
+       [EEPROM_RSSI_BG]                = 0x0028,
+       [EEPROM_TXPOWER_DELTA]          = 0x0028, /* Overlaps with RSSI_BG */
+       [EEPROM_RSSI_BG2]               = 0x0029,
+       [EEPROM_TXMIXER_GAIN_BG]        = 0x0029, /* Overlaps with RSSI_BG2 */
+       [EEPROM_RSSI_A]                 = 0x002a,
+       [EEPROM_RSSI_A2]                = 0x002b,
+       [EEPROM_TXMIXER_GAIN_A]         = 0x002b, /* Overlaps with RSSI_A2 */
+       [EEPROM_TXPOWER_BG1]            = 0x0030,
+       [EEPROM_TXPOWER_BG2]            = 0x0037,
+       [EEPROM_EXT_TXPOWER_BG3]        = 0x003e,
+       [EEPROM_TSSI_BOUND_BG1]         = 0x0045,
+       [EEPROM_TSSI_BOUND_BG2]         = 0x0046,
+       [EEPROM_TSSI_BOUND_BG3]         = 0x0047,
+       [EEPROM_TSSI_BOUND_BG4]         = 0x0048,
+       [EEPROM_TSSI_BOUND_BG5]         = 0x0049,
+       [EEPROM_TXPOWER_A1]             = 0x004b,
+       [EEPROM_TXPOWER_A2]             = 0x0065,
+       [EEPROM_EXT_TXPOWER_A3]         = 0x007f,
+       [EEPROM_TSSI_BOUND_A1]          = 0x009a,
+       [EEPROM_TSSI_BOUND_A2]          = 0x009b,
+       [EEPROM_TSSI_BOUND_A3]          = 0x009c,
+       [EEPROM_TSSI_BOUND_A4]          = 0x009d,
+       [EEPROM_TSSI_BOUND_A5]          = 0x009e,
+       [EEPROM_TXPOWER_BYRATE]         = 0x00a0,
+};
+
+static unsigned int rt2800_eeprom_word_index(struct rt2x00_dev *rt2x00dev,
+                                            const enum rt2800_eeprom_word word)
+{
+       const unsigned int *map;
+       unsigned int index;
+
+       if (WARN_ONCE(word >= EEPROM_WORD_COUNT,
+                     "%s: invalid EEPROM word %d\n",
+                     wiphy_name(rt2x00dev->hw->wiphy), word))
+               return 0;
+
+       if (rt2x00_rt(rt2x00dev, RT3593))
+               map = rt2800_eeprom_map_ext;
+       else
+               map = rt2800_eeprom_map;
+
+       index = map[word];
+
+       /* Index 0 is valid only for EEPROM_CHIP_ID.
+        * Otherwise it means that the offset of the
+        * given word is not initialized in the map,
+        * or that the field is not usable on the
+        * actual chipset.
+        */
+       WARN_ONCE(word != EEPROM_CHIP_ID && index == 0,
+                 "%s: invalid access of EEPROM word %d\n",
+                 wiphy_name(rt2x00dev->hw->wiphy), word);
+
+       return index;
+}
+
+static void *rt2800_eeprom_addr(struct rt2x00_dev *rt2x00dev,
+                               const enum rt2800_eeprom_word word)
+{
+       unsigned int index;
+
+       index = rt2800_eeprom_word_index(rt2x00dev, word);
+       return rt2x00_eeprom_addr(rt2x00dev, index);
+}
+
+static void rt2800_eeprom_read(struct rt2x00_dev *rt2x00dev,
+                              const enum rt2800_eeprom_word word, u16 *data)
+{
+       unsigned int index;
+
+       index = rt2800_eeprom_word_index(rt2x00dev, word);
+       rt2x00_eeprom_read(rt2x00dev, index, data);
+}
+
+static void rt2800_eeprom_write(struct rt2x00_dev *rt2x00dev,
+                               const enum rt2800_eeprom_word word, u16 data)
+{
+       unsigned int index;
+
+       index = rt2800_eeprom_word_index(rt2x00dev, word);
+       rt2x00_eeprom_write(rt2x00dev, index, data);
+}
+
+static void rt2800_eeprom_read_from_array(struct rt2x00_dev *rt2x00dev,
+                                         const enum rt2800_eeprom_word array,
+                                         unsigned int offset,
+                                         u16 *data)
+{
+       unsigned int index;
+
+       index = rt2800_eeprom_word_index(rt2x00dev, array);
+       rt2x00_eeprom_read(rt2x00dev, index + offset, data);
+}
+
 static int rt2800_enable_wlan_rt3290(struct rt2x00_dev *rt2x00dev)
 {
        u32 reg;
@@ -609,16 +760,16 @@ static int rt2800_agc_to_rssi(struct rt2x00_dev *rt2x00dev, u32 rxwi_w2)
        u8 offset2;
 
        if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) {
-               rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &eeprom);
+               rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &eeprom);
                offset0 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET0);
                offset1 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET1);
-               rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &eeprom);
+               rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &eeprom);
                offset2 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG2_OFFSET2);
        } else {
-               rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A, &eeprom);
+               rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A, &eeprom);
                offset0 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A_OFFSET0);
                offset1 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A_OFFSET1);
-               rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &eeprom);
+               rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &eeprom);
                offset2 = rt2x00_get_field16(eeprom, EEPROM_RSSI_A2_OFFSET2);
        }
 
@@ -890,6 +1041,9 @@ const struct rt2x00debug rt2800_rt2x00debug = {
                .word_count     = CSR_REG_SIZE / sizeof(u32),
        },
        .eeprom = {
+               /* NOTE: The local EEPROM access functions can't
+                * be used here, use the generic versions instead.
+                */
                .read           = rt2x00_eeprom_read,
                .write          = rt2x00_eeprom_write,
                .word_base      = EEPROM_BASE,
@@ -1547,7 +1701,7 @@ static void rt2800_config_3572bt_ant(struct rt2x00_dev *rt2x00dev)
        led_r_mode = rt2x00_get_field32(reg, LED_CFG_LED_POLAR) ? 0 : 3;
        if (led_g_mode != rt2x00_get_field32(reg, LED_CFG_G_LED_MODE) ||
            led_r_mode != rt2x00_get_field32(reg, LED_CFG_R_LED_MODE)) {
-               rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom);
+               rt2800_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom);
                led_ctrl = rt2x00_get_field16(eeprom, EEPROM_FREQ_LED_MODE);
                if (led_ctrl == 0 || led_ctrl > 0x40) {
                        rt2x00_set_field32(&reg, LED_CFG_G_LED_MODE, led_g_mode);
@@ -1609,7 +1763,7 @@ void rt2800_config_ant(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant)
                        rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 2);
                break;
        case 3:
-               rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0);
+               rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 2);
                break;
        }
 
@@ -1622,7 +1776,7 @@ void rt2800_config_ant(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant)
                    rt2x00_rt(rt2x00dev, RT3090) ||
                    rt2x00_rt(rt2x00dev, RT3352) ||
                    rt2x00_rt(rt2x00dev, RT3390)) {
-                       rt2x00_eeprom_read(rt2x00dev,
+                       rt2800_eeprom_read(rt2x00dev,
                                           EEPROM_NIC_CONF1, &eeprom);
                        if (rt2x00_get_field16(eeprom,
                                                EEPROM_NIC_CONF1_ANT_DIVERSITY))
@@ -1649,6 +1803,13 @@ void rt2800_config_ant(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant)
 
        rt2800_bbp_write(rt2x00dev, 3, r3);
        rt2800_bbp_write(rt2x00dev, 1, r1);
+
+       if (rt2x00_rt(rt2x00dev, RT3593)) {
+               if (ant->rx_chain_num == 1)
+                       rt2800_bbp_write(rt2x00dev, 86, 0x00);
+               else
+                       rt2800_bbp_write(rt2x00dev, 86, 0x46);
+       }
 }
 EXPORT_SYMBOL_GPL(rt2800_config_ant);
 
@@ -1659,17 +1820,31 @@ static void rt2800_config_lna_gain(struct rt2x00_dev *rt2x00dev,
        short lna_gain;
 
        if (libconf->rf.channel <= 14) {
-               rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom);
+               rt2800_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom);
                lna_gain = rt2x00_get_field16(eeprom, EEPROM_LNA_BG);
        } else if (libconf->rf.channel <= 64) {
-               rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom);
+               rt2800_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom);
                lna_gain = rt2x00_get_field16(eeprom, EEPROM_LNA_A0);
        } else if (libconf->rf.channel <= 128) {
-               rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &eeprom);
-               lna_gain = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG2_LNA_A1);
+               if (rt2x00_rt(rt2x00dev, RT3593)) {
+                       rt2800_eeprom_read(rt2x00dev, EEPROM_EXT_LNA2, &eeprom);
+                       lna_gain = rt2x00_get_field16(eeprom,
+                                                     EEPROM_EXT_LNA2_A1);
+               } else {
+                       rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &eeprom);
+                       lna_gain = rt2x00_get_field16(eeprom,
+                                                     EEPROM_RSSI_BG2_LNA_A1);
+               }
        } else {
-               rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &eeprom);
-               lna_gain = rt2x00_get_field16(eeprom, EEPROM_RSSI_A2_LNA_A2);
+               if (rt2x00_rt(rt2x00dev, RT3593)) {
+                       rt2800_eeprom_read(rt2x00dev, EEPROM_EXT_LNA2, &eeprom);
+                       lna_gain = rt2x00_get_field16(eeprom,
+                                                     EEPROM_EXT_LNA2_A2);
+               } else {
+                       rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &eeprom);
+                       lna_gain = rt2x00_get_field16(eeprom,
+                                                     EEPROM_RSSI_A2_LNA_A2);
+               }
        }
 
        rt2x00dev->lna_gain = lna_gain;
@@ -1993,6 +2168,303 @@ static void rt2800_config_channel_rf3052(struct rt2x00_dev *rt2x00dev,
        rt2800_rfcsr_write(rt2x00dev, 7, rfcsr);
 }
 
+static void rt2800_config_channel_rf3053(struct rt2x00_dev *rt2x00dev,
+                                        struct ieee80211_conf *conf,
+                                        struct rf_channel *rf,
+                                        struct channel_info *info)
+{
+       struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
+       u8 txrx_agc_fc;
+       u8 txrx_h20m;
+       u8 rfcsr;
+       u8 bbp;
+       const bool txbf_enabled = false; /* TODO */
+
+       /* TODO: use TX{0,1,2}FinePowerControl values from EEPROM */
+       rt2800_bbp_read(rt2x00dev, 109, &bbp);
+       rt2x00_set_field8(&bbp, BBP109_TX0_POWER, 0);
+       rt2x00_set_field8(&bbp, BBP109_TX1_POWER, 0);
+       rt2800_bbp_write(rt2x00dev, 109, bbp);
+
+       rt2800_bbp_read(rt2x00dev, 110, &bbp);
+       rt2x00_set_field8(&bbp, BBP110_TX2_POWER, 0);
+       rt2800_bbp_write(rt2x00dev, 110, bbp);
+
+       if (rf->channel <= 14) {
+               /* Restore BBP 25 & 26 for 2.4 GHz */
+               rt2800_bbp_write(rt2x00dev, 25, drv_data->bbp25);
+               rt2800_bbp_write(rt2x00dev, 26, drv_data->bbp26);
+       } else {
+               /* Hard code BBP 25 & 26 for 5GHz */
+
+               /* Enable IQ Phase correction */
+               rt2800_bbp_write(rt2x00dev, 25, 0x09);
+               /* Setup IQ Phase correction value */
+               rt2800_bbp_write(rt2x00dev, 26, 0xff);
+       }
+
+       rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1);
+       rt2800_rfcsr_write(rt2x00dev, 9, rf->rf3 & 0xf);
+
+       rt2800_rfcsr_read(rt2x00dev, 11, &rfcsr);
+       rt2x00_set_field8(&rfcsr, RFCSR11_R, (rf->rf2 & 0x3));
+       rt2800_rfcsr_write(rt2x00dev, 11, rfcsr);
+
+       rt2800_rfcsr_read(rt2x00dev, 11, &rfcsr);
+       rt2x00_set_field8(&rfcsr, RFCSR11_PLL_IDOH, 1);
+       if (rf->channel <= 14)
+               rt2x00_set_field8(&rfcsr, RFCSR11_PLL_MOD, 1);
+       else
+               rt2x00_set_field8(&rfcsr, RFCSR11_PLL_MOD, 2);
+       rt2800_rfcsr_write(rt2x00dev, 11, rfcsr);
+
+       rt2800_rfcsr_read(rt2x00dev, 53, &rfcsr);
+       if (rf->channel <= 14) {
+               rfcsr = 0;
+               rt2x00_set_field8(&rfcsr, RFCSR53_TX_POWER,
+                                 info->default_power1 & 0x1f);
+       } else {
+               if (rt2x00_is_usb(rt2x00dev))
+                       rfcsr = 0x40;
+
+               rt2x00_set_field8(&rfcsr, RFCSR53_TX_POWER,
+                                 ((info->default_power1 & 0x18) << 1) |
+                                 (info->default_power1 & 7));
+       }
+       rt2800_rfcsr_write(rt2x00dev, 53, rfcsr);
+
+       rt2800_rfcsr_read(rt2x00dev, 55, &rfcsr);
+       if (rf->channel <= 14) {
+               rfcsr = 0;
+               rt2x00_set_field8(&rfcsr, RFCSR55_TX_POWER,
+                                 info->default_power2 & 0x1f);
+       } else {
+               if (rt2x00_is_usb(rt2x00dev))
+                       rfcsr = 0x40;
+
+               rt2x00_set_field8(&rfcsr, RFCSR55_TX_POWER,
+                                 ((info->default_power2 & 0x18) << 1) |
+                                 (info->default_power2 & 7));
+       }
+       rt2800_rfcsr_write(rt2x00dev, 55, rfcsr);
+
+       rt2800_rfcsr_read(rt2x00dev, 54, &rfcsr);
+       if (rf->channel <= 14) {
+               rfcsr = 0;
+               rt2x00_set_field8(&rfcsr, RFCSR54_TX_POWER,
+                                 info->default_power3 & 0x1f);
+       } else {
+               if (rt2x00_is_usb(rt2x00dev))
+                       rfcsr = 0x40;
+
+               rt2x00_set_field8(&rfcsr, RFCSR54_TX_POWER,
+                                 ((info->default_power3 & 0x18) << 1) |
+                                 (info->default_power3 & 7));
+       }
+       rt2800_rfcsr_write(rt2x00dev, 54, rfcsr);
+
+       rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr);
+       rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 0);
+       rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 0);
+       rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 0);
+       rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 0);
+       rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, 0);
+       rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, 0);
+       rt2x00_set_field8(&rfcsr, RFCSR1_RF_BLOCK_EN, 1);
+       rt2x00_set_field8(&rfcsr, RFCSR1_PLL_PD, 1);
+
+       switch (rt2x00dev->default_ant.tx_chain_num) {
+       case 3:
+               rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, 1);
+               /* fallthrough */
+       case 2:
+               rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 1);
+               /* fallthrough */
+       case 1:
+               rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 1);
+               break;
+       }
+
+       switch (rt2x00dev->default_ant.rx_chain_num) {
+       case 3:
+               rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, 1);
+               /* fallthrough */
+       case 2:
+               rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 1);
+               /* fallthrough */
+       case 1:
+               rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 1);
+               break;
+       }
+       rt2800_rfcsr_write(rt2x00dev, 1, rfcsr);
+
+       /* TODO: frequency calibration? */
+
+       if (conf_is_ht40(conf)) {
+               txrx_agc_fc = rt2x00_get_field8(drv_data->calibration_bw40,
+                                               RFCSR24_TX_AGC_FC);
+               txrx_h20m = rt2x00_get_field8(drv_data->calibration_bw40,
+                                             RFCSR24_TX_H20M);
+       } else {
+               txrx_agc_fc = rt2x00_get_field8(drv_data->calibration_bw20,
+                                               RFCSR24_TX_AGC_FC);
+               txrx_h20m = rt2x00_get_field8(drv_data->calibration_bw20,
+                                             RFCSR24_TX_H20M);
+       }
+
+       /* NOTE: the reference driver does not writes the new value
+        * back to RFCSR 32
+        */
+       rt2800_rfcsr_read(rt2x00dev, 32, &rfcsr);
+       rt2x00_set_field8(&rfcsr, RFCSR32_TX_AGC_FC, txrx_agc_fc);
+
+       if (rf->channel <= 14)
+               rfcsr = 0xa0;
+       else
+               rfcsr = 0x80;
+       rt2800_rfcsr_write(rt2x00dev, 31, rfcsr);
+
+       rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr);
+       rt2x00_set_field8(&rfcsr, RFCSR30_TX_H20M, txrx_h20m);
+       rt2x00_set_field8(&rfcsr, RFCSR30_RX_H20M, txrx_h20m);
+       rt2800_rfcsr_write(rt2x00dev, 30, rfcsr);
+
+       /* Band selection */
+       rt2800_rfcsr_read(rt2x00dev, 36, &rfcsr);
+       if (rf->channel <= 14)
+               rt2x00_set_field8(&rfcsr, RFCSR36_RF_BS, 1);
+       else
+               rt2x00_set_field8(&rfcsr, RFCSR36_RF_BS, 0);
+       rt2800_rfcsr_write(rt2x00dev, 36, rfcsr);
+
+       rt2800_rfcsr_read(rt2x00dev, 34, &rfcsr);
+       if (rf->channel <= 14)
+               rfcsr = 0x3c;
+       else
+               rfcsr = 0x20;
+       rt2800_rfcsr_write(rt2x00dev, 34, rfcsr);
+
+       rt2800_rfcsr_read(rt2x00dev, 12, &rfcsr);
+       if (rf->channel <= 14)
+               rfcsr = 0x1a;
+       else
+               rfcsr = 0x12;
+       rt2800_rfcsr_write(rt2x00dev, 12, rfcsr);
+
+       rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr);
+       if (rf->channel >= 1 && rf->channel <= 14)
+               rt2x00_set_field8(&rfcsr, RFCSR6_VCO_IC, 1);
+       else if (rf->channel >= 36 && rf->channel <= 64)
+               rt2x00_set_field8(&rfcsr, RFCSR6_VCO_IC, 2);
+       else if (rf->channel >= 100 && rf->channel <= 128)
+               rt2x00_set_field8(&rfcsr, RFCSR6_VCO_IC, 2);
+       else
+               rt2x00_set_field8(&rfcsr, RFCSR6_VCO_IC, 1);
+       rt2800_rfcsr_write(rt2x00dev, 6, rfcsr);
+
+       rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr);
+       rt2x00_set_field8(&rfcsr, RFCSR30_RX_VCM, 2);
+       rt2800_rfcsr_write(rt2x00dev, 30, rfcsr);
+
+       rt2800_rfcsr_write(rt2x00dev, 46, 0x60);
+
+       if (rf->channel <= 14) {
+               rt2800_rfcsr_write(rt2x00dev, 10, 0xd3);
+               rt2800_rfcsr_write(rt2x00dev, 13, 0x12);
+       } else {
+               rt2800_rfcsr_write(rt2x00dev, 10, 0xd8);
+               rt2800_rfcsr_write(rt2x00dev, 13, 0x23);
+       }
+
+       rt2800_rfcsr_read(rt2x00dev, 51, &rfcsr);
+       rt2x00_set_field8(&rfcsr, RFCSR51_BITS01, 1);
+       rt2800_rfcsr_write(rt2x00dev, 51, rfcsr);
+
+       rt2800_rfcsr_read(rt2x00dev, 51, &rfcsr);
+       if (rf->channel <= 14) {
+               rt2x00_set_field8(&rfcsr, RFCSR51_BITS24, 5);
+               rt2x00_set_field8(&rfcsr, RFCSR51_BITS57, 3);
+       } else {
+               rt2x00_set_field8(&rfcsr, RFCSR51_BITS24, 4);
+               rt2x00_set_field8(&rfcsr, RFCSR51_BITS57, 2);
+       }
+       rt2800_rfcsr_write(rt2x00dev, 51, rfcsr);
+
+       rt2800_rfcsr_read(rt2x00dev, 49, &rfcsr);
+       if (rf->channel <= 14)
+               rt2x00_set_field8(&rfcsr, RFCSR49_TX_LO1_IC, 3);
+       else
+               rt2x00_set_field8(&rfcsr, RFCSR49_TX_LO1_IC, 2);
+
+       if (txbf_enabled)
+               rt2x00_set_field8(&rfcsr, RFCSR49_TX_DIV, 1);
+
+       rt2800_rfcsr_write(rt2x00dev, 49, rfcsr);
+
+       rt2800_rfcsr_read(rt2x00dev, 50, &rfcsr);
+       rt2x00_set_field8(&rfcsr, RFCSR50_TX_LO1_EN, 0);
+       rt2800_rfcsr_write(rt2x00dev, 50, rfcsr);
+
+       rt2800_rfcsr_read(rt2x00dev, 57, &rfcsr);
+       if (rf->channel <= 14)
+               rt2x00_set_field8(&rfcsr, RFCSR57_DRV_CC, 0x1b);
+       else
+               rt2x00_set_field8(&rfcsr, RFCSR57_DRV_CC, 0x0f);
+       rt2800_rfcsr_write(rt2x00dev, 57, rfcsr);
+
+       if (rf->channel <= 14) {
+               rt2800_rfcsr_write(rt2x00dev, 44, 0x93);
+               rt2800_rfcsr_write(rt2x00dev, 52, 0x45);
+       } else {
+               rt2800_rfcsr_write(rt2x00dev, 44, 0x9b);
+               rt2800_rfcsr_write(rt2x00dev, 52, 0x05);
+       }
+
+       /* Initiate VCO calibration */
+       rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr);
+       if (rf->channel <= 14) {
+               rt2x00_set_field8(&rfcsr, RFCSR3_VCOCAL_EN, 1);
+       } else {
+               rt2x00_set_field8(&rfcsr, RFCSR3_BIT1, 1);
+               rt2x00_set_field8(&rfcsr, RFCSR3_BIT2, 1);
+               rt2x00_set_field8(&rfcsr, RFCSR3_BIT3, 1);
+               rt2x00_set_field8(&rfcsr, RFCSR3_BIT4, 1);
+               rt2x00_set_field8(&rfcsr, RFCSR3_BIT5, 1);
+               rt2x00_set_field8(&rfcsr, RFCSR3_VCOCAL_EN, 1);
+       }
+       rt2800_rfcsr_write(rt2x00dev, 3, rfcsr);
+
+       if (rf->channel >= 1 && rf->channel <= 14) {
+               rfcsr = 0x23;
+               if (txbf_enabled)
+                       rt2x00_set_field8(&rfcsr, RFCSR39_RX_DIV, 1);
+               rt2800_rfcsr_write(rt2x00dev, 39, rfcsr);
+
+               rt2800_rfcsr_write(rt2x00dev, 45, 0xbb);
+       } else if (rf->channel >= 36 && rf->channel <= 64) {
+               rfcsr = 0x36;
+               if (txbf_enabled)
+                       rt2x00_set_field8(&rfcsr, RFCSR39_RX_DIV, 1);
+               rt2800_rfcsr_write(rt2x00dev, 39, 0x36);
+
+               rt2800_rfcsr_write(rt2x00dev, 45, 0xeb);
+       } else if (rf->channel >= 100 && rf->channel <= 128) {
+               rfcsr = 0x32;
+               if (txbf_enabled)
+                       rt2x00_set_field8(&rfcsr, RFCSR39_RX_DIV, 1);
+               rt2800_rfcsr_write(rt2x00dev, 39, rfcsr);
+
+               rt2800_rfcsr_write(rt2x00dev, 45, 0xb3);
+       } else {
+               rfcsr = 0x30;
+               if (txbf_enabled)
+                       rt2x00_set_field8(&rfcsr, RFCSR39_RX_DIV, 1);
+               rt2800_rfcsr_write(rt2x00dev, 39, rfcsr);
+
+               rt2800_rfcsr_write(rt2x00dev, 45, 0x9b);
+       }
+}
+
 #define POWER_BOUND            0x27
 #define POWER_BOUND_5G         0x2b
 #define FREQ_OFFSET_BOUND      0x5f
@@ -2563,6 +3035,23 @@ static void rt2800_iq_calibrate(struct rt2x00_dev *rt2x00dev, int channel)
        rt2800_bbp_write(rt2x00dev, 159, cal != 0xff ? cal : 0);
 }
 
+static char rt2800_txpower_to_dev(struct rt2x00_dev *rt2x00dev,
+                                 unsigned int channel,
+                                 char txpower)
+{
+       if (rt2x00_rt(rt2x00dev, RT3593))
+               txpower = rt2x00_get_field8(txpower, EEPROM_TXPOWER_ALC);
+
+       if (channel <= 14)
+               return clamp_t(char, txpower, MIN_G_TXPOWER, MAX_G_TXPOWER);
+
+       if (rt2x00_rt(rt2x00dev, RT3593))
+               return clamp_t(char, txpower, MIN_A_TXPOWER_3593,
+                              MAX_A_TXPOWER_3593);
+       else
+               return clamp_t(char, txpower, MIN_A_TXPOWER, MAX_A_TXPOWER);
+}
+
 static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
                                  struct ieee80211_conf *conf,
                                  struct rf_channel *rf,
@@ -2572,13 +3061,14 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
        unsigned int tx_pin;
        u8 bbp, rfcsr;
 
-       if (rf->channel <= 14) {
-               info->default_power1 = TXPOWER_G_TO_DEV(info->default_power1);
-               info->default_power2 = TXPOWER_G_TO_DEV(info->default_power2);
-       } else {
-               info->default_power1 = TXPOWER_A_TO_DEV(info->default_power1);
-               info->default_power2 = TXPOWER_A_TO_DEV(info->default_power2);
-       }
+       info->default_power1 = rt2800_txpower_to_dev(rt2x00dev, rf->channel,
+                                                    info->default_power1);
+       info->default_power2 = rt2800_txpower_to_dev(rt2x00dev, rf->channel,
+                                                    info->default_power2);
+       if (rt2x00dev->default_ant.tx_chain_num > 2)
+               info->default_power3 =
+                       rt2800_txpower_to_dev(rt2x00dev, rf->channel,
+                                             info->default_power3);
 
        switch (rt2x00dev->chip.rf) {
        case RF2020:
@@ -2591,6 +3081,9 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
        case RF3052:
                rt2800_config_channel_rf3052(rt2x00dev, conf, rf, info);
                break;
+       case RF3053:
+               rt2800_config_channel_rf3053(rt2x00dev, conf, rf, info);
+               break;
        case RF3290:
                rt2800_config_channel_rf3290(rt2x00dev, conf, rf, info);
                break;
@@ -2636,6 +3129,23 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
                rt2800_bbp_write(rt2x00dev, 66, 0x26 + rt2x00dev->lna_gain);
                rt2800_bbp_write(rt2x00dev, 27, 0x20);
                rt2800_bbp_write(rt2x00dev, 66, 0x26 + rt2x00dev->lna_gain);
+       } else if (rt2x00_rt(rt2x00dev, RT3593)) {
+               if (rf->channel > 14) {
+                       /* Disable CCK Packet detection on 5GHz */
+                       rt2800_bbp_write(rt2x00dev, 70, 0x00);
+               } else {
+                       rt2800_bbp_write(rt2x00dev, 70, 0x0a);
+               }
+
+               if (conf_is_ht40(conf))
+                       rt2800_bbp_write(rt2x00dev, 105, 0x04);
+               else
+                       rt2800_bbp_write(rt2x00dev, 105, 0x34);
+
+               rt2800_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain);
+               rt2800_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain);
+               rt2800_bbp_write(rt2x00dev, 64, 0x37 - rt2x00dev->lna_gain);
+               rt2800_bbp_write(rt2x00dev, 77, 0x98);
        } else {
                rt2800_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain);
                rt2800_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain);
@@ -2651,16 +3161,27 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
                                rt2800_bbp_write(rt2x00dev, 82, 0x62);
                                rt2800_bbp_write(rt2x00dev, 75, 0x46);
                        } else {
-                               rt2800_bbp_write(rt2x00dev, 82, 0x84);
+                               if (rt2x00_rt(rt2x00dev, RT3593))
+                                       rt2800_bbp_write(rt2x00dev, 82, 0x62);
+                               else
+                                       rt2800_bbp_write(rt2x00dev, 82, 0x84);
                                rt2800_bbp_write(rt2x00dev, 75, 0x50);
                        }
+                       if (rt2x00_rt(rt2x00dev, RT3593))
+                               rt2800_bbp_write(rt2x00dev, 83, 0x8a);
                }
+
        } else {
                if (rt2x00_rt(rt2x00dev, RT3572))
                        rt2800_bbp_write(rt2x00dev, 82, 0x94);
+               else if (rt2x00_rt(rt2x00dev, RT3593))
+                       rt2800_bbp_write(rt2x00dev, 82, 0x82);
                else
                        rt2800_bbp_write(rt2x00dev, 82, 0xf2);
 
+               if (rt2x00_rt(rt2x00dev, RT3593))
+                       rt2800_bbp_write(rt2x00dev, 83, 0x9a);
+
                if (test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags))
                        rt2800_bbp_write(rt2x00dev, 75, 0x46);
                else
@@ -2731,6 +3252,41 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
        if (rt2x00_rt(rt2x00dev, RT3572))
                rt2800_rfcsr_write(rt2x00dev, 8, 0x80);
 
+       if (rt2x00_rt(rt2x00dev, RT3593)) {
+               if (rt2x00_is_usb(rt2x00dev)) {
+                       rt2800_register_read(rt2x00dev, GPIO_CTRL, &reg);
+
+                       /* Band selection. GPIO #8 controls all paths */
+                       rt2x00_set_field32(&reg, GPIO_CTRL_DIR8, 0);
+                       if (rf->channel <= 14)
+                               rt2x00_set_field32(&reg, GPIO_CTRL_VAL8, 1);
+                       else
+                               rt2x00_set_field32(&reg, GPIO_CTRL_VAL8, 0);
+
+                       rt2x00_set_field32(&reg, GPIO_CTRL_DIR4, 0);
+                       rt2x00_set_field32(&reg, GPIO_CTRL_DIR7, 0);
+
+                       /* LNA PE control.
+                       * GPIO #4 controls PE0 and PE1,
+                       * GPIO #7 controls PE2
+                       */
+                       rt2x00_set_field32(&reg, GPIO_CTRL_VAL4, 1);
+                       rt2x00_set_field32(&reg, GPIO_CTRL_VAL7, 1);
+
+                       rt2800_register_write(rt2x00dev, GPIO_CTRL, reg);
+               }
+
+               /* AGC init */
+               if (rf->channel <= 14)
+                       reg = 0x1c + 2 * rt2x00dev->lna_gain;
+               else
+                       reg = 0x22 + ((rt2x00dev->lna_gain * 5) / 3);
+
+               rt2800_bbp_write_with_rx_chain(rt2x00dev, 66, reg);
+
+               usleep_range(1000, 1500);
+       }
+
        if (rt2x00_rt(rt2x00dev, RT5592)) {
                rt2800_bbp_write(rt2x00dev, 195, 141);
                rt2800_bbp_write(rt2x00dev, 196, conf_is_ht40(conf) ? 0x10 : 0x1a);
@@ -2798,62 +3354,62 @@ static int rt2800_get_gain_calibration_delta(struct rt2x00_dev *rt2x00dev)
         * Example TSSI bounds  0xF0 0xD0 0xB5 0xA0 0x88 0x45 0x25 0x15 0x00
         */
        if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) {
-               rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG1, &eeprom);
+               rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG1, &eeprom);
                tssi_bounds[0] = rt2x00_get_field16(eeprom,
                                        EEPROM_TSSI_BOUND_BG1_MINUS4);
                tssi_bounds[1] = rt2x00_get_field16(eeprom,
                                        EEPROM_TSSI_BOUND_BG1_MINUS3);
 
-               rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG2, &eeprom);
+               rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG2, &eeprom);
                tssi_bounds[2] = rt2x00_get_field16(eeprom,
                                        EEPROM_TSSI_BOUND_BG2_MINUS2);
                tssi_bounds[3] = rt2x00_get_field16(eeprom,
                                        EEPROM_TSSI_BOUND_BG2_MINUS1);
 
-               rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG3, &eeprom);
+               rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG3, &eeprom);
                tssi_bounds[4] = rt2x00_get_field16(eeprom,
                                        EEPROM_TSSI_BOUND_BG3_REF);
                tssi_bounds[5] = rt2x00_get_field16(eeprom,
                                        EEPROM_TSSI_BOUND_BG3_PLUS1);
 
-               rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG4, &eeprom);
+               rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG4, &eeprom);
                tssi_bounds[6] = rt2x00_get_field16(eeprom,
                                        EEPROM_TSSI_BOUND_BG4_PLUS2);
                tssi_bounds[7] = rt2x00_get_field16(eeprom,
                                        EEPROM_TSSI_BOUND_BG4_PLUS3);
 
-               rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG5, &eeprom);
+               rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG5, &eeprom);
                tssi_bounds[8] = rt2x00_get_field16(eeprom,
                                        EEPROM_TSSI_BOUND_BG5_PLUS4);
 
                step = rt2x00_get_field16(eeprom,
                                          EEPROM_TSSI_BOUND_BG5_AGC_STEP);
        } else {
-               rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A1, &eeprom);
+               rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A1, &eeprom);
                tssi_bounds[0] = rt2x00_get_field16(eeprom,
                                        EEPROM_TSSI_BOUND_A1_MINUS4);
                tssi_bounds[1] = rt2x00_get_field16(eeprom,
                                        EEPROM_TSSI_BOUND_A1_MINUS3);
 
-               rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A2, &eeprom);
+               rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A2, &eeprom);
                tssi_bounds[2] = rt2x00_get_field16(eeprom,
                                        EEPROM_TSSI_BOUND_A2_MINUS2);
                tssi_bounds[3] = rt2x00_get_field16(eeprom,
                                        EEPROM_TSSI_BOUND_A2_MINUS1);
 
-               rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A3, &eeprom);
+               rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A3, &eeprom);
                tssi_bounds[4] = rt2x00_get_field16(eeprom,
                                        EEPROM_TSSI_BOUND_A3_REF);
                tssi_bounds[5] = rt2x00_get_field16(eeprom,
                                        EEPROM_TSSI_BOUND_A3_PLUS1);
 
-               rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A4, &eeprom);
+               rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A4, &eeprom);
                tssi_bounds[6] = rt2x00_get_field16(eeprom,
                                        EEPROM_TSSI_BOUND_A4_PLUS2);
                tssi_bounds[7] = rt2x00_get_field16(eeprom,
                                        EEPROM_TSSI_BOUND_A4_PLUS3);
 
-               rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A5, &eeprom);
+               rt2800_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A5, &eeprom);
                tssi_bounds[8] = rt2x00_get_field16(eeprom,
                                        EEPROM_TSSI_BOUND_A5_PLUS4);
 
@@ -2899,7 +3455,7 @@ static int rt2800_get_txpower_bw_comp(struct rt2x00_dev *rt2x00dev,
        u8 comp_type;
        int comp_value = 0;
 
-       rt2x00_eeprom_read(rt2x00dev, EEPROM_TXPOWER_DELTA, &eeprom);
+       rt2800_eeprom_read(rt2x00dev, EEPROM_TXPOWER_DELTA, &eeprom);
 
        /*
         * HT40 compensation not required.
@@ -2966,6 +3522,9 @@ static u8 rt2800_compensate_txpower(struct rt2x00_dev *rt2x00dev, int is_rate_b,
        u8 eirp_txpower_criterion;
        u8 reg_limit;
 
+       if (rt2x00_rt(rt2x00dev, RT3593))
+               return min_t(u8, txpower, 0xc);
+
        if (test_bit(CAPABILITY_POWER_LIMIT, &rt2x00dev->cap_flags)) {
                /*
                 * Check if eirp txpower exceed txpower_limit.
@@ -2974,12 +3533,12 @@ static u8 rt2800_compensate_txpower(struct rt2x00_dev *rt2x00dev, int is_rate_b,
                 * .11b data rate need add additional 4dbm
                 * when calculating eirp txpower.
                 */
-               rt2x00_eeprom_read(rt2x00dev, EEPROM_TXPOWER_BYRATE + 1,
-                                  &eeprom);
+               rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE,
+                                             1, &eeprom);
                criterion = rt2x00_get_field16(eeprom,
                                               EEPROM_TXPOWER_BYRATE_RATE0);
 
-               rt2x00_eeprom_read(rt2x00dev, EEPROM_EIRP_MAX_TX_POWER,
+               rt2800_eeprom_read(rt2x00dev, EEPROM_EIRP_MAX_TX_POWER,
                                   &eeprom);
 
                if (band == IEEE80211_BAND_2GHZ)
@@ -3001,6 +3560,412 @@ static u8 rt2800_compensate_txpower(struct rt2x00_dev *rt2x00dev, int is_rate_b,
        return min_t(u8, txpower, 0xc);
 }
 
+
+enum {
+       TX_PWR_CFG_0_IDX,
+       TX_PWR_CFG_1_IDX,
+       TX_PWR_CFG_2_IDX,
+       TX_PWR_CFG_3_IDX,
+       TX_PWR_CFG_4_IDX,
+       TX_PWR_CFG_5_IDX,
+       TX_PWR_CFG_6_IDX,
+       TX_PWR_CFG_7_IDX,
+       TX_PWR_CFG_8_IDX,
+       TX_PWR_CFG_9_IDX,
+       TX_PWR_CFG_0_EXT_IDX,
+       TX_PWR_CFG_1_EXT_IDX,
+       TX_PWR_CFG_2_EXT_IDX,
+       TX_PWR_CFG_3_EXT_IDX,
+       TX_PWR_CFG_4_EXT_IDX,
+       TX_PWR_CFG_IDX_COUNT,
+};
+
+static void rt2800_config_txpower_rt3593(struct rt2x00_dev *rt2x00dev,
+                                        struct ieee80211_channel *chan,
+                                        int power_level)
+{
+       u8 txpower;
+       u16 eeprom;
+       u32 regs[TX_PWR_CFG_IDX_COUNT];
+       unsigned int offset;
+       enum ieee80211_band band = chan->band;
+       int delta;
+       int i;
+
+       memset(regs, '\0', sizeof(regs));
+
+       /* TODO: adapt TX power reduction from the rt28xx code */
+
+       /* calculate temperature compensation delta */
+       delta = rt2800_get_gain_calibration_delta(rt2x00dev);
+
+       if (band == IEEE80211_BAND_5GHZ)
+               offset = 16;
+       else
+               offset = 0;
+
+       if (test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags))
+               offset += 8;
+
+       /* read the next four txpower values */
+       rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE,
+                                     offset, &eeprom);
+
+       /* CCK 1MBS,2MBS */
+       txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0);
+       txpower = rt2800_compensate_txpower(rt2x00dev, 1, band, power_level,
+                                           txpower, delta);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_0_IDX],
+                          TX_PWR_CFG_0_CCK1_CH0, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_0_IDX],
+                          TX_PWR_CFG_0_CCK1_CH1, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_0_EXT_IDX],
+                          TX_PWR_CFG_0_EXT_CCK1_CH2, txpower);
+
+       /* CCK 5.5MBS,11MBS */
+       txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE1);
+       txpower = rt2800_compensate_txpower(rt2x00dev, 1, band, power_level,
+                                           txpower, delta);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_0_IDX],
+                          TX_PWR_CFG_0_CCK5_CH0, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_0_IDX],
+                          TX_PWR_CFG_0_CCK5_CH1, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_0_EXT_IDX],
+                          TX_PWR_CFG_0_EXT_CCK5_CH2, txpower);
+
+       /* OFDM 6MBS,9MBS */
+       txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE2);
+       txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+                                           txpower, delta);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_0_IDX],
+                          TX_PWR_CFG_0_OFDM6_CH0, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_0_IDX],
+                          TX_PWR_CFG_0_OFDM6_CH1, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_0_EXT_IDX],
+                          TX_PWR_CFG_0_EXT_OFDM6_CH2, txpower);
+
+       /* OFDM 12MBS,18MBS */
+       txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE3);
+       txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+                                           txpower, delta);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_0_IDX],
+                          TX_PWR_CFG_0_OFDM12_CH0, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_0_IDX],
+                          TX_PWR_CFG_0_OFDM12_CH1, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_0_EXT_IDX],
+                          TX_PWR_CFG_0_EXT_OFDM12_CH2, txpower);
+
+       /* read the next four txpower values */
+       rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE,
+                                     offset + 1, &eeprom);
+
+       /* OFDM 24MBS,36MBS */
+       txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0);
+       txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+                                           txpower, delta);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_1_IDX],
+                          TX_PWR_CFG_1_OFDM24_CH0, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_1_IDX],
+                          TX_PWR_CFG_1_OFDM24_CH1, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_1_EXT_IDX],
+                          TX_PWR_CFG_1_EXT_OFDM24_CH2, txpower);
+
+       /* OFDM 48MBS */
+       txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE1);
+       txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+                                           txpower, delta);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_1_IDX],
+                          TX_PWR_CFG_1_OFDM48_CH0, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_1_IDX],
+                          TX_PWR_CFG_1_OFDM48_CH1, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_1_EXT_IDX],
+                          TX_PWR_CFG_1_EXT_OFDM48_CH2, txpower);
+
+       /* OFDM 54MBS */
+       txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE2);
+       txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+                                           txpower, delta);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_7_IDX],
+                          TX_PWR_CFG_7_OFDM54_CH0, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_7_IDX],
+                          TX_PWR_CFG_7_OFDM54_CH1, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_7_IDX],
+                          TX_PWR_CFG_7_OFDM54_CH2, txpower);
+
+       /* read the next four txpower values */
+       rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE,
+                                     offset + 2, &eeprom);
+
+       /* MCS 0,1 */
+       txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0);
+       txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+                                           txpower, delta);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_1_IDX],
+                          TX_PWR_CFG_1_MCS0_CH0, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_1_IDX],
+                          TX_PWR_CFG_1_MCS0_CH1, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_1_EXT_IDX],
+                          TX_PWR_CFG_1_EXT_MCS0_CH2, txpower);
+
+       /* MCS 2,3 */
+       txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE1);
+       txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+                                           txpower, delta);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_1_IDX],
+                          TX_PWR_CFG_1_MCS2_CH0, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_1_IDX],
+                          TX_PWR_CFG_1_MCS2_CH1, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_1_EXT_IDX],
+                          TX_PWR_CFG_1_EXT_MCS2_CH2, txpower);
+
+       /* MCS 4,5 */
+       txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE2);
+       txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+                                           txpower, delta);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_2_IDX],
+                          TX_PWR_CFG_2_MCS4_CH0, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_2_IDX],
+                          TX_PWR_CFG_2_MCS4_CH1, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_2_EXT_IDX],
+                          TX_PWR_CFG_2_EXT_MCS4_CH2, txpower);
+
+       /* MCS 6 */
+       txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE3);
+       txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+                                           txpower, delta);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_2_IDX],
+                          TX_PWR_CFG_2_MCS6_CH0, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_2_IDX],
+                          TX_PWR_CFG_2_MCS6_CH1, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_2_EXT_IDX],
+                          TX_PWR_CFG_2_EXT_MCS6_CH2, txpower);
+
+       /* read the next four txpower values */
+       rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE,
+                                     offset + 3, &eeprom);
+
+       /* MCS 7 */
+       txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0);
+       txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+                                           txpower, delta);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_7_IDX],
+                          TX_PWR_CFG_7_MCS7_CH0, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_7_IDX],
+                          TX_PWR_CFG_7_MCS7_CH1, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_7_IDX],
+                          TX_PWR_CFG_7_MCS7_CH2, txpower);
+
+       /* MCS 8,9 */
+       txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE1);
+       txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+                                           txpower, delta);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_2_IDX],
+                          TX_PWR_CFG_2_MCS8_CH0, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_2_IDX],
+                          TX_PWR_CFG_2_MCS8_CH1, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_2_EXT_IDX],
+                          TX_PWR_CFG_2_EXT_MCS8_CH2, txpower);
+
+       /* MCS 10,11 */
+       txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE2);
+       txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+                                           txpower, delta);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_2_IDX],
+                          TX_PWR_CFG_2_MCS10_CH0, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_2_IDX],
+                          TX_PWR_CFG_2_MCS10_CH1, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_2_EXT_IDX],
+                          TX_PWR_CFG_2_EXT_MCS10_CH2, txpower);
+
+       /* MCS 12,13 */
+       txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE3);
+       txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+                                           txpower, delta);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_3_IDX],
+                          TX_PWR_CFG_3_MCS12_CH0, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_3_IDX],
+                          TX_PWR_CFG_3_MCS12_CH1, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_3_EXT_IDX],
+                          TX_PWR_CFG_3_EXT_MCS12_CH2, txpower);
+
+       /* read the next four txpower values */
+       rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE,
+                                     offset + 4, &eeprom);
+
+       /* MCS 14 */
+       txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0);
+       txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+                                           txpower, delta);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_3_IDX],
+                          TX_PWR_CFG_3_MCS14_CH0, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_3_IDX],
+                          TX_PWR_CFG_3_MCS14_CH1, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_3_EXT_IDX],
+                          TX_PWR_CFG_3_EXT_MCS14_CH2, txpower);
+
+       /* MCS 15 */
+       txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE1);
+       txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+                                           txpower, delta);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_8_IDX],
+                          TX_PWR_CFG_8_MCS15_CH0, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_8_IDX],
+                          TX_PWR_CFG_8_MCS15_CH1, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_8_IDX],
+                          TX_PWR_CFG_8_MCS15_CH2, txpower);
+
+       /* MCS 16,17 */
+       txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE2);
+       txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+                                           txpower, delta);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_5_IDX],
+                          TX_PWR_CFG_5_MCS16_CH0, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_5_IDX],
+                          TX_PWR_CFG_5_MCS16_CH1, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_5_IDX],
+                          TX_PWR_CFG_5_MCS16_CH2, txpower);
+
+       /* MCS 18,19 */
+       txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE3);
+       txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+                                           txpower, delta);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_5_IDX],
+                          TX_PWR_CFG_5_MCS18_CH0, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_5_IDX],
+                          TX_PWR_CFG_5_MCS18_CH1, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_5_IDX],
+                          TX_PWR_CFG_5_MCS18_CH2, txpower);
+
+       /* read the next four txpower values */
+       rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE,
+                                     offset + 5, &eeprom);
+
+       /* MCS 20,21 */
+       txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0);
+       txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+                                           txpower, delta);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_6_IDX],
+                          TX_PWR_CFG_6_MCS20_CH0, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_6_IDX],
+                          TX_PWR_CFG_6_MCS20_CH1, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_6_IDX],
+                          TX_PWR_CFG_6_MCS20_CH2, txpower);
+
+       /* MCS 22 */
+       txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE1);
+       txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+                                           txpower, delta);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_6_IDX],
+                          TX_PWR_CFG_6_MCS22_CH0, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_6_IDX],
+                          TX_PWR_CFG_6_MCS22_CH1, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_6_IDX],
+                          TX_PWR_CFG_6_MCS22_CH2, txpower);
+
+       /* MCS 23 */
+       txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE2);
+       txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+                                           txpower, delta);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_8_IDX],
+                          TX_PWR_CFG_8_MCS23_CH0, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_8_IDX],
+                          TX_PWR_CFG_8_MCS23_CH1, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_8_IDX],
+                          TX_PWR_CFG_8_MCS23_CH2, txpower);
+
+       /* read the next four txpower values */
+       rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE,
+                                     offset + 6, &eeprom);
+
+       /* STBC, MCS 0,1 */
+       txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0);
+       txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+                                           txpower, delta);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_3_IDX],
+                          TX_PWR_CFG_3_STBC0_CH0, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_3_IDX],
+                          TX_PWR_CFG_3_STBC0_CH1, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_3_EXT_IDX],
+                          TX_PWR_CFG_3_EXT_STBC0_CH2, txpower);
+
+       /* STBC, MCS 2,3 */
+       txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE1);
+       txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+                                           txpower, delta);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_3_IDX],
+                          TX_PWR_CFG_3_STBC2_CH0, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_3_IDX],
+                          TX_PWR_CFG_3_STBC2_CH1, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_3_EXT_IDX],
+                          TX_PWR_CFG_3_EXT_STBC2_CH2, txpower);
+
+       /* STBC, MCS 4,5 */
+       txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE2);
+       txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+                                           txpower, delta);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_4_IDX], TX_PWR_CFG_RATE0, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_4_IDX], TX_PWR_CFG_RATE1, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_4_EXT_IDX], TX_PWR_CFG_RATE0,
+                          txpower);
+
+       /* STBC, MCS 6 */
+       txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE3);
+       txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+                                           txpower, delta);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_4_IDX], TX_PWR_CFG_RATE2, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_4_IDX], TX_PWR_CFG_RATE3, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_4_EXT_IDX], TX_PWR_CFG_RATE2,
+                          txpower);
+
+       /* read the next four txpower values */
+       rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE,
+                                     offset + 7, &eeprom);
+
+       /* STBC, MCS 7 */
+       txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0);
+       txpower = rt2800_compensate_txpower(rt2x00dev, 0, band, power_level,
+                                           txpower, delta);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_9_IDX],
+                          TX_PWR_CFG_9_STBC7_CH0, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_9_IDX],
+                          TX_PWR_CFG_9_STBC7_CH1, txpower);
+       rt2x00_set_field32(&regs[TX_PWR_CFG_9_IDX],
+                          TX_PWR_CFG_9_STBC7_CH2, txpower);
+
+       rt2800_register_write(rt2x00dev, TX_PWR_CFG_0, regs[TX_PWR_CFG_0_IDX]);
+       rt2800_register_write(rt2x00dev, TX_PWR_CFG_1, regs[TX_PWR_CFG_1_IDX]);
+       rt2800_register_write(rt2x00dev, TX_PWR_CFG_2, regs[TX_PWR_CFG_2_IDX]);
+       rt2800_register_write(rt2x00dev, TX_PWR_CFG_3, regs[TX_PWR_CFG_3_IDX]);
+       rt2800_register_write(rt2x00dev, TX_PWR_CFG_4, regs[TX_PWR_CFG_4_IDX]);
+       rt2800_register_write(rt2x00dev, TX_PWR_CFG_5, regs[TX_PWR_CFG_5_IDX]);
+       rt2800_register_write(rt2x00dev, TX_PWR_CFG_6, regs[TX_PWR_CFG_6_IDX]);
+       rt2800_register_write(rt2x00dev, TX_PWR_CFG_7, regs[TX_PWR_CFG_7_IDX]);
+       rt2800_register_write(rt2x00dev, TX_PWR_CFG_8, regs[TX_PWR_CFG_8_IDX]);
+       rt2800_register_write(rt2x00dev, TX_PWR_CFG_9, regs[TX_PWR_CFG_9_IDX]);
+
+       rt2800_register_write(rt2x00dev, TX_PWR_CFG_0_EXT,
+                             regs[TX_PWR_CFG_0_EXT_IDX]);
+       rt2800_register_write(rt2x00dev, TX_PWR_CFG_1_EXT,
+                             regs[TX_PWR_CFG_1_EXT_IDX]);
+       rt2800_register_write(rt2x00dev, TX_PWR_CFG_2_EXT,
+                             regs[TX_PWR_CFG_2_EXT_IDX]);
+       rt2800_register_write(rt2x00dev, TX_PWR_CFG_3_EXT,
+                             regs[TX_PWR_CFG_3_EXT_IDX]);
+       rt2800_register_write(rt2x00dev, TX_PWR_CFG_4_EXT,
+                             regs[TX_PWR_CFG_4_EXT_IDX]);
+
+       for (i = 0; i < TX_PWR_CFG_IDX_COUNT; i++)
+               rt2x00_dbg(rt2x00dev,
+                          "band:%cGHz, BW:%c0MHz, TX_PWR_CFG_%d%s = %08lx\n",
+                          (band == IEEE80211_BAND_5GHZ) ? '5' : '2',
+                          (test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags)) ?
+                                                               '4' : '2',
+                          (i > TX_PWR_CFG_9_IDX) ?
+                                       (i - TX_PWR_CFG_9_IDX - 1) : i,
+                          (i > TX_PWR_CFG_9_IDX) ? "_EXT" : "",
+                          (unsigned long) regs[i]);
+}
+
 /*
  * We configure transmit power using MAC TX_PWR_CFG_{0,...,N} registers and
  * BBP R1 register. TX_PWR_CFG_X allow to configure per rate TX power values,
@@ -3010,9 +3975,9 @@ static u8 rt2800_compensate_txpower(struct rt2x00_dev *rt2x00dev, int is_rate_b,
  * EEPROM_TXPOWER_BYRATE offset. We adjust them and BBP R1 settings according to
  * current conditions (i.e. band, bandwidth, temperature, user settings).
  */
-static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev,
-                                 struct ieee80211_channel *chan,
-                                 int power_level)
+static void rt2800_config_txpower_rt28xx(struct rt2x00_dev *rt2x00dev,
+                                        struct ieee80211_channel *chan,
+                                        int power_level)
 {
        u8 txpower, r1;
        u16 eeprom;
@@ -3080,8 +4045,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev,
                rt2800_register_read(rt2x00dev, offset, &reg);
 
                /* read the next four txpower values */
-               rt2x00_eeprom_read(rt2x00dev, EEPROM_TXPOWER_BYRATE + i,
-                                  &eeprom);
+               rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE,
+                                             i, &eeprom);
 
                is_rate_b = i ? 0 : 1;
                /*
@@ -3129,8 +4094,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev,
                rt2x00_set_field32(&reg, TX_PWR_CFG_RATE3, txpower);
 
                /* read the next four txpower values */
-               rt2x00_eeprom_read(rt2x00dev, EEPROM_TXPOWER_BYRATE + i + 1,
-                                  &eeprom);
+               rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_TXPOWER_BYRATE,
+                                             i + 1, &eeprom);
 
                is_rate_b = 0;
                /*
@@ -3184,6 +4149,16 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev,
        }
 }
 
+static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev,
+                                 struct ieee80211_channel *chan,
+                                 int power_level)
+{
+       if (rt2x00_rt(rt2x00dev, RT3593))
+               rt2800_config_txpower_rt3593(rt2x00dev, chan, power_level);
+       else
+               rt2800_config_txpower_rt28xx(rt2x00dev, chan, power_level);
+}
+
 void rt2800_gain_calibration(struct rt2x00_dev *rt2x00dev)
 {
        rt2800_config_txpower(rt2x00dev, rt2x00dev->hw->conf.chandef.chan,
@@ -3219,6 +4194,7 @@ void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev)
                rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1);
                rt2800_rfcsr_write(rt2x00dev, 7, rfcsr);
                break;
+       case RF3053:
        case RF3290:
        case RF5360:
        case RF5370:
@@ -3528,7 +4504,8 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
                if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
                    rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E) ||
                    rt2x00_rt_rev_lt(rt2x00dev, RT3390, REV_RT3390E)) {
-                       rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
+                       rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1,
+                                          &eeprom);
                        if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_DAC_TEST))
                                rt2800_register_write(rt2x00dev, TX_SW_CFG2,
                                                      0x0000002c);
@@ -3559,6 +4536,23 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
        } else if (rt2x00_rt(rt2x00dev, RT3572)) {
                rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
                rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
+       } else if (rt2x00_rt(rt2x00dev, RT3593)) {
+               rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000402);
+               rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000);
+               if (rt2x00_rt_rev_lt(rt2x00dev, RT3593, REV_RT3593E)) {
+                       rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1,
+                                          &eeprom);
+                       if (rt2x00_get_field16(eeprom,
+                                              EEPROM_NIC_CONF1_DAC_TEST))
+                               rt2800_register_write(rt2x00dev, TX_SW_CFG2,
+                                                     0x0000001f);
+                       else
+                               rt2800_register_write(rt2x00dev, TX_SW_CFG2,
+                                                     0x0000000f);
+               } else {
+                       rt2800_register_write(rt2x00dev, TX_SW_CFG2,
+                                             0x00000000);
+               }
        } else if (rt2x00_rt(rt2x00dev, RT5390) ||
                   rt2x00_rt(rt2x00dev, RT5392) ||
                   rt2x00_rt(rt2x00dev, RT5592)) {
@@ -3989,7 +4983,7 @@ static void rt2800_disable_unused_dac_adc(struct rt2x00_dev *rt2x00dev)
        u8 value;
 
        rt2800_bbp_read(rt2x00dev, 138, &value);
-       rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom);
+       rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom);
        if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) == 1)
                value |= 0x20;
        if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) == 1)
@@ -4332,6 +5326,22 @@ static void rt2800_init_bbp_3572(struct rt2x00_dev *rt2x00dev)
        rt2800_disable_unused_dac_adc(rt2x00dev);
 }
 
+static void rt2800_init_bbp_3593(struct rt2x00_dev *rt2x00dev)
+{
+       rt2800_init_bbp_early(rt2x00dev);
+
+       rt2800_bbp_write(rt2x00dev, 79, 0x13);
+       rt2800_bbp_write(rt2x00dev, 80, 0x05);
+       rt2800_bbp_write(rt2x00dev, 81, 0x33);
+       rt2800_bbp_write(rt2x00dev, 137, 0x0f);
+
+       rt2800_bbp_write(rt2x00dev, 84, 0x19);
+
+       /* Enable DC filter */
+       if (rt2x00_rt_rev_gte(rt2x00dev, RT3593, REV_RT3593E))
+               rt2800_bbp_write(rt2x00dev, 103, 0xc0);
+}
+
 static void rt2800_init_bbp_53xx(struct rt2x00_dev *rt2x00dev)
 {
        int ant, div_mode;
@@ -4402,7 +5412,7 @@ static void rt2800_init_bbp_53xx(struct rt2x00_dev *rt2x00dev)
 
        rt2800_disable_unused_dac_adc(rt2x00dev);
 
-       rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
+       rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
        div_mode = rt2x00_get_field16(eeprom,
                                      EEPROM_NIC_CONF1_ANT_DIVERSITY);
        ant = (div_mode == 3) ? 1 : 0;
@@ -4488,7 +5498,7 @@ static void rt2800_init_bbp_5592(struct rt2x00_dev *rt2x00dev)
 
        rt2800_bbp4_mac_if_ctrl(rt2x00dev);
 
-       rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
+       rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
        div_mode = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_ANT_DIVERSITY);
        ant = (div_mode == 3) ? 1 : 0;
        rt2800_bbp_read(rt2x00dev, 152, &value);
@@ -4547,6 +5557,9 @@ static void rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
        case RT3572:
                rt2800_init_bbp_3572(rt2x00dev);
                break;
+       case RT3593:
+               rt2800_init_bbp_3593(rt2x00dev);
+               return;
        case RT5390:
        case RT5392:
                rt2800_init_bbp_53xx(rt2x00dev);
@@ -4557,7 +5570,8 @@ static void rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
        }
 
        for (i = 0; i < EEPROM_BBP_SIZE; i++) {
-               rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom);
+               rt2800_eeprom_read_from_array(rt2x00dev, EEPROM_BBP_START, i,
+                                             &eeprom);
 
                if (eeprom != 0xffff && eeprom != 0x0000) {
                        reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID);
@@ -4728,7 +5742,7 @@ static void rt2800_normal_mode_setup_3xxx(struct rt2x00_dev *rt2x00dev)
        if (rt2x00_rt(rt2x00dev, RT3090)) {
                /*  Turn off unused DAC1 and ADC1 to reduce power consumption */
                rt2800_bbp_read(rt2x00dev, 138, &bbp);
-               rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom);
+               rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom);
                if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) == 1)
                        rt2x00_set_field8(&bbp, BBP138_RX_ADC1, 0);
                if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) == 1)
@@ -4771,6 +5785,42 @@ static void rt2800_normal_mode_setup_3xxx(struct rt2x00_dev *rt2x00dev)
        }
 }
 
+static void rt2800_normal_mode_setup_3593(struct rt2x00_dev *rt2x00dev)
+{
+       struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
+       u8 rfcsr;
+       u8 tx_gain;
+
+       rt2800_rfcsr_read(rt2x00dev, 50, &rfcsr);
+       rt2x00_set_field8(&rfcsr, RFCSR50_TX_LO2_EN, 0);
+       rt2800_rfcsr_write(rt2x00dev, 50, rfcsr);
+
+       rt2800_rfcsr_read(rt2x00dev, 51, &rfcsr);
+       tx_gain = rt2x00_get_field8(drv_data->txmixer_gain_24g,
+                                   RFCSR17_TXMIXER_GAIN);
+       rt2x00_set_field8(&rfcsr, RFCSR51_BITS24, tx_gain);
+       rt2800_rfcsr_write(rt2x00dev, 51, rfcsr);
+
+       rt2800_rfcsr_read(rt2x00dev, 38, &rfcsr);
+       rt2x00_set_field8(&rfcsr, RFCSR38_RX_LO1_EN, 0);
+       rt2800_rfcsr_write(rt2x00dev, 38, rfcsr);
+
+       rt2800_rfcsr_read(rt2x00dev, 39, &rfcsr);
+       rt2x00_set_field8(&rfcsr, RFCSR39_RX_LO2_EN, 0);
+       rt2800_rfcsr_write(rt2x00dev, 39, rfcsr);
+
+       rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr);
+       rt2x00_set_field8(&rfcsr, RFCSR1_RF_BLOCK_EN, 1);
+       rt2x00_set_field8(&rfcsr, RFCSR1_PLL_PD, 1);
+       rt2800_rfcsr_write(rt2x00dev, 1, rfcsr);
+
+       rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr);
+       rt2x00_set_field8(&rfcsr, RFCSR30_RX_VCM, 2);
+       rt2800_rfcsr_write(rt2x00dev, 30, rfcsr);
+
+       /* TODO: enable stream mode */
+}
+
 static void rt2800_normal_mode_setup_5xxx(struct rt2x00_dev *rt2x00dev)
 {
        u8 reg;
@@ -4778,7 +5828,7 @@ static void rt2800_normal_mode_setup_5xxx(struct rt2x00_dev *rt2x00dev)
 
        /*  Turn off unused DAC1 and ADC1 to reduce power consumption */
        rt2800_bbp_read(rt2x00dev, 138, &reg);
-       rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom);
+       rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom);
        if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) == 1)
                rt2x00_set_field8(&reg, BBP138_RX_ADC1, 0);
        if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) == 1)
@@ -4884,7 +5934,8 @@ static void rt2800_init_rfcsr_30xx(struct rt2x00_dev *rt2x00dev)
                rt2x00_set_field32(&reg, LDO_CFG0_BGSEL, 1);
                if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
                    rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E)) {
-                       rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
+                       rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1,
+                                          &eeprom);
                        if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_DAC_TEST))
                                rt2x00_set_field32(&reg, LDO_CFG0_LDO_CORE_VLEVEL, 3);
                        else
@@ -5152,6 +6203,136 @@ static void rt2800_init_rfcsr_3572(struct rt2x00_dev *rt2x00dev)
        rt2800_normal_mode_setup_3xxx(rt2x00dev);
 }
 
+static void rt3593_post_bbp_init(struct rt2x00_dev *rt2x00dev)
+{
+       u8 bbp;
+       bool txbf_enabled = false; /* FIXME */
+
+       rt2800_bbp_read(rt2x00dev, 105, &bbp);
+       if (rt2x00dev->default_ant.rx_chain_num == 1)
+               rt2x00_set_field8(&bbp, BBP105_MLD, 0);
+       else
+               rt2x00_set_field8(&bbp, BBP105_MLD, 1);
+       rt2800_bbp_write(rt2x00dev, 105, bbp);
+
+       rt2800_bbp4_mac_if_ctrl(rt2x00dev);
+
+       rt2800_bbp_write(rt2x00dev, 92, 0x02);
+       rt2800_bbp_write(rt2x00dev, 82, 0x82);
+       rt2800_bbp_write(rt2x00dev, 106, 0x05);
+       rt2800_bbp_write(rt2x00dev, 104, 0x92);
+       rt2800_bbp_write(rt2x00dev, 88, 0x90);
+       rt2800_bbp_write(rt2x00dev, 148, 0xc8);
+       rt2800_bbp_write(rt2x00dev, 47, 0x48);
+       rt2800_bbp_write(rt2x00dev, 120, 0x50);
+
+       if (txbf_enabled)
+               rt2800_bbp_write(rt2x00dev, 163, 0xbd);
+       else
+               rt2800_bbp_write(rt2x00dev, 163, 0x9d);
+
+       /* SNR mapping */
+       rt2800_bbp_write(rt2x00dev, 142, 6);
+       rt2800_bbp_write(rt2x00dev, 143, 160);
+       rt2800_bbp_write(rt2x00dev, 142, 7);
+       rt2800_bbp_write(rt2x00dev, 143, 161);
+       rt2800_bbp_write(rt2x00dev, 142, 8);
+       rt2800_bbp_write(rt2x00dev, 143, 162);
+
+       /* ADC/DAC control */
+       rt2800_bbp_write(rt2x00dev, 31, 0x08);
+
+       /* RX AGC energy lower bound in log2 */
+       rt2800_bbp_write(rt2x00dev, 68, 0x0b);
+
+       /* FIXME: BBP 105 owerwrite? */
+       rt2800_bbp_write(rt2x00dev, 105, 0x04);
+
+}
+
+static void rt2800_init_rfcsr_3593(struct rt2x00_dev *rt2x00dev)
+{
+       struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
+       u32 reg;
+       u8 rfcsr;
+
+       /* Disable GPIO #4 and #7 function for LAN PE control */
+       rt2800_register_read(rt2x00dev, GPIO_SWITCH, &reg);
+       rt2x00_set_field32(&reg, GPIO_SWITCH_4, 0);
+       rt2x00_set_field32(&reg, GPIO_SWITCH_7, 0);
+       rt2800_register_write(rt2x00dev, GPIO_SWITCH, reg);
+
+       /* Initialize default register values */
+       rt2800_rfcsr_write(rt2x00dev, 1, 0x03);
+       rt2800_rfcsr_write(rt2x00dev, 3, 0x80);
+       rt2800_rfcsr_write(rt2x00dev, 5, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 6, 0x40);
+       rt2800_rfcsr_write(rt2x00dev, 8, 0xf1);
+       rt2800_rfcsr_write(rt2x00dev, 9, 0x02);
+       rt2800_rfcsr_write(rt2x00dev, 10, 0xd3);
+       rt2800_rfcsr_write(rt2x00dev, 11, 0x40);
+       rt2800_rfcsr_write(rt2x00dev, 12, 0x4e);
+       rt2800_rfcsr_write(rt2x00dev, 13, 0x12);
+       rt2800_rfcsr_write(rt2x00dev, 18, 0x40);
+       rt2800_rfcsr_write(rt2x00dev, 22, 0x20);
+       rt2800_rfcsr_write(rt2x00dev, 30, 0x10);
+       rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
+       rt2800_rfcsr_write(rt2x00dev, 32, 0x78);
+       rt2800_rfcsr_write(rt2x00dev, 33, 0x3b);
+       rt2800_rfcsr_write(rt2x00dev, 34, 0x3c);
+       rt2800_rfcsr_write(rt2x00dev, 35, 0xe0);
+       rt2800_rfcsr_write(rt2x00dev, 38, 0x86);
+       rt2800_rfcsr_write(rt2x00dev, 39, 0x23);
+       rt2800_rfcsr_write(rt2x00dev, 44, 0xd3);
+       rt2800_rfcsr_write(rt2x00dev, 45, 0xbb);
+       rt2800_rfcsr_write(rt2x00dev, 46, 0x60);
+       rt2800_rfcsr_write(rt2x00dev, 49, 0x8e);
+       rt2800_rfcsr_write(rt2x00dev, 50, 0x86);
+       rt2800_rfcsr_write(rt2x00dev, 51, 0x75);
+       rt2800_rfcsr_write(rt2x00dev, 52, 0x45);
+       rt2800_rfcsr_write(rt2x00dev, 53, 0x18);
+       rt2800_rfcsr_write(rt2x00dev, 54, 0x18);
+       rt2800_rfcsr_write(rt2x00dev, 55, 0x18);
+       rt2800_rfcsr_write(rt2x00dev, 56, 0xdb);
+       rt2800_rfcsr_write(rt2x00dev, 57, 0x6e);
+
+       /* Initiate calibration */
+       /* TODO: use rt2800_rf_init_calibration ? */
+       rt2800_rfcsr_read(rt2x00dev, 2, &rfcsr);
+       rt2x00_set_field8(&rfcsr, RFCSR2_RESCAL_EN, 1);
+       rt2800_rfcsr_write(rt2x00dev, 2, rfcsr);
+
+       rt2800_adjust_freq_offset(rt2x00dev);
+
+       rt2800_rfcsr_read(rt2x00dev, 18, &rfcsr);
+       rt2x00_set_field8(&rfcsr, RFCSR18_XO_TUNE_BYPASS, 1);
+       rt2800_rfcsr_write(rt2x00dev, 18, rfcsr);
+
+       rt2800_register_read(rt2x00dev, LDO_CFG0, &reg);
+       rt2x00_set_field32(&reg, LDO_CFG0_LDO_CORE_VLEVEL, 3);
+       rt2x00_set_field32(&reg, LDO_CFG0_BGSEL, 1);
+       rt2800_register_write(rt2x00dev, LDO_CFG0, reg);
+       usleep_range(1000, 1500);
+       rt2800_register_read(rt2x00dev, LDO_CFG0, &reg);
+       rt2x00_set_field32(&reg, LDO_CFG0_LDO_CORE_VLEVEL, 0);
+       rt2800_register_write(rt2x00dev, LDO_CFG0, reg);
+
+       /* Set initial values for RX filter calibration */
+       drv_data->calibration_bw20 = 0x1f;
+       drv_data->calibration_bw40 = 0x2f;
+
+       /* Save BBP 25 & 26 values for later use in channel switching */
+       rt2800_bbp_read(rt2x00dev, 25, &drv_data->bbp25);
+       rt2800_bbp_read(rt2x00dev, 26, &drv_data->bbp26);
+
+       rt2800_led_open_drain_enable(rt2x00dev);
+       rt2800_normal_mode_setup_3593(rt2x00dev);
+
+       rt3593_post_bbp_init(rt2x00dev);
+
+       /* TODO: enable stream mode support */
+}
+
 static void rt2800_init_rfcsr_5390(struct rt2x00_dev *rt2x00dev)
 {
        rt2800_rf_init_calibration(rt2x00dev, 2);
@@ -5380,6 +6561,9 @@ static void rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
        case RT3572:
                rt2800_init_rfcsr_3572(rt2x00dev);
                break;
+       case RT3593:
+               rt2800_init_rfcsr_3593(rt2x00dev);
+               break;
        case RT5390:
                rt2800_init_rfcsr_5390(rt2x00dev);
                break;
@@ -5456,15 +6640,15 @@ int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev)
        /*
         * Initialize LED control
         */
-       rt2x00_eeprom_read(rt2x00dev, EEPROM_LED_AG_CONF, &word);
+       rt2800_eeprom_read(rt2x00dev, EEPROM_LED_AG_CONF, &word);
        rt2800_mcu_request(rt2x00dev, MCU_LED_AG_CONF, 0xff,
                           word & 0xff, (word >> 8) & 0xff);
 
-       rt2x00_eeprom_read(rt2x00dev, EEPROM_LED_ACT_CONF, &word);
+       rt2800_eeprom_read(rt2x00dev, EEPROM_LED_ACT_CONF, &word);
        rt2800_mcu_request(rt2x00dev, MCU_LED_ACT_CONF, 0xff,
                           word & 0xff, (word >> 8) & 0xff);
 
-       rt2x00_eeprom_read(rt2x00dev, EEPROM_LED_POLARITY, &word);
+       rt2800_eeprom_read(rt2x00dev, EEPROM_LED_POLARITY, &word);
        rt2800_mcu_request(rt2x00dev, MCU_LED_LED_POLARITY, 0xff,
                           word & 0xff, (word >> 8) & 0xff);
 
@@ -5560,6 +6744,34 @@ int rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
 }
 EXPORT_SYMBOL_GPL(rt2800_read_eeprom_efuse);
 
+static u8 rt2800_get_txmixer_gain_24g(struct rt2x00_dev *rt2x00dev)
+{
+       u16 word;
+
+       if (rt2x00_rt(rt2x00dev, RT3593))
+               return 0;
+
+       rt2800_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_BG, &word);
+       if ((word & 0x00ff) != 0x00ff)
+               return rt2x00_get_field16(word, EEPROM_TXMIXER_GAIN_BG_VAL);
+
+       return 0;
+}
+
+static u8 rt2800_get_txmixer_gain_5g(struct rt2x00_dev *rt2x00dev)
+{
+       u16 word;
+
+       if (rt2x00_rt(rt2x00dev, RT3593))
+               return 0;
+
+       rt2800_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_A, &word);
+       if ((word & 0x00ff) != 0x00ff)
+               return rt2x00_get_field16(word, EEPROM_TXMIXER_GAIN_A_VAL);
+
+       return 0;
+}
+
 static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
 {
        struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
@@ -5578,18 +6790,18 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
        /*
         * Start validation of the data that has been read.
         */
-       mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
+       mac = rt2800_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
        if (!is_valid_ether_addr(mac)) {
                eth_random_addr(mac);
                rt2x00_eeprom_dbg(rt2x00dev, "MAC: %pM\n", mac);
        }
 
-       rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &word);
+       rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &word);
        if (word == 0xffff) {
                rt2x00_set_field16(&word, EEPROM_NIC_CONF0_RXPATH, 2);
                rt2x00_set_field16(&word, EEPROM_NIC_CONF0_TXPATH, 1);
                rt2x00_set_field16(&word, EEPROM_NIC_CONF0_RF_TYPE, RF2820);
-               rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC_CONF0, word);
+               rt2800_eeprom_write(rt2x00dev, EEPROM_NIC_CONF0, word);
                rt2x00_eeprom_dbg(rt2x00dev, "Antenna: 0x%04x\n", word);
        } else if (rt2x00_rt(rt2x00dev, RT2860) ||
                   rt2x00_rt(rt2x00dev, RT2872)) {
@@ -5598,10 +6810,10 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
                 */
                if (rt2x00_get_field16(word, EEPROM_NIC_CONF0_RXPATH) > 2)
                        rt2x00_set_field16(&word, EEPROM_NIC_CONF0_RXPATH, 2);
-               rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC_CONF0, word);
+               rt2800_eeprom_write(rt2x00dev, EEPROM_NIC_CONF0, word);
        }
 
-       rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &word);
+       rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &word);
        if (word == 0xffff) {
                rt2x00_set_field16(&word, EEPROM_NIC_CONF1_HW_RADIO, 0);
                rt2x00_set_field16(&word, EEPROM_NIC_CONF1_EXTERNAL_TX_ALC, 0);
@@ -5618,24 +6830,24 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
                rt2x00_set_field16(&word, EEPROM_NIC_CONF1_INTERNAL_TX_ALC, 0);
                rt2x00_set_field16(&word, EEPROM_NIC_CONF1_BT_COEXIST, 0);
                rt2x00_set_field16(&word, EEPROM_NIC_CONF1_DAC_TEST, 0);
-               rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC_CONF1, word);
+               rt2800_eeprom_write(rt2x00dev, EEPROM_NIC_CONF1, word);
                rt2x00_eeprom_dbg(rt2x00dev, "NIC: 0x%04x\n", word);
        }
 
-       rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word);
+       rt2800_eeprom_read(rt2x00dev, EEPROM_FREQ, &word);
        if ((word & 0x00ff) == 0x00ff) {
                rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0);
-               rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word);
+               rt2800_eeprom_write(rt2x00dev, EEPROM_FREQ, word);
                rt2x00_eeprom_dbg(rt2x00dev, "Freq: 0x%04x\n", word);
        }
        if ((word & 0xff00) == 0xff00) {
                rt2x00_set_field16(&word, EEPROM_FREQ_LED_MODE,
                                   LED_MODE_TXRX_ACTIVITY);
                rt2x00_set_field16(&word, EEPROM_FREQ_LED_POLARITY, 0);
-               rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word);
-               rt2x00_eeprom_write(rt2x00dev, EEPROM_LED_AG_CONF, 0x5555);
-               rt2x00_eeprom_write(rt2x00dev, EEPROM_LED_ACT_CONF, 0x2221);
-               rt2x00_eeprom_write(rt2x00dev, EEPROM_LED_POLARITY, 0xa9f8);
+               rt2800_eeprom_write(rt2x00dev, EEPROM_FREQ, word);
+               rt2800_eeprom_write(rt2x00dev, EEPROM_LED_AG_CONF, 0x5555);
+               rt2800_eeprom_write(rt2x00dev, EEPROM_LED_ACT_CONF, 0x2221);
+               rt2800_eeprom_write(rt2x00dev, EEPROM_LED_POLARITY, 0xa9f8);
                rt2x00_eeprom_dbg(rt2x00dev, "Led Mode: 0x%04x\n", word);
        }
 
@@ -5644,56 +6856,61 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
         * lna0 as correct value. Note that EEPROM_LNA
         * is never validated.
         */
-       rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &word);
+       rt2800_eeprom_read(rt2x00dev, EEPROM_LNA, &word);
        default_lna_gain = rt2x00_get_field16(word, EEPROM_LNA_A0);
 
-       rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &word);
+       rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &word);
        if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET0)) > 10)
                rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET0, 0);
        if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET1)) > 10)
                rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET1, 0);
-       rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_BG, word);
+       rt2800_eeprom_write(rt2x00dev, EEPROM_RSSI_BG, word);
 
-       rt2x00_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_BG, &word);
-       if ((word & 0x00ff) != 0x00ff) {
-               drv_data->txmixer_gain_24g =
-                       rt2x00_get_field16(word, EEPROM_TXMIXER_GAIN_BG_VAL);
-       } else {
-               drv_data->txmixer_gain_24g = 0;
-       }
+       drv_data->txmixer_gain_24g = rt2800_get_txmixer_gain_24g(rt2x00dev);
 
-       rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &word);
+       rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &word);
        if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG2_OFFSET2)) > 10)
                rt2x00_set_field16(&word, EEPROM_RSSI_BG2_OFFSET2, 0);
-       if (rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0x00 ||
-           rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0xff)
-               rt2x00_set_field16(&word, EEPROM_RSSI_BG2_LNA_A1,
-                                  default_lna_gain);
-       rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_BG2, word);
-
-       rt2x00_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_A, &word);
-       if ((word & 0x00ff) != 0x00ff) {
-               drv_data->txmixer_gain_5g =
-                       rt2x00_get_field16(word, EEPROM_TXMIXER_GAIN_A_VAL);
-       } else {
-               drv_data->txmixer_gain_5g = 0;
+       if (!rt2x00_rt(rt2x00dev, RT3593)) {
+               if (rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0x00 ||
+                   rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0xff)
+                       rt2x00_set_field16(&word, EEPROM_RSSI_BG2_LNA_A1,
+                                          default_lna_gain);
        }
+       rt2800_eeprom_write(rt2x00dev, EEPROM_RSSI_BG2, word);
+
+       drv_data->txmixer_gain_5g = rt2800_get_txmixer_gain_5g(rt2x00dev);
 
-       rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A, &word);
+       rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A, &word);
        if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET0)) > 10)
                rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET0, 0);
        if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET1)) > 10)
                rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET1, 0);
-       rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A, word);
+       rt2800_eeprom_write(rt2x00dev, EEPROM_RSSI_A, word);
 
-       rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &word);
+       rt2800_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &word);
        if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A2_OFFSET2)) > 10)
                rt2x00_set_field16(&word, EEPROM_RSSI_A2_OFFSET2, 0);
-       if (rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0x00 ||
-           rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0xff)
-               rt2x00_set_field16(&word, EEPROM_RSSI_A2_LNA_A2,
-                                  default_lna_gain);
-       rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A2, word);
+       if (!rt2x00_rt(rt2x00dev, RT3593)) {
+               if (rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0x00 ||
+                   rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0xff)
+                       rt2x00_set_field16(&word, EEPROM_RSSI_A2_LNA_A2,
+                                          default_lna_gain);
+       }
+       rt2800_eeprom_write(rt2x00dev, EEPROM_RSSI_A2, word);
+
+       if (rt2x00_rt(rt2x00dev, RT3593)) {
+               rt2800_eeprom_read(rt2x00dev, EEPROM_EXT_LNA2, &word);
+               if (rt2x00_get_field16(word, EEPROM_EXT_LNA2_A1) == 0x00 ||
+                   rt2x00_get_field16(word, EEPROM_EXT_LNA2_A1) == 0xff)
+                       rt2x00_set_field16(&word, EEPROM_EXT_LNA2_A1,
+                                          default_lna_gain);
+               if (rt2x00_get_field16(word, EEPROM_EXT_LNA2_A2) == 0x00 ||
+                   rt2x00_get_field16(word, EEPROM_EXT_LNA2_A2) == 0xff)
+                       rt2x00_set_field16(&word, EEPROM_EXT_LNA2_A1,
+                                          default_lna_gain);
+               rt2800_eeprom_write(rt2x00dev, EEPROM_EXT_LNA2, word);
+       }
 
        return 0;
 }
@@ -5707,7 +6924,7 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
        /*
         * Read EEPROM word for configuration.
         */
-       rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom);
+       rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom);
 
        /*
         * Identify RF chipset by EEPROM value
@@ -5717,7 +6934,7 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
        if (rt2x00_rt(rt2x00dev, RT3290) ||
            rt2x00_rt(rt2x00dev, RT5390) ||
            rt2x00_rt(rt2x00dev, RT5392))
-               rt2x00_eeprom_read(rt2x00dev, EEPROM_CHIP_ID, &rf);
+               rt2800_eeprom_read(rt2x00dev, EEPROM_CHIP_ID, &rf);
        else
                rf = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RF_TYPE);
 
@@ -5731,6 +6948,7 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
        case RF3021:
        case RF3022:
        case RF3052:
+       case RF3053:
        case RF3290:
        case RF3320:
        case RF3322:
@@ -5757,7 +6975,7 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
        rt2x00dev->default_ant.rx_chain_num =
            rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH);
 
-       rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
+       rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
 
        if (rt2x00_rt(rt2x00dev, RT3070) ||
            rt2x00_rt(rt2x00dev, RT3090) ||
@@ -5810,7 +7028,7 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
        /*
         * Read frequency offset and RF programming sequence.
         */
-       rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom);
+       rt2800_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom);
        rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET);
 
        /*
@@ -5827,7 +7045,7 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
        /*
         * Check if support EIRP tx power limit feature.
         */
-       rt2x00_eeprom_read(rt2x00dev, EEPROM_EIRP_MAX_TX_POWER, &eeprom);
+       rt2800_eeprom_read(rt2x00dev, EEPROM_EIRP_MAX_TX_POWER, &eeprom);
 
        if (rt2x00_get_field16(eeprom, EEPROM_EIRP_MAX_TX_POWER_2GHZ) <
                                        EIRP_MAX_TX_POWER_LIMIT)
@@ -6109,12 +7327,79 @@ static const struct rf_channel rf_vals_5592_xtal40[] = {
        {196, 83, 0, 12, 1},
 };
 
+static const struct rf_channel rf_vals_3053[] = {
+       /* Channel, N, R, K */
+       {1, 241, 2, 2},
+       {2, 241, 2, 7},
+       {3, 242, 2, 2},
+       {4, 242, 2, 7},
+       {5, 243, 2, 2},
+       {6, 243, 2, 7},
+       {7, 244, 2, 2},
+       {8, 244, 2, 7},
+       {9, 245, 2, 2},
+       {10, 245, 2, 7},
+       {11, 246, 2, 2},
+       {12, 246, 2, 7},
+       {13, 247, 2, 2},
+       {14, 248, 2, 4},
+
+       {36, 0x56, 0, 4},
+       {38, 0x56, 0, 6},
+       {40, 0x56, 0, 8},
+       {44, 0x57, 0, 0},
+       {46, 0x57, 0, 2},
+       {48, 0x57, 0, 4},
+       {52, 0x57, 0, 8},
+       {54, 0x57, 0, 10},
+       {56, 0x58, 0, 0},
+       {60, 0x58, 0, 4},
+       {62, 0x58, 0, 6},
+       {64, 0x58, 0, 8},
+
+       {100, 0x5B, 0, 8},
+       {102, 0x5B, 0, 10},
+       {104, 0x5C, 0, 0},
+       {108, 0x5C, 0, 4},
+       {110, 0x5C, 0, 6},
+       {112, 0x5C, 0, 8},
+
+       /* NOTE: Channel 114 has been removed intentionally.
+        * The EEPROM contains no TX power values for that,
+        * and it is disabled in the vendor driver as well.
+        */
+
+       {116, 0x5D, 0, 0},
+       {118, 0x5D, 0, 2},
+       {120, 0x5D, 0, 4},
+       {124, 0x5D, 0, 8},
+       {126, 0x5D, 0, 10},
+       {128, 0x5E, 0, 0},
+       {132, 0x5E, 0, 4},
+       {134, 0x5E, 0, 6},
+       {136, 0x5E, 0, 8},
+       {140, 0x5F, 0, 0},
+
+       {149, 0x5F, 0, 9},
+       {151, 0x5F, 0, 11},
+       {153, 0x60, 0, 1},
+       {157, 0x60, 0, 5},
+       {159, 0x60, 0, 7},
+       {161, 0x60, 0, 9},
+       {165, 0x61, 0, 1},
+       {167, 0x61, 0, 3},
+       {169, 0x61, 0, 5},
+       {171, 0x61, 0, 7},
+       {173, 0x61, 0, 9},
+};
+
 static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 {
        struct hw_mode_spec *spec = &rt2x00dev->spec;
        struct channel_info *info;
        char *default_power1;
        char *default_power2;
+       char *default_power3;
        unsigned int i;
        u16 eeprom;
        u32 reg;
@@ -6148,7 +7433,7 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 
        SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
        SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
-                               rt2x00_eeprom_addr(rt2x00dev,
+                               rt2800_eeprom_addr(rt2x00dev,
                                                   EEPROM_MAC_ADDR_0));
 
        /*
@@ -6164,7 +7449,7 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        rt2x00dev->hw->max_report_rates = 7;
        rt2x00dev->hw->max_rate_tries = 1;
 
-       rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom);
+       rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom);
 
        /*
         * Initialize hw_mode information.
@@ -6199,6 +7484,10 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
                spec->supported_bands |= SUPPORT_BAND_5GHZ;
                spec->num_channels = ARRAY_SIZE(rf_vals_3x);
                spec->channels = rf_vals_3x;
+       } else if (rt2x00_rf(rt2x00dev, RF3053)) {
+               spec->supported_bands |= SUPPORT_BAND_5GHZ;
+               spec->num_channels = ARRAY_SIZE(rf_vals_3053);
+               spec->channels = rf_vals_3053;
        } else if (rt2x00_rf(rt2x00dev, RF5592)) {
                spec->supported_bands |= SUPPORT_BAND_5GHZ;
 
@@ -6264,21 +7553,40 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 
        spec->channels_info = info;
 
-       default_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1);
-       default_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2);
+       default_power1 = rt2800_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1);
+       default_power2 = rt2800_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2);
+
+       if (rt2x00dev->default_ant.tx_chain_num > 2)
+               default_power3 = rt2800_eeprom_addr(rt2x00dev,
+                                                   EEPROM_EXT_TXPOWER_BG3);
+       else
+               default_power3 = NULL;
 
        for (i = 0; i < 14; i++) {
                info[i].default_power1 = default_power1[i];
                info[i].default_power2 = default_power2[i];
+               if (default_power3)
+                       info[i].default_power3 = default_power3[i];
        }
 
        if (spec->num_channels > 14) {
-               default_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A1);
-               default_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A2);
+               default_power1 = rt2800_eeprom_addr(rt2x00dev,
+                                                   EEPROM_TXPOWER_A1);
+               default_power2 = rt2800_eeprom_addr(rt2x00dev,
+                                                   EEPROM_TXPOWER_A2);
+
+               if (rt2x00dev->default_ant.tx_chain_num > 2)
+                       default_power3 =
+                               rt2800_eeprom_addr(rt2x00dev,
+                                                  EEPROM_EXT_TXPOWER_A3);
+               else
+                       default_power3 = NULL;
 
                for (i = 14; i < spec->num_channels; i++) {
                        info[i].default_power1 = default_power1[i - 14];
                        info[i].default_power2 = default_power2[i - 14];
+                       if (default_power3)
+                               info[i].default_power3 = default_power3[i - 14];
                }
        }
 
@@ -6289,6 +7597,7 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        case RF3022:
        case RF3320:
        case RF3052:
+       case RF3053:
        case RF3290:
        case RF5360:
        case RF5370:
@@ -6327,6 +7636,7 @@ static int rt2800_probe_rt(struct rt2x00_dev *rt2x00dev)
        case RT3352:
        case RT3390:
        case RT3572:
+       case RT3593:
        case RT5390:
        case RT5392:
        case RT5592:
index 840833b26bfaeeda520a5ce29fba81bf839af284..fc9efdfca8f2eda014e4e4391d0bc295a61afb12 100644 (file)
@@ -854,7 +854,10 @@ static void rt2800usb_queue_init(struct data_queue *queue)
        struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
        unsigned short txwi_size, rxwi_size;
 
-       if (rt2x00_rt(rt2x00dev, RT5592)) {
+       if (rt2x00_rt(rt2x00dev, RT3593)) {
+               txwi_size = TXWI_DESC_SIZE_4WORDS;
+               rxwi_size = RXWI_DESC_SIZE_5WORDS;
+       } else if (rt2x00_rt(rt2x00dev, RT5592)) {
                txwi_size = TXWI_DESC_SIZE_5WORDS;
                rxwi_size = RXWI_DESC_SIZE_6WORDS;
        } else {
@@ -1194,6 +1197,40 @@ static struct usb_device_id rt2800usb_device_table[] = {
        /* Zinwell */
        { USB_DEVICE(0x5a57, 0x0284) },
 #endif
+#ifdef CONFIG_RT2800USB_RT3573
+       /* AirLive */
+       { USB_DEVICE(0x1b75, 0x7733) },
+       /* ASUS */
+       { USB_DEVICE(0x0b05, 0x17bc) },
+       { USB_DEVICE(0x0b05, 0x17ad) },
+       /* Belkin */
+       { USB_DEVICE(0x050d, 0x1103) },
+       /* Cameo */
+       { USB_DEVICE(0x148f, 0xf301) },
+       /* Edimax */
+       { USB_DEVICE(0x7392, 0x7733) },
+       /* Hawking */
+       { USB_DEVICE(0x0e66, 0x0020) },
+       { USB_DEVICE(0x0e66, 0x0021) },
+       /* I-O DATA */
+       { USB_DEVICE(0x04bb, 0x094e) },
+       /* Linksys */
+       { USB_DEVICE(0x13b1, 0x003b) },
+       /* Logitec */
+       { USB_DEVICE(0x0789, 0x016b) },
+       /* NETGEAR */
+       { USB_DEVICE(0x0846, 0x9012) },
+       { USB_DEVICE(0x0846, 0x9019) },
+       /* Planex */
+       { USB_DEVICE(0x2019, 0xed19) },
+       /* Ralink */
+       { USB_DEVICE(0x148f, 0x3573) },
+       /* Sitecom */
+       { USB_DEVICE(0x0df6, 0x0067) },
+       { USB_DEVICE(0x0df6, 0x006a) },
+       /* ZyXEL */
+       { USB_DEVICE(0x0586, 0x3421) },
+#endif
 #ifdef CONFIG_RT2800USB_RT53XX
        /* Arcadyan */
        { USB_DEVICE(0x043e, 0x7a12) },
index ee3fc570b11d04b0a6531f182abb1113dcd9be93..fe4c572db52c2749317690b75ad4cc296aec5157 100644 (file)
@@ -211,6 +211,7 @@ struct channel_info {
        short max_power;
        short default_power1;
        short default_power2;
+       short default_power3;
 };
 
 /*
index 6c0a91ff963c6833bb7d325cac7954c7c10b41fc..aa95c6cf3545432bf93b0743af97900a91f55ec9 100644 (file)
@@ -936,13 +936,8 @@ void rt2x00queue_index_inc(struct queue_entry *entry, enum queue_index index)
        spin_unlock_irqrestore(&queue->index_lock, irqflags);
 }
 
-void rt2x00queue_pause_queue(struct data_queue *queue)
+void rt2x00queue_pause_queue_nocheck(struct data_queue *queue)
 {
-       if (!test_bit(DEVICE_STATE_PRESENT, &queue->rt2x00dev->flags) ||
-           !test_bit(QUEUE_STARTED, &queue->flags) ||
-           test_and_set_bit(QUEUE_PAUSED, &queue->flags))
-               return;
-
        switch (queue->qid) {
        case QID_AC_VO:
        case QID_AC_VI:
@@ -958,6 +953,15 @@ void rt2x00queue_pause_queue(struct data_queue *queue)
                break;
        }
 }
+void rt2x00queue_pause_queue(struct data_queue *queue)
+{
+       if (!test_bit(DEVICE_STATE_PRESENT, &queue->rt2x00dev->flags) ||
+           !test_bit(QUEUE_STARTED, &queue->flags) ||
+           test_and_set_bit(QUEUE_PAUSED, &queue->flags))
+               return;
+
+       rt2x00queue_pause_queue_nocheck(queue);
+}
 EXPORT_SYMBOL_GPL(rt2x00queue_pause_queue);
 
 void rt2x00queue_unpause_queue(struct data_queue *queue)
@@ -1019,7 +1023,7 @@ void rt2x00queue_stop_queue(struct data_queue *queue)
                return;
        }
 
-       rt2x00queue_pause_queue(queue);
+       rt2x00queue_pause_queue_nocheck(queue);
 
        queue->rt2x00dev->ops->lib->stop_queue(queue);
 
index 7253de3d8c6671c78e732b001e7270731465d039..c2ffce7a907c90cf3fcc01400f50f2850d371533 100644 (file)
@@ -1,27 +1,20 @@
-config RTLWIFI
-       tristate "Realtek wireless card support"
-       depends on MAC80211
-       select FW_LOADER
-       ---help---
-         This is common code for RTL8192CE/RTL8192CU/RTL8192SE/RTL8723AE
-         drivers.  This module does nothing by itself - the various front-end
-         drivers need to be enabled to support any desired devices.
-
-         If you choose to build as a module, it'll be called rtlwifi.
-
-config RTLWIFI_DEBUG
-       bool "Debugging output for rtlwifi driver family"
-       depends on RTLWIFI
+menuconfig RTL_CARDS
+       tristate "Realtek rtlwifi family of devices"
+       depends on MAC80211 && (PCI || USB)
        default y
        ---help---
-       To use the module option that sets the dynamic-debugging level for,
-       the front-end driver, this parameter must be "Y". For memory-limited
-       systems, choose "N". If in doubt, choose "Y".
+         This option will enable support for the Realtek mac80211-based
+         wireless drivers. Drivers rtl8192ce, rtl8192cu, rtl8192se, rtl8192de,
+         rtl8723eu, and rtl8188eu share some common code.
+
+if RTL_CARDS
 
 config RTL8192CE
        tristate "Realtek RTL8192CE/RTL8188CE Wireless Network Adapter"
-       depends on RTLWIFI && PCI
+       depends on PCI
        select RTL8192C_COMMON
+       select RTLWIFI
+       select RTLWIFI_PCI
        ---help---
        This is the driver for Realtek RTL8192CE/RTL8188CE 802.11n PCIe
        wireless network adapters.
@@ -30,7 +23,9 @@ config RTL8192CE
 
 config RTL8192SE
        tristate "Realtek RTL8192SE/RTL8191SE PCIe Wireless Network Adapter"
-       depends on RTLWIFI && PCI
+       depends on PCI
+       select RTLWIFI
+       select RTLWIFI_PCI
        ---help---
        This is the driver for Realtek RTL8192SE/RTL8191SE 802.11n PCIe
        wireless network adapters.
@@ -39,7 +34,9 @@ config RTL8192SE
 
 config RTL8192DE
        tristate "Realtek RTL8192DE/RTL8188DE PCIe Wireless Network Adapter"
-       depends on RTLWIFI && PCI
+       depends on PCI
+       select RTLWIFI
+       select RTLWIFI_PCI
        ---help---
        This is the driver for Realtek RTL8192DE/RTL8188DE 802.11n PCIe
        wireless network adapters.
@@ -48,7 +45,9 @@ config RTL8192DE
 
 config RTL8723AE
        tristate "Realtek RTL8723AE PCIe Wireless Network Adapter"
-       depends on RTLWIFI && PCI
+       depends on PCI
+       select RTLWIFI
+       select RTLWIFI_PCI
        ---help---
        This is the driver for Realtek RTL8723AE 802.11n PCIe
        wireless network adapters.
@@ -57,7 +56,9 @@ config RTL8723AE
 
 config RTL8188EE
        tristate "Realtek RTL8188EE Wireless Network Adapter"
-       depends on RTLWIFI && PCI
+       depends on PCI
+       select RTLWIFI
+       select RTLWIFI_PCI
        ---help---
        This is the driver for Realtek RTL8188EE 802.11n PCIe
        wireless network adapters.
@@ -66,7 +67,9 @@ config RTL8188EE
 
 config RTL8192CU
        tristate "Realtek RTL8192CU/RTL8188CU USB Wireless Network Adapter"
-       depends on RTLWIFI && USB
+       depends on USB
+       select RTLWIFI
+       select RTLWIFI_USB
        select RTL8192C_COMMON
        ---help---
        This is the driver for Realtek RTL8192CU/RTL8188CU 802.11n USB
@@ -74,7 +77,28 @@ config RTL8192CU
 
        If you choose to build it as a module, it will be called rtl8192cu
 
+config RTLWIFI
+       tristate
+       select FW_LOADER
+
+config RTLWIFI_PCI
+       tristate
+
+config RTLWIFI_USB
+       tristate
+
+config RTLWIFI_DEBUG
+       bool "Debugging output for rtlwifi driver family"
+       depends on RTLWIFI
+       default y
+       ---help---
+       To use the module option that sets the dynamic-debugging level for,
+       the front-end driver, this parameter must be "Y". For memory-limited
+       systems, choose "N". If in doubt, choose "Y".
+
 config RTL8192C_COMMON
        tristate
        depends on RTL8192CE || RTL8192CU
-       default m
+       default y
+
+endif
index ff02b874f8d87dfd15ff0205a6036e65c0b9ad5c..d56f023a4b90dfadabf45670b2f5c8d0ca1fa46d 100644 (file)
@@ -12,13 +12,11 @@ rtlwifi-objs        :=              \
 
 rtl8192c_common-objs +=                \
 
-ifneq ($(CONFIG_PCI),)
-rtlwifi-objs   += pci.o
-endif
+obj-$(CONFIG_RTLWIFI_PCI)      += rtl_pci.o
+rtl_pci-objs   :=              pci.o
 
-ifneq ($(CONFIG_USB),)
-rtlwifi-objs   += usb.o
-endif
+obj-$(CONFIG_RTLWIFI_USB)      += rtl_usb.o
+rtl_usb-objs   :=              usb.o
 
 obj-$(CONFIG_RTL8192C_COMMON)  += rtl8192c/
 obj-$(CONFIG_RTL8192CE)                += rtl8192ce/
index 9d558ac77b0c78b36ad6f6a31a49cf5aa4aae765..7651f5acc14bcccdc179fc09450af258f9d30e23 100644 (file)
@@ -172,6 +172,7 @@ u8 rtl_tid_to_ac(u8 tid)
 {
        return tid_to_ac[tid];
 }
+EXPORT_SYMBOL_GPL(rtl_tid_to_ac);
 
 static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw,
                                  struct ieee80211_sta_ht_cap *ht_cap)
@@ -406,6 +407,7 @@ void rtl_deinit_deferred_work(struct ieee80211_hw *hw)
        cancel_delayed_work(&rtlpriv->works.ps_rfon_wq);
        cancel_delayed_work(&rtlpriv->works.fwevt_wq);
 }
+EXPORT_SYMBOL_GPL(rtl_deinit_deferred_work);
 
 void rtl_init_rfkill(struct ieee80211_hw *hw)
 {
@@ -439,6 +441,7 @@ void rtl_deinit_rfkill(struct ieee80211_hw *hw)
 {
        wiphy_rfkill_stop_polling(hw->wiphy);
 }
+EXPORT_SYMBOL_GPL(rtl_deinit_rfkill);
 
 int rtl_init_core(struct ieee80211_hw *hw)
 {
@@ -489,10 +492,12 @@ int rtl_init_core(struct ieee80211_hw *hw)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(rtl_init_core);
 
 void rtl_deinit_core(struct ieee80211_hw *hw)
 {
 }
+EXPORT_SYMBOL_GPL(rtl_deinit_core);
 
 void rtl_init_rx_config(struct ieee80211_hw *hw)
 {
@@ -501,6 +506,7 @@ void rtl_init_rx_config(struct ieee80211_hw *hw)
 
        rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *) (&mac->rx_conf));
 }
+EXPORT_SYMBOL_GPL(rtl_init_rx_config);
 
 /*********************************************************
  *
@@ -879,6 +885,7 @@ bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb)
 
        return true;
 }
+EXPORT_SYMBOL_GPL(rtl_tx_mgmt_proc);
 
 void rtl_get_tcb_desc(struct ieee80211_hw *hw,
                      struct ieee80211_tx_info *info,
@@ -1052,6 +1059,7 @@ bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
 
        return true;
 }
+EXPORT_SYMBOL_GPL(rtl_action_proc);
 
 /*should call before software enc*/
 u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
@@ -1125,6 +1133,7 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
 
        return false;
 }
+EXPORT_SYMBOL_GPL(rtl_is_special_data);
 
 /*********************************************************
  *
@@ -1300,6 +1309,7 @@ void rtl_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb)
 
        rtlpriv->link_info.bcn_rx_inperiod++;
 }
+EXPORT_SYMBOL_GPL(rtl_beacon_statistic);
 
 void rtl_watchdog_wq_callback(void *data)
 {
@@ -1793,6 +1803,7 @@ void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len)
 
        mac->vendor = vendor;
 }
+EXPORT_SYMBOL_GPL(rtl_recognize_peer);
 
 /*********************************************************
  *
@@ -1849,6 +1860,7 @@ struct attribute_group rtl_attribute_group = {
        .name = "rtlsysfs",
        .attrs = rtl_sysfs_entries,
 };
+EXPORT_SYMBOL_GPL(rtl_attribute_group);
 
 MODULE_AUTHOR("lizhaoming      <chaoming_li@realsil.com.cn>");
 MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>");
@@ -1856,7 +1868,8 @@ MODULE_AUTHOR("Larry Finger       <Larry.FInger@lwfinger.net>");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Realtek 802.11n PCI wireless core");
 
-struct rtl_global_var global_var = {};
+struct rtl_global_var rtl_global_var = {};
+EXPORT_SYMBOL_GPL(rtl_global_var);
 
 static int __init rtl_core_module_init(void)
 {
@@ -1864,8 +1877,8 @@ static int __init rtl_core_module_init(void)
                pr_err("Unable to register rtl_rc, use default RC !!\n");
 
        /* init some global vars */
-       INIT_LIST_HEAD(&global_var.glb_priv_list);
-       spin_lock_init(&global_var.glb_list_lock);
+       INIT_LIST_HEAD(&rtl_global_var.glb_priv_list);
+       spin_lock_init(&rtl_global_var.glb_list_lock);
 
        return 0;
 }
index 8576bc34b03289ef077db41f5700e3a2eea5bf21..0e5fe0902daf6eb180a1da431ce54477e49486cb 100644 (file)
@@ -147,7 +147,7 @@ void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len);
 u8 rtl_tid_to_ac(u8 tid);
 extern struct attribute_group rtl_attribute_group;
 void rtl_easy_concurrent_retrytimer_callback(unsigned long data);
-extern struct rtl_global_var global_var;
+extern struct rtl_global_var rtl_global_var;
 int rtlwifi_rate_mapping(struct ieee80211_hw *hw,
                         bool isht, u8 desc_rate, bool first_ampdu);
 bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb);
index ee84844be0080c2e1bcef681f7e53a7f42f93125..733b7ce7f0e2a981f442cd9cdadd8f40a6426558 100644 (file)
@@ -1330,3 +1330,4 @@ const struct ieee80211_ops rtl_ops = {
        .rfkill_poll = rtl_op_rfkill_poll,
        .flush = rtl_op_flush,
 };
+EXPORT_SYMBOL_GPL(rtl_ops);
index 7d52d3d7769f0e357be0900ec0423dac70cb390c..76e2086e137e5f0356325887ecccc5c768d17f6c 100644 (file)
@@ -51,3 +51,4 @@ void rtl_dbgp_flag_init(struct ieee80211_hw *hw)
 
        /*Init Debug flag enable condition */
 }
+EXPORT_SYMBOL_GPL(rtl_dbgp_flag_init);
index 9e3894178e7773b3d6aca8a4cca70fc518fd6a96..838a1ed3f1942b9f3d56a122c2840548b38103c9 100644 (file)
@@ -229,6 +229,7 @@ void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf)
 
        *pbuf = (u8) (value32 & 0xff);
 }
+EXPORT_SYMBOL_GPL(read_efuse_byte);
 
 void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf)
 {
index c97e9d327331c8b25624327ec4d672c7289f4492..703f839af6ca0b4abefcfc754dc21eb3d13b2dac 100644 (file)
 #include "efuse.h"
 #include <linux/export.h>
 #include <linux/kmemleak.h>
+#include <linux/module.h>
+
+MODULE_AUTHOR("lizhaoming      <chaoming_li@realsil.com.cn>");
+MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>");
+MODULE_AUTHOR("Larry Finger    <Larry.FInger@lwfinger.net>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PCI basic driver for rtlwifi");
 
 static const u16 pcibridge_vendors[PCI_BRIDGE_VENDOR_MAX] = {
        PCI_VENDOR_ID_INTEL,
@@ -1008,19 +1015,6 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw)
        return;
 }
 
-static void rtl_lps_change_work_callback(struct work_struct *work)
-{
-       struct rtl_works *rtlworks =
-           container_of(work, struct rtl_works, lps_change_work);
-       struct ieee80211_hw *hw = rtlworks->hw;
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-
-       if (rtlpriv->enter_ps)
-               rtl_lps_enter(hw);
-       else
-               rtl_lps_leave(hw);
-}
-
 static void _rtl_pci_init_trx_var(struct ieee80211_hw *hw)
 {
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
@@ -1899,7 +1893,7 @@ int rtl_pci_probe(struct pci_dev *pdev,
        rtlpriv->rtlhal.interface = INTF_PCI;
        rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_data);
        rtlpriv->intf_ops = &rtl_pci_ops;
-       rtlpriv->glb_var = &global_var;
+       rtlpriv->glb_var = &rtl_global_var;
 
        /*
         *init dbgp flags before all
index 884bceae38a91d2b9ce4e07cf70c5c040e844df4..298b615964e861acb23c9ccd85e7b154854e9cda 100644 (file)
@@ -269,6 +269,7 @@ void rtl_ips_nic_on(struct ieee80211_hw *hw)
 
        spin_unlock_irqrestore(&rtlpriv->locks.ips_lock, flags);
 }
+EXPORT_SYMBOL_GPL(rtl_ips_nic_on);
 
 /*for FW LPS*/
 
@@ -518,6 +519,7 @@ void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len)
                         "u_bufferd: %x, m_buffered: %x\n", u_buffed, m_buffed);
        }
 }
+EXPORT_SYMBOL_GPL(rtl_swlps_beacon);
 
 void rtl_swlps_rf_awake(struct ieee80211_hw *hw)
 {
@@ -611,6 +613,19 @@ void rtl_swlps_rf_sleep(struct ieee80211_hw *hw)
                        MSECS(sleep_intv * mac->vif->bss_conf.beacon_int - 40));
 }
 
+void rtl_lps_change_work_callback(struct work_struct *work)
+{
+       struct rtl_works *rtlworks =
+           container_of(work, struct rtl_works, lps_change_work);
+       struct ieee80211_hw *hw = rtlworks->hw;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       if (rtlpriv->enter_ps)
+               rtl_lps_enter(hw);
+       else
+               rtl_lps_leave(hw);
+}
+EXPORT_SYMBOL_GPL(rtl_lps_change_work_callback);
 
 void rtl_swlps_wq_callback(void *data)
 {
@@ -922,3 +937,4 @@ void rtl_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len)
        else
                rtl_p2p_noa_ie(hw, data, len - FCS_LEN);
 }
+EXPORT_SYMBOL_GPL(rtl_p2p_info);
index 4d682b753f503df0f61b5e58b98e871f58c31029..88bd76ea88f7621dd92cb4ff495ee22e9dc53912 100644 (file)
@@ -49,5 +49,6 @@ void rtl_swlps_rf_awake(struct ieee80211_hw *hw);
 void rtl_swlps_rf_sleep(struct ieee80211_hw *hw);
 void rtl_p2p_ps_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state);
 void rtl_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len);
+void rtl_lps_change_work_callback(struct work_struct *work);
 
 #endif
index f9f059dadb734af694c992bb8634fe866d317a61..a98acefb8c06a3802290c9130de368b8effcab83 100644 (file)
@@ -218,6 +218,7 @@ static void rtl_tx_status(void *ppriv,
 
 static void rtl_rate_init(void *ppriv,
                          struct ieee80211_supported_band *sband,
+                         struct cfg80211_chan_def *chandef,
                          struct ieee80211_sta *sta, void *priv_sta)
 {
 }
index 8e3ec1e25644688c469a38f2e057bbf90a6558cb..0f7812e0c8aa0c75d5382c52b4872431447c8108 100644 (file)
@@ -109,5 +109,8 @@ void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus);
 void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw,
                         u8 element_id, u32 cmd_len, u8 *p_cmdbuffer);
 bool rtl92cu_phy_mac_config(struct ieee80211_hw *hw);
+void rtl92cu_update_hal_rate_tbl(struct ieee80211_hw *hw,
+                                struct ieee80211_sta *sta,
+                                u8 rssi_level);
 
 #endif
index 262e1e4c6e5b007065ed2e834e139446566bde6f..a1310abd0d54605e6bbd1a1cc9f9200bc3ecbe43 100644 (file)
@@ -49,8 +49,5 @@ bool rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw,
 u32 rtl92cu_phy_query_rf_reg(struct ieee80211_hw *hw,
                            enum radio_path rfpath, u32 regaddr, u32 bitmask);
 void rtl92cu_phy_set_bw_mode_callback(struct ieee80211_hw *hw);
-void rtl92cu_update_hal_rate_tbl(struct ieee80211_hw *hw,
-                                struct ieee80211_sta *sta,
-                                u8 rssi_level);
 
 #endif
index a3532e0778710ff5975a3c3fec4e21299e45e301..e56778cac9bfce39e56d5aa239e34f2fb1135ffb 100644 (file)
 #include "ps.h"
 #include "rtl8192c/fw_common.h"
 #include <linux/export.h>
+#include <linux/module.h>
+
+MODULE_AUTHOR("lizhaoming      <chaoming_li@realsil.com.cn>");
+MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>");
+MODULE_AUTHOR("Larry Finger    <Larry.FInger@lwfinger.net>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("USB basic driver for rtlwifi");
 
 #define        REALTEK_USB_VENQT_READ                  0xC0
 #define        REALTEK_USB_VENQT_WRITE                 0x40
@@ -1070,6 +1077,8 @@ int rtl_usb_probe(struct usb_interface *intf,
        spin_lock_init(&rtlpriv->locks.usb_lock);
        INIT_WORK(&rtlpriv->works.fill_h2c_cmd,
                  rtl_fill_h2c_cmd_work_callback);
+       INIT_WORK(&rtlpriv->works.lps_change_work,
+                 rtl_lps_change_work_callback);
 
        rtlpriv->usb_data_index = 0;
        init_completion(&rtlpriv->firmware_loading_complete);
index b8db55c868c7b0027e96bf28f7174a00a308eb0f..d1b19c38a907ddba1d5dfe4106e8caa2ce49315c 100644 (file)
@@ -1315,7 +1315,7 @@ static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
 
 #ifdef CONFIG_PM
 static int
-wl1271_validate_wowlan_pattern(struct cfg80211_wowlan_trig_pkt_pattern *p)
+wl1271_validate_wowlan_pattern(struct cfg80211_pkt_pattern *p)
 {
        int num_fields = 0, in_field = 0, fields_size = 0;
        int i, pattern_len = 0;
@@ -1458,9 +1458,9 @@ void wl1271_rx_filter_flatten_fields(struct wl12xx_rx_filter *filter,
  * Allocates an RX filter returned through f
  * which needs to be freed using rx_filter_free()
  */
-static int wl1271_convert_wowlan_pattern_to_rx_filter(
-       struct cfg80211_wowlan_trig_pkt_pattern *p,
-       struct wl12xx_rx_filter **f)
+static int
+wl1271_convert_wowlan_pattern_to_rx_filter(struct cfg80211_pkt_pattern *p,
+                                          struct wl12xx_rx_filter **f)
 {
        int i, j, ret = 0;
        struct wl12xx_rx_filter *filter;
@@ -1562,7 +1562,7 @@ static int wl1271_configure_wowlan(struct wl1271 *wl,
 
        /* Translate WoWLAN patterns into filters */
        for (i = 0; i < wow->n_patterns; i++) {
-               struct cfg80211_wowlan_trig_pkt_pattern *p;
+               struct cfg80211_pkt_pattern *p;
                struct wl12xx_rx_filter *filter = NULL;
 
                p = &wow->patterns[i];
index 13a633b1612e1786b9cdcb7f2eebece8b0a70dde..7bf3926aecc0d765af64f166cbeb871ea66ac127 100644 (file)
@@ -86,10 +86,6 @@ struct mvebu_sw_pci_bridge {
        u16 secondary_status;
        u16 membase;
        u16 memlimit;
-       u16 prefmembase;
-       u16 prefmemlimit;
-       u32 prefbaseupper;
-       u32 preflimitupper;
        u16 iobaseupper;
        u16 iolimitupper;
        u8 cappointer;
@@ -419,15 +415,7 @@ static int mvebu_sw_pci_bridge_read(struct mvebu_pcie_port *port,
                break;
 
        case PCI_PREF_MEMORY_BASE:
-               *value = (bridge->prefmemlimit << 16 | bridge->prefmembase);
-               break;
-
-       case PCI_PREF_BASE_UPPER32:
-               *value = bridge->prefbaseupper;
-               break;
-
-       case PCI_PREF_LIMIT_UPPER32:
-               *value = bridge->preflimitupper;
+               *value = 0;
                break;
 
        case PCI_IO_BASE_UPPER16:
@@ -501,19 +489,6 @@ static int mvebu_sw_pci_bridge_write(struct mvebu_pcie_port *port,
                mvebu_pcie_handle_membase_change(port);
                break;
 
-       case PCI_PREF_MEMORY_BASE:
-               bridge->prefmembase = value & 0xffff;
-               bridge->prefmemlimit = value >> 16;
-               break;
-
-       case PCI_PREF_BASE_UPPER32:
-               bridge->prefbaseupper = value;
-               break;
-
-       case PCI_PREF_LIMIT_UPPER32:
-               bridge->preflimitupper = value;
-               break;
-
        case PCI_IO_BASE_UPPER16:
                bridge->iobaseupper = value & 0xffff;
                bridge->iolimitupper = value >> 16;
index bb7ebb22db01e39a66840ba4684f811e7d89e075..d85009de713d647b9e3a81024776b6bdaf312754 100644 (file)
@@ -3,16 +3,13 @@
 #
 
 menuconfig HOTPLUG_PCI
-       tristate "Support for PCI Hotplug"
+       bool "Support for PCI Hotplug"
        depends on PCI && SYSFS
        ---help---
          Say Y here if you have a motherboard with a PCI Hotplug controller.
          This allows you to add and remove PCI cards while the machine is
          powered up and running.
 
-         To compile this driver as a module, choose M here: the
-         module will be called pci_hotplug.
-
          When in doubt, say N.
 
 if HOTPLUG_PCI
index 6fdd49c6f0b91760978139827511a02a7bb10e7d..f4e0289246672c0a9157927303945f0934e26d31 100644 (file)
@@ -49,6 +49,7 @@
 #define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
 #define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
 
+struct acpiphp_context;
 struct acpiphp_bridge;
 struct acpiphp_slot;
 
@@ -59,6 +60,7 @@ struct slot {
        struct hotplug_slot     *hotplug_slot;
        struct acpiphp_slot     *acpi_slot;
        struct hotplug_slot_info info;
+       unsigned int sun;       /* ACPI _SUN (Slot User Number) value */
 };
 
 static inline const char *slot_name(struct slot *slot)
@@ -75,15 +77,11 @@ struct acpiphp_bridge {
        struct list_head list;
        struct list_head slots;
        struct kref ref;
-       acpi_handle handle;
 
-       /* Ejectable PCI-to-PCI bridge (PCI bridge and PCI function) */
-       struct acpiphp_func *func;
+       struct acpiphp_context *context;
 
        int nr_slots;
 
-       u32 flags;
-
        /* This bus (host bridge) or Secondary bus (PCI-to-PCI bridge) */
        struct pci_bus *pci_bus;
 
@@ -99,15 +97,13 @@ struct acpiphp_bridge {
  */
 struct acpiphp_slot {
        struct list_head node;
-       struct acpiphp_bridge *bridge;  /* parent */
+       struct pci_bus *bus;
        struct list_head funcs;         /* one slot may have different
                                           objects (i.e. for each function) */
        struct slot *slot;
        struct mutex crit_sect;
 
        u8              device;         /* pci device# */
-
-       unsigned long long sun;         /* ACPI _SUN (slot unique number) */
        u32             flags;          /* see below */
 };
 
@@ -119,16 +115,32 @@ struct acpiphp_slot {
  * typically 8 objects per slot (i.e. for each PCI function)
  */
 struct acpiphp_func {
-       struct acpiphp_slot *slot;      /* parent */
+       struct acpiphp_bridge *parent;
+       struct acpiphp_slot *slot;
 
        struct list_head sibling;
-       struct notifier_block nb;
-       acpi_handle     handle;
 
        u8              function;       /* pci function# */
        u32             flags;          /* see below */
 };
 
+struct acpiphp_context {
+       acpi_handle handle;
+       struct acpiphp_func func;
+       struct acpiphp_bridge *bridge;
+       unsigned int refcount;
+};
+
+static inline struct acpiphp_context *func_to_context(struct acpiphp_func *func)
+{
+       return container_of(func, struct acpiphp_context, func);
+}
+
+static inline acpi_handle func_to_handle(struct acpiphp_func *func)
+{
+       return func_to_context(func)->handle;
+}
+
 /*
  * struct acpiphp_attention_info - device specific attention registration
  *
@@ -142,45 +154,32 @@ struct acpiphp_attention_info
        struct module *owner;
 };
 
-/* PCI bus bridge HID */
-#define ACPI_PCI_HOST_HID              "PNP0A03"
-
 /* ACPI _STA method value (ignore bit 4; battery present) */
 #define ACPI_STA_ALL                   (0x0000000f)
 
-/* bridge flags */
-#define BRIDGE_HAS_EJ0         (0x00000001)
-
 /* slot flags */
 
-#define SLOT_POWEREDON         (0x00000001)
-#define SLOT_ENABLED           (0x00000002)
-#define SLOT_MULTIFUNCTION     (0x00000004)
+#define SLOT_ENABLED           (0x00000001)
 
 /* function flags */
 
 #define FUNC_HAS_STA           (0x00000001)
 #define FUNC_HAS_EJ0           (0x00000002)
-#define FUNC_HAS_PS0           (0x00000010)
-#define FUNC_HAS_PS1           (0x00000020)
-#define FUNC_HAS_PS2           (0x00000040)
-#define FUNC_HAS_PS3           (0x00000080)
-#define FUNC_HAS_DCK            (0x00000100)
+#define FUNC_HAS_DCK            (0x00000004)
 
 /* function prototypes */
 
 /* acpiphp_core.c */
 int acpiphp_register_attention(struct acpiphp_attention_info*info);
 int acpiphp_unregister_attention(struct acpiphp_attention_info *info);
-int acpiphp_register_hotplug_slot(struct acpiphp_slot *slot);
+int acpiphp_register_hotplug_slot(struct acpiphp_slot *slot, unsigned int sun);
 void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *slot);
 
 /* acpiphp_glue.c */
 typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data);
 
 int acpiphp_enable_slot(struct acpiphp_slot *slot);
-int acpiphp_disable_slot(struct acpiphp_slot *slot);
-int acpiphp_eject_slot(struct acpiphp_slot *slot);
+int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot);
 u8 acpiphp_get_power_status(struct acpiphp_slot *slot);
 u8 acpiphp_get_attention_status(struct acpiphp_slot *slot);
 u8 acpiphp_get_latch_status(struct acpiphp_slot *slot);
index ca8127950fcd49397027370d82937246204a0e9b..bf2203ef1308bfa13f3e8b2744db6bd0b2adbcb8 100644 (file)
@@ -155,15 +155,11 @@ static int enable_slot(struct hotplug_slot *hotplug_slot)
 static int disable_slot(struct hotplug_slot *hotplug_slot)
 {
        struct slot *slot = hotplug_slot->private;
-       int retval;
 
        dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
 
        /* disable the specified slot */
-       retval = acpiphp_disable_slot(slot->acpi_slot);
-       if (!retval)
-               retval = acpiphp_eject_slot(slot->acpi_slot);
-       return retval;
+       return acpiphp_disable_and_eject_slot(slot->acpi_slot);
 }
 
 
@@ -290,7 +286,8 @@ static void release_slot(struct hotplug_slot *hotplug_slot)
 }
 
 /* callback routine to initialize 'struct slot' for each slot */
-int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
+int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot,
+                                 unsigned int sun)
 {
        struct slot *slot;
        int retval = -ENOMEM;
@@ -317,12 +314,11 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
        slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot);
 
        acpiphp_slot->slot = slot;
-       snprintf(name, SLOT_NAME_SIZE, "%llu", slot->acpi_slot->sun);
+       slot->sun = sun;
+       snprintf(name, SLOT_NAME_SIZE, "%u", sun);
 
-       retval = pci_hp_register(slot->hotplug_slot,
-                                       acpiphp_slot->bridge->pci_bus,
-                                       acpiphp_slot->device,
-                                       name);
+       retval = pci_hp_register(slot->hotplug_slot, acpiphp_slot->bus,
+                                acpiphp_slot->device, name);
        if (retval == -EBUSY)
                goto error_hpslot;
        if (retval) {
index 59df8575a48ce834fb48ea002689ed97ed9ca51a..05e463db11decf8588fc84508ce65c4b95bf5db8 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/pci.h>
 #include <linux/pci_hotplug.h>
 #include <linux/pci-acpi.h>
+#include <linux/pm_runtime.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
 #include <linux/acpi.h>
 
 static LIST_HEAD(bridge_list);
 static DEFINE_MUTEX(bridge_mutex);
+static DEFINE_MUTEX(acpiphp_context_lock);
 
 #define MY_NAME "acpiphp_glue"
 
-static void handle_hotplug_event_bridge (acpi_handle, u32, void *);
+static void handle_hotplug_event(acpi_handle handle, u32 type, void *data);
 static void acpiphp_sanitize_bus(struct pci_bus *bus);
 static void acpiphp_set_hpp_values(struct pci_bus *bus);
-static void hotplug_event_func(acpi_handle handle, u32 type, void *context);
-static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context);
+static void hotplug_event(acpi_handle handle, u32 type, void *data);
 static void free_bridge(struct kref *kref);
 
-/* callback routine to check for the existence of a pci dock device */
-static acpi_status
-is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv)
+static void acpiphp_context_handler(acpi_handle handle, void *context)
 {
-       int *count = (int *)context;
+       /* Intentionally empty. */
+}
 
-       if (is_dock_device(handle)) {
-               (*count)++;
-               return AE_CTRL_TERMINATE;
-       } else {
-               return AE_OK;
+/**
+ * acpiphp_init_context - Create hotplug context and grab a reference to it.
+ * @handle: ACPI object handle to create the context for.
+ *
+ * Call under acpiphp_context_lock.
+ */
+static struct acpiphp_context *acpiphp_init_context(acpi_handle handle)
+{
+       struct acpiphp_context *context;
+       acpi_status status;
+
+       context = kzalloc(sizeof(*context), GFP_KERNEL);
+       if (!context)
+               return NULL;
+
+       context->handle = handle;
+       context->refcount = 1;
+       status = acpi_attach_data(handle, acpiphp_context_handler, context);
+       if (ACPI_FAILURE(status)) {
+               kfree(context);
+               return NULL;
        }
+       return context;
+}
+
+/**
+ * acpiphp_get_context - Get hotplug context and grab a reference to it.
+ * @handle: ACPI object handle to get the context for.
+ *
+ * Call under acpiphp_context_lock.
+ */
+static struct acpiphp_context *acpiphp_get_context(acpi_handle handle)
+{
+       struct acpiphp_context *context = NULL;
+       acpi_status status;
+       void *data;
+
+       status = acpi_get_data(handle, acpiphp_context_handler, &data);
+       if (ACPI_SUCCESS(status)) {
+               context = data;
+               context->refcount++;
+       }
+       return context;
+}
+
+/**
+ * acpiphp_put_context - Drop a reference to ACPI hotplug context.
+ * @handle: ACPI object handle to put the context for.
+ *
+ * The context object is removed if there are no more references to it.
+ *
+ * Call under acpiphp_context_lock.
+ */
+static void acpiphp_put_context(struct acpiphp_context *context)
+{
+       if (--context->refcount)
+               return;
+
+       WARN_ON(context->bridge);
+       acpi_detach_data(context->handle, acpiphp_context_handler);
+       kfree(context);
 }
 
 static inline void get_bridge(struct acpiphp_bridge *bridge)
@@ -91,25 +146,36 @@ static inline void put_bridge(struct acpiphp_bridge *bridge)
 
 static void free_bridge(struct kref *kref)
 {
+       struct acpiphp_context *context;
        struct acpiphp_bridge *bridge;
        struct acpiphp_slot *slot, *next;
        struct acpiphp_func *func, *tmp;
 
+       mutex_lock(&acpiphp_context_lock);
+
        bridge = container_of(kref, struct acpiphp_bridge, ref);
 
        list_for_each_entry_safe(slot, next, &bridge->slots, node) {
-               list_for_each_entry_safe(func, tmp, &slot->funcs, sibling) {
-                       kfree(func);
-               }
+               list_for_each_entry_safe(func, tmp, &slot->funcs, sibling)
+                       acpiphp_put_context(func_to_context(func));
+
                kfree(slot);
        }
 
-       /* Release reference acquired by acpiphp_bridge_handle_to_function() */
-       if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func)
-               put_bridge(bridge->func->slot->bridge);
+       context = bridge->context;
+       /* Root bridges will not have hotplug context. */
+       if (context) {
+               /* Release the reference taken by acpiphp_enumerate_slots(). */
+               put_bridge(context->func.parent);
+               context->bridge = NULL;
+               acpiphp_put_context(context);
+       }
+
        put_device(&bridge->pci_bus->dev);
        pci_dev_put(bridge->pci_dev);
        kfree(bridge);
+
+       mutex_unlock(&acpiphp_context_lock);
 }
 
 /*
@@ -119,15 +185,14 @@ static void free_bridge(struct kref *kref)
  * TBD - figure out a way to only call fixups for
  * systems that require them.
  */
-static int post_dock_fixups(struct notifier_block *nb, unsigned long val,
-       void *v)
+static void post_dock_fixups(acpi_handle not_used, u32 event, void *data)
 {
-       struct acpiphp_func *func = container_of(nb, struct acpiphp_func, nb);
-       struct pci_bus *bus = func->slot->bridge->pci_bus;
+       struct acpiphp_context *context = data;
+       struct pci_bus *bus = context->func.slot->bus;
        u32 buses;
 
        if (!bus->self)
-               return  NOTIFY_OK;
+               return;
 
        /* fixup bad _DCK function that rewrites
         * secondary bridge on slot
@@ -143,12 +208,12 @@ static int post_dock_fixups(struct notifier_block *nb, unsigned long val,
                        | ((unsigned int)(bus->busn_res.end) << 16);
                pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses);
        }
-       return NOTIFY_OK;
 }
 
 
 static const struct acpi_dock_ops acpiphp_dock_ops = {
-       .handler = hotplug_event_func,
+       .fixup = post_dock_fixups,
+       .handler = hotplug_event,
 };
 
 /* Check whether the PCI device is managed by native PCIe hotplug driver */
@@ -182,129 +247,117 @@ static bool device_is_managed_by_native_pciehp(struct pci_dev *pdev)
 
 static void acpiphp_dock_init(void *data)
 {
-       struct acpiphp_func *func = data;
+       struct acpiphp_context *context = data;
 
-       get_bridge(func->slot->bridge);
+       get_bridge(context->func.parent);
 }
 
 static void acpiphp_dock_release(void *data)
 {
-       struct acpiphp_func *func = data;
+       struct acpiphp_context *context = data;
 
-       put_bridge(func->slot->bridge);
+       put_bridge(context->func.parent);
 }
 
 /* callback routine to register each ACPI PCI slot object */
-static acpi_status
-register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
+static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
+                                void **rv)
 {
-       struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context;
+       struct acpiphp_bridge *bridge = data;
+       struct acpiphp_context *context;
        struct acpiphp_slot *slot;
        struct acpiphp_func *newfunc;
-       acpi_handle tmp;
        acpi_status status = AE_OK;
-       unsigned long long adr, sun;
-       int device, function, retval, found = 0;
+       unsigned long long adr;
+       int device, function;
        struct pci_bus *pbus = bridge->pci_bus;
-       struct pci_dev *pdev;
+       struct pci_dev *pdev = bridge->pci_dev;
        u32 val;
 
-       if (!acpi_pci_check_ejectable(pbus, handle) && !is_dock_device(handle))
+       if (pdev && device_is_managed_by_native_pciehp(pdev))
                return AE_OK;
 
        status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
        if (ACPI_FAILURE(status)) {
-               warn("can't evaluate _ADR (%#x)\n", status);
+               acpi_handle_warn(handle, "can't evaluate _ADR (%#x)\n", status);
                return AE_OK;
        }
 
        device = (adr >> 16) & 0xffff;
        function = adr & 0xffff;
 
-       pdev = bridge->pci_dev;
-       if (pdev && device_is_managed_by_native_pciehp(pdev))
-               return AE_OK;
-
-       newfunc = kzalloc(sizeof(struct acpiphp_func), GFP_KERNEL);
-       if (!newfunc)
-               return AE_NO_MEMORY;
-
-       newfunc->handle = handle;
+       mutex_lock(&acpiphp_context_lock);
+       context = acpiphp_init_context(handle);
+       if (!context) {
+               mutex_unlock(&acpiphp_context_lock);
+               acpi_handle_err(handle, "No hotplug context\n");
+               return AE_NOT_EXIST;
+       }
+       newfunc = &context->func;
        newfunc->function = function;
+       newfunc->parent = bridge;
+       mutex_unlock(&acpiphp_context_lock);
 
-       if (ACPI_SUCCESS(acpi_get_handle(handle, "_EJ0", &tmp)))
+       if (acpi_has_method(handle, "_EJ0"))
                newfunc->flags = FUNC_HAS_EJ0;
 
-       if (ACPI_SUCCESS(acpi_get_handle(handle, "_STA", &tmp)))
+       if (acpi_has_method(handle, "_STA"))
                newfunc->flags |= FUNC_HAS_STA;
 
-       if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS0", &tmp)))
-               newfunc->flags |= FUNC_HAS_PS0;
-
-       if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp)))
-               newfunc->flags |= FUNC_HAS_PS3;
-
-       if (ACPI_SUCCESS(acpi_get_handle(handle, "_DCK", &tmp)))
+       if (acpi_has_method(handle, "_DCK"))
                newfunc->flags |= FUNC_HAS_DCK;
 
-       status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun);
-       if (ACPI_FAILURE(status)) {
-               /*
-                * use the count of the number of slots we've found
-                * for the number of the slot
-                */
-               sun = bridge->nr_slots+1;
-       }
-
        /* search for objects that share the same slot */
        list_for_each_entry(slot, &bridge->slots, node)
-               if (slot->device == device) {
-                       if (slot->sun != sun)
-                               warn("sibling found, but _SUN doesn't match!\n");
-                       found = 1;
-                       break;
-               }
+               if (slot->device == device)
+                       goto slot_found;
 
-       if (!found) {
-               slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL);
-               if (!slot) {
-                       kfree(newfunc);
-                       return AE_NO_MEMORY;
-               }
+       slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL);
+       if (!slot) {
+               status = AE_NO_MEMORY;
+               goto err;
+       }
 
-               slot->bridge = bridge;
-               slot->device = device;
-               slot->sun = sun;
-               INIT_LIST_HEAD(&slot->funcs);
-               mutex_init(&slot->crit_sect);
+       slot->bus = bridge->pci_bus;
+       slot->device = device;
+       INIT_LIST_HEAD(&slot->funcs);
+       mutex_init(&slot->crit_sect);
+
+       list_add_tail(&slot->node, &bridge->slots);
+
+       /* Register slots for ejectable funtions only. */
+       if (acpi_pci_check_ejectable(pbus, handle)  || is_dock_device(handle)) {
+               unsigned long long sun;
+               int retval;
 
-               mutex_lock(&bridge_mutex);
-               list_add_tail(&slot->node, &bridge->slots);
-               mutex_unlock(&bridge_mutex);
                bridge->nr_slots++;
+               status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun);
+               if (ACPI_FAILURE(status))
+                       sun = bridge->nr_slots;
 
                dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n",
-                   slot->sun, pci_domain_nr(pbus), pbus->number, device);
-               retval = acpiphp_register_hotplug_slot(slot);
+                   sun, pci_domain_nr(pbus), pbus->number, device);
+
+               retval = acpiphp_register_hotplug_slot(slot, sun);
                if (retval) {
+                       bridge->nr_slots--;
                        if (retval == -EBUSY)
                                warn("Slot %llu already registered by another "
-                                       "hotplug driver\n", slot->sun);
+                                       "hotplug driver\n", sun);
                        else
                                warn("acpiphp_register_hotplug_slot failed "
                                        "(err code = 0x%x)\n", retval);
-                       goto err_exit;
                }
+               /* Even if the slot registration fails, we can still use it. */
        }
 
+ slot_found:
        newfunc->slot = slot;
-       mutex_lock(&bridge_mutex);
        list_add_tail(&newfunc->sibling, &slot->funcs);
-       mutex_unlock(&bridge_mutex);
 
        if (pci_bus_read_dev_vendor_id(pbus, PCI_DEVFN(device, function),
                                       &val, 60*1000))
-               slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON);
+               slot->flags |= SLOT_ENABLED;
 
        if (is_dock_device(handle)) {
                /* we don't want to call this device's _EJ0
@@ -313,136 +366,46 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
                 */
                newfunc->flags &= ~FUNC_HAS_EJ0;
                if (register_hotplug_dock_device(handle,
-                       &acpiphp_dock_ops, newfunc,
+                       &acpiphp_dock_ops, context,
                        acpiphp_dock_init, acpiphp_dock_release))
                        dbg("failed to register dock device\n");
-
-               /* we need to be notified when dock events happen
-                * outside of the hotplug operation, since we may
-                * need to do fixups before we can hotplug.
-                */
-               newfunc->nb.notifier_call = post_dock_fixups;
-               if (register_dock_notifier(&newfunc->nb))
-                       dbg("failed to register a dock notifier");
        }
 
        /* install notify handler */
        if (!(newfunc->flags & FUNC_HAS_DCK)) {
-               status = acpi_install_notify_handler(handle,
-                                            ACPI_SYSTEM_NOTIFY,
-                                            handle_hotplug_event_func,
-                                            newfunc);
-
+               status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+                                                    handle_hotplug_event,
+                                                    context);
                if (ACPI_FAILURE(status))
-                       err("failed to register interrupt notify handler\n");
-       } else
-               status = AE_OK;
-
-       return status;
-
- err_exit:
-       bridge->nr_slots--;
-       mutex_lock(&bridge_mutex);
-       list_del(&slot->node);
-       mutex_unlock(&bridge_mutex);
-       kfree(slot);
-       kfree(newfunc);
-
-       return AE_OK;
-}
-
-
-/* see if it's worth looking at this bridge */
-static int detect_ejectable_slots(acpi_handle handle)
-{
-       int found = acpi_pci_detect_ejectable(handle);
-       if (!found) {
-               acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
-                                   is_pci_dock_device, NULL, (void *)&found, NULL);
-       }
-       return found;
-}
-
-/* initialize miscellaneous stuff for both root and PCI-to-PCI bridge */
-static void init_bridge_misc(struct acpiphp_bridge *bridge)
-{
-       acpi_status status;
-
-       /* must be added to the list prior to calling register_slot */
-       mutex_lock(&bridge_mutex);
-       list_add(&bridge->list, &bridge_list);
-       mutex_unlock(&bridge_mutex);
-
-       /* register all slot objects under this bridge */
-       status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1,
-                                    register_slot, NULL, bridge, NULL);
-       if (ACPI_FAILURE(status)) {
-               mutex_lock(&bridge_mutex);
-               list_del(&bridge->list);
-               mutex_unlock(&bridge_mutex);
-               return;
+                       acpi_handle_err(handle,
+                                       "failed to install notify handler\n");
        }
 
-       /* install notify handler for P2P bridges */
-       if (!pci_is_root_bus(bridge->pci_bus)) {
-               if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) {
-                       status = acpi_remove_notify_handler(bridge->func->handle,
-                                               ACPI_SYSTEM_NOTIFY,
-                                               handle_hotplug_event_func);
-                       if (ACPI_FAILURE(status))
-                               err("failed to remove notify handler\n");
-               }
-               status = acpi_install_notify_handler(bridge->handle,
-                                            ACPI_SYSTEM_NOTIFY,
-                                            handle_hotplug_event_bridge,
-                                            bridge);
-
-               if (ACPI_FAILURE(status)) {
-                       err("failed to register interrupt notify handler\n");
-               }
-       }
-}
-
-
-/* find acpiphp_func from acpiphp_bridge */
-static struct acpiphp_func *acpiphp_bridge_handle_to_function(acpi_handle handle)
-{
-       struct acpiphp_bridge *bridge;
-       struct acpiphp_slot *slot;
-       struct acpiphp_func *func = NULL;
-
-       mutex_lock(&bridge_mutex);
-       list_for_each_entry(bridge, &bridge_list, list) {
-               list_for_each_entry(slot, &bridge->slots, node) {
-                       list_for_each_entry(func, &slot->funcs, sibling) {
-                               if (func->handle == handle) {
-                                       get_bridge(func->slot->bridge);
-                                       mutex_unlock(&bridge_mutex);
-                                       return func;
-                               }
-                       }
-               }
-       }
-       mutex_unlock(&bridge_mutex);
+       return AE_OK;
 
-       return NULL;
+ err:
+       mutex_lock(&acpiphp_context_lock);
+       acpiphp_put_context(context);
+       mutex_unlock(&acpiphp_context_lock);
+       return status;
 }
 
-
 static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle)
 {
-       struct acpiphp_bridge *bridge;
-
-       mutex_lock(&bridge_mutex);
-       list_for_each_entry(bridge, &bridge_list, list)
-               if (bridge->handle == handle) {
+       struct acpiphp_context *context;
+       struct acpiphp_bridge *bridge = NULL;
+
+       mutex_lock(&acpiphp_context_lock);
+       context = acpiphp_get_context(handle);
+       if (context) {
+               bridge = context->bridge;
+               if (bridge)
                        get_bridge(bridge);
-                       mutex_unlock(&bridge_mutex);
-                       return bridge;
-               }
-       mutex_unlock(&bridge_mutex);
 
-       return NULL;
+               acpiphp_put_context(context);
+       }
+       mutex_unlock(&acpiphp_context_lock);
+       return bridge;
 }
 
 static void cleanup_bridge(struct acpiphp_bridge *bridge)
@@ -450,35 +413,18 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
        struct acpiphp_slot *slot;
        struct acpiphp_func *func;
        acpi_status status;
-       acpi_handle handle = bridge->handle;
-
-       if (!pci_is_root_bus(bridge->pci_bus)) {
-               status = acpi_remove_notify_handler(handle,
-                                           ACPI_SYSTEM_NOTIFY,
-                                           handle_hotplug_event_bridge);
-               if (ACPI_FAILURE(status))
-                       err("failed to remove notify handler\n");
-       }
-
-       if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) {
-               status = acpi_install_notify_handler(bridge->func->handle,
-                                               ACPI_SYSTEM_NOTIFY,
-                                               handle_hotplug_event_func,
-                                               bridge->func);
-               if (ACPI_FAILURE(status))
-                       err("failed to install interrupt notify handler\n");
-       }
 
        list_for_each_entry(slot, &bridge->slots, node) {
                list_for_each_entry(func, &slot->funcs, sibling) {
-                       if (is_dock_device(func->handle)) {
-                               unregister_hotplug_dock_device(func->handle);
-                               unregister_dock_notifier(&func->nb);
-                       }
+                       acpi_handle handle = func_to_handle(func);
+
+                       if (is_dock_device(handle))
+                               unregister_hotplug_dock_device(handle);
+
                        if (!(func->flags & FUNC_HAS_DCK)) {
-                               status = acpi_remove_notify_handler(func->handle,
-                                               ACPI_SYSTEM_NOTIFY,
-                                               handle_hotplug_event_func);
+                               status = acpi_remove_notify_handler(handle,
+                                                       ACPI_SYSTEM_NOTIFY,
+                                                       handle_hotplug_event);
                                if (ACPI_FAILURE(status))
                                        err("failed to remove notify handler\n");
                        }
@@ -491,71 +437,6 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
        mutex_unlock(&bridge_mutex);
 }
 
-static int power_on_slot(struct acpiphp_slot *slot)
-{
-       acpi_status status;
-       struct acpiphp_func *func;
-       int retval = 0;
-
-       /* if already enabled, just skip */
-       if (slot->flags & SLOT_POWEREDON)
-               goto err_exit;
-
-       list_for_each_entry(func, &slot->funcs, sibling) {
-               if (func->flags & FUNC_HAS_PS0) {
-                       dbg("%s: executing _PS0\n", __func__);
-                       status = acpi_evaluate_object(func->handle, "_PS0", NULL, NULL);
-                       if (ACPI_FAILURE(status)) {
-                               warn("%s: _PS0 failed\n", __func__);
-                               retval = -1;
-                               goto err_exit;
-                       } else
-                               break;
-               }
-       }
-
-       /* TBD: evaluate _STA to check if the slot is enabled */
-
-       slot->flags |= SLOT_POWEREDON;
-
- err_exit:
-       return retval;
-}
-
-
-static int power_off_slot(struct acpiphp_slot *slot)
-{
-       acpi_status status;
-       struct acpiphp_func *func;
-
-       int retval = 0;
-
-       /* if already disabled, just skip */
-       if ((slot->flags & SLOT_POWEREDON) == 0)
-               goto err_exit;
-
-       list_for_each_entry(func, &slot->funcs, sibling) {
-               if (func->flags & FUNC_HAS_PS3) {
-                       status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL);
-                       if (ACPI_FAILURE(status)) {
-                               warn("%s: _PS3 failed\n", __func__);
-                               retval = -1;
-                               goto err_exit;
-                       } else
-                               break;
-               }
-       }
-
-       /* TBD: evaluate _STA to check if the slot is disabled */
-
-       slot->flags &= (~SLOT_POWEREDON);
-
- err_exit:
-       return retval;
-}
-
-
-
 /**
  * acpiphp_max_busnr - return the highest reserved bus number under the given bus.
  * @bus: bus to start search with
@@ -583,52 +464,32 @@ static unsigned char acpiphp_max_busnr(struct pci_bus *bus)
        return max;
 }
 
-
 /**
- * acpiphp_bus_add - add a new bus to acpi subsystem
- * @func: acpiphp_func of the bridge
+ * acpiphp_bus_trim - Trim device objects in an ACPI namespace subtree.
+ * @handle: ACPI device object handle to start from.
  */
-static int acpiphp_bus_add(struct acpiphp_func *func)
+static void acpiphp_bus_trim(acpi_handle handle)
 {
-       struct acpi_device *device;
-       int ret_val;
-
-       if (!acpi_bus_get_device(func->handle, &device)) {
-               dbg("bus exists... trim\n");
-               /* this shouldn't be in here, so remove
-                * the bus then re-add it...
-                */
-               acpi_bus_trim(device);
-       }
-
-       ret_val = acpi_bus_scan(func->handle);
-       if (!ret_val)
-               ret_val = acpi_bus_get_device(func->handle, &device);
-
-       if (ret_val)
-               dbg("error adding bus, %x\n", -ret_val);
+       struct acpi_device *adev = NULL;
 
-       return ret_val;
+       acpi_bus_get_device(handle, &adev);
+       if (adev)
+               acpi_bus_trim(adev);
 }
 
-
 /**
- * acpiphp_bus_trim - trim a bus from acpi subsystem
- * @handle: handle to acpi namespace
+ * acpiphp_bus_add - Scan ACPI namespace subtree.
+ * @handle: ACPI object handle to start the scan from.
  */
-static int acpiphp_bus_trim(acpi_handle handle)
+static void acpiphp_bus_add(acpi_handle handle)
 {
-       struct acpi_device *device;
-       int retval;
-
-       retval = acpi_bus_get_device(handle, &device);
-       if (retval) {
-               dbg("acpi_device not found\n");
-               return retval;
-       }
+       struct acpi_device *adev = NULL;
 
-       acpi_bus_trim(device);
-       return 0;
+       acpiphp_bus_trim(handle);
+       acpi_bus_scan(handle);
+       acpi_bus_get_device(handle, &adev);
+       if (adev)
+               acpi_device_set_power(adev, ACPI_STATE_D0);
 }
 
 static void acpiphp_set_acpi_region(struct acpiphp_slot *slot)
@@ -645,7 +506,8 @@ static void acpiphp_set_acpi_region(struct acpiphp_slot *slot)
                params[1].type = ACPI_TYPE_INTEGER;
                params[1].integer.value = 1;
                /* _REG is optional, we don't care about if there is failure */
-               acpi_evaluate_object(func->handle, "_REG", &arg_list, NULL);
+               acpi_evaluate_object(func_to_handle(func), "_REG", &arg_list,
+                                    NULL);
        }
 }
 
@@ -653,59 +515,44 @@ static void check_hotplug_bridge(struct acpiphp_slot *slot, struct pci_dev *dev)
 {
        struct acpiphp_func *func;
 
-       if (!dev->subordinate)
-               return;
-
        /* quirk, or pcie could set it already */
        if (dev->is_hotplug_bridge)
                return;
 
-       if (PCI_SLOT(dev->devfn) != slot->device)
-               return;
-
        list_for_each_entry(func, &slot->funcs, sibling) {
                if (PCI_FUNC(dev->devfn) == func->function) {
-                       /* check if this bridge has ejectable slots */
-                       if ((detect_ejectable_slots(func->handle) > 0))
-                               dev->is_hotplug_bridge = 1;
+                       dev->is_hotplug_bridge = 1;
                        break;
                }
        }
 }
 
 /**
- * enable_device - enable, configure a slot
+ * enable_slot - enable, configure a slot
  * @slot: slot to be enabled
  *
  * This function should be called per *physical slot*,
  * not per each slot object in ACPI namespace.
  */
-static int __ref enable_device(struct acpiphp_slot *slot)
+static void __ref enable_slot(struct acpiphp_slot *slot)
 {
        struct pci_dev *dev;
-       struct pci_bus *bus = slot->bridge->pci_bus;
+       struct pci_bus *bus = slot->bus;
        struct acpiphp_func *func;
-       int num, max, pass;
+       int max, pass;
        LIST_HEAD(add_list);
 
-       if (slot->flags & SLOT_ENABLED)
-               goto err_exit;
-
        list_for_each_entry(func, &slot->funcs, sibling)
-               acpiphp_bus_add(func);
+               acpiphp_bus_add(func_to_handle(func));
 
-       num = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
-       if (num == 0) {
-               /* Maybe only part of funcs are added. */
-               dbg("No new device found\n");
-               goto err_exit;
-       }
+       pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
 
        max = acpiphp_max_busnr(bus);
        for (pass = 0; pass < 2; pass++) {
                list_for_each_entry(dev, &bus->devices, bus_list) {
                        if (PCI_SLOT(dev->devfn) != slot->device)
                                continue;
+
                        if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
                            dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
                                max = pci_scan_bridge(bus, dev, max, pass);
@@ -744,16 +591,12 @@ static int __ref enable_device(struct acpiphp_slot *slot)
                        continue;
                }
        }
-
-
- err_exit:
-       return 0;
 }
 
 /* return first device in slot, acquiring a reference on it */
 static struct pci_dev *dev_in_slot(struct acpiphp_slot *slot)
 {
-       struct pci_bus *bus = slot->bridge->pci_bus;
+       struct pci_bus *bus = slot->bus;
        struct pci_dev *dev;
        struct pci_dev *ret = NULL;
 
@@ -769,16 +612,16 @@ static struct pci_dev *dev_in_slot(struct acpiphp_slot *slot)
 }
 
 /**
- * disable_device - disable a slot
+ * disable_slot - disable a slot
  * @slot: ACPI PHP slot
  */
-static int disable_device(struct acpiphp_slot *slot)
+static void disable_slot(struct acpiphp_slot *slot)
 {
        struct acpiphp_func *func;
        struct pci_dev *pdev;
 
        /*
-        * enable_device() enumerates all functions in this device via
+        * enable_slot() enumerates all functions in this device via
         * pci_scan_slot(), whether they have associated ACPI hotplug
         * methods (_EJ0, etc.) or not.  Therefore, we remove all functions
         * here.
@@ -788,13 +631,10 @@ static int disable_device(struct acpiphp_slot *slot)
                pci_dev_put(pdev);
        }
 
-       list_for_each_entry(func, &slot->funcs, sibling) {
-               acpiphp_bus_trim(func->handle);
-       }
+       list_for_each_entry(func, &slot->funcs, sibling)
+               acpiphp_bus_trim(func_to_handle(func));
 
        slot->flags &= (~SLOT_ENABLED);
-
-       return 0;
 }
 
 
@@ -812,18 +652,21 @@ static int disable_device(struct acpiphp_slot *slot)
  */
 static unsigned int get_slot_status(struct acpiphp_slot *slot)
 {
-       acpi_status status;
        unsigned long long sta = 0;
-       u32 dvid;
        struct acpiphp_func *func;
 
        list_for_each_entry(func, &slot->funcs, sibling) {
                if (func->flags & FUNC_HAS_STA) {
-                       status = acpi_evaluate_integer(func->handle, "_STA", NULL, &sta);
+                       acpi_status status;
+
+                       status = acpi_evaluate_integer(func_to_handle(func),
+                                                      "_STA", NULL, &sta);
                        if (ACPI_SUCCESS(status) && sta)
                                break;
                } else {
-                       pci_bus_read_config_dword(slot->bridge->pci_bus,
+                       u32 dvid;
+
+                       pci_bus_read_config_dword(slot->bus,
                                                  PCI_DEVFN(slot->device,
                                                            func->function),
                                                  PCI_VENDOR_ID, &dvid);
@@ -838,34 +681,42 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot)
 }
 
 /**
- * acpiphp_eject_slot - physically eject the slot
- * @slot: ACPI PHP slot
+ * trim_stale_devices - remove PCI devices that are not responding.
+ * @dev: PCI device to start walking the hierarchy from.
  */
-int acpiphp_eject_slot(struct acpiphp_slot *slot)
+static void trim_stale_devices(struct pci_dev *dev)
 {
-       acpi_status status;
-       struct acpiphp_func *func;
-       struct acpi_object_list arg_list;
-       union acpi_object arg;
+       acpi_handle handle = ACPI_HANDLE(&dev->dev);
+       struct pci_bus *bus = dev->subordinate;
+       bool alive = false;
 
-       list_for_each_entry(func, &slot->funcs, sibling) {
-               /* We don't want to call _EJ0 on non-existing functions. */
-               if ((func->flags & FUNC_HAS_EJ0)) {
-                       /* _EJ0 method take one argument */
-                       arg_list.count = 1;
-                       arg_list.pointer = &arg;
-                       arg.type = ACPI_TYPE_INTEGER;
-                       arg.integer.value = 1;
-
-                       status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL);
-                       if (ACPI_FAILURE(status)) {
-                               warn("%s: _EJ0 failed\n", __func__);
-                               return -1;
-                       } else
-                               break;
-               }
+       if (handle) {
+               acpi_status status;
+               unsigned long long sta;
+
+               status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
+               alive = ACPI_SUCCESS(status) && sta == ACPI_STA_ALL;
+       }
+       if (!alive) {
+               u32 v;
+
+               /* Check if the device responds. */
+               alive = pci_bus_read_dev_vendor_id(dev->bus, dev->devfn, &v, 0);
+       }
+       if (!alive) {
+               pci_stop_and_remove_bus_device(dev);
+               if (handle)
+                       acpiphp_bus_trim(handle);
+       } else if (bus) {
+               struct pci_dev *child, *tmp;
+
+               /* The device is a bridge. so check the bus below it. */
+               pm_runtime_get_sync(&dev->dev);
+               list_for_each_entry_safe(child, tmp, &bus->devices, bus_list)
+                       trim_stale_devices(child);
+
+               pm_runtime_put(&dev->dev);
        }
-       return 0;
 }
 
 /**
@@ -875,43 +726,30 @@ int acpiphp_eject_slot(struct acpiphp_slot *slot)
  * Iterate over all slots under this bridge and make sure that if a
  * card is present they are enabled, and if not they are disabled.
  */
-static int acpiphp_check_bridge(struct acpiphp_bridge *bridge)
+static void acpiphp_check_bridge(struct acpiphp_bridge *bridge)
 {
        struct acpiphp_slot *slot;
-       int retval = 0;
-       int enabled, disabled;
-
-       enabled = disabled = 0;
 
        list_for_each_entry(slot, &bridge->slots, node) {
-               unsigned int status = get_slot_status(slot);
-               if (slot->flags & SLOT_ENABLED) {
-                       if (status == ACPI_STA_ALL)
-                               continue;
-                       retval = acpiphp_disable_slot(slot);
-                       if (retval) {
-                               err("Error occurred in disabling\n");
-                               goto err_exit;
-                       } else {
-                               acpiphp_eject_slot(slot);
-                       }
-                       disabled++;
+               struct pci_bus *bus = slot->bus;
+               struct pci_dev *dev, *tmp;
+
+               mutex_lock(&slot->crit_sect);
+               /* wake up all functions */
+               if (get_slot_status(slot) == ACPI_STA_ALL) {
+                       /* remove stale devices if any */
+                       list_for_each_entry_safe(dev, tmp, &bus->devices,
+                                                bus_list)
+                               if (PCI_SLOT(dev->devfn) == slot->device)
+                                       trim_stale_devices(dev);
+
+                       /* configure all functions */
+                       enable_slot(slot);
                } else {
-                       if (status != ACPI_STA_ALL)
-                               continue;
-                       retval = acpiphp_enable_slot(slot);
-                       if (retval) {
-                               err("Error occurred in enabling\n");
-                               goto err_exit;
-                       }
-                       enabled++;
+                       disable_slot(slot);
                }
+               mutex_unlock(&slot->crit_sect);
        }
-
-       dbg("%s: %d enabled, %d disabled\n", __func__, enabled, disabled);
-
- err_exit:
-       return retval;
 }
 
 static void acpiphp_set_hpp_values(struct pci_bus *bus)
@@ -950,25 +788,6 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus)
  * ACPI event handlers
  */
 
-static acpi_status
-check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
-{
-       struct acpiphp_bridge *bridge;
-       char objname[64];
-       struct acpi_buffer buffer = { .length = sizeof(objname),
-                                     .pointer = objname };
-
-       bridge = acpiphp_handle_to_bridge(handle);
-       if (bridge) {
-               acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-               dbg("%s: re-enumerating slots under %s\n",
-                       __func__, objname);
-               acpiphp_check_bridge(bridge);
-               put_bridge(bridge);
-       }
-       return AE_OK ;
-}
-
 void acpiphp_check_host_bridge(acpi_handle handle)
 {
        struct acpiphp_bridge *bridge;
@@ -978,27 +797,23 @@ void acpiphp_check_host_bridge(acpi_handle handle)
                acpiphp_check_bridge(bridge);
                put_bridge(bridge);
        }
-
-       acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
-               ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL);
 }
 
-static void _handle_hotplug_event_bridge(struct work_struct *work)
+static void hotplug_event(acpi_handle handle, u32 type, void *data)
 {
+       struct acpiphp_context *context = data;
+       struct acpiphp_func *func = &context->func;
        struct acpiphp_bridge *bridge;
        char objname[64];
        struct acpi_buffer buffer = { .length = sizeof(objname),
                                      .pointer = objname };
-       struct acpi_hp_work *hp_work;
-       acpi_handle handle;
-       u32 type;
 
-       hp_work = container_of(work, struct acpi_hp_work, work);
-       handle = hp_work->handle;
-       type = hp_work->type;
-       bridge = (struct acpiphp_bridge *)hp_work->context;
+       mutex_lock(&acpiphp_context_lock);
+       bridge = context->bridge;
+       if (bridge)
+               get_bridge(bridge);
 
-       acpi_scan_lock_acquire();
+       mutex_unlock(&acpiphp_context_lock);
 
        acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
 
@@ -1007,188 +822,129 @@ static void _handle_hotplug_event_bridge(struct work_struct *work)
                /* bus re-enumerate */
                dbg("%s: Bus check notify on %s\n", __func__, objname);
                dbg("%s: re-enumerating slots under %s\n", __func__, objname);
-               acpiphp_check_bridge(bridge);
-               acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
-                       ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL);
+               if (bridge) {
+                       acpiphp_check_bridge(bridge);
+               } else {
+                       struct acpiphp_slot *slot = func->slot;
+
+                       mutex_lock(&slot->crit_sect);
+                       enable_slot(slot);
+                       mutex_unlock(&slot->crit_sect);
+               }
                break;
 
        case ACPI_NOTIFY_DEVICE_CHECK:
                /* device check */
                dbg("%s: Device check notify on %s\n", __func__, objname);
-               acpiphp_check_bridge(bridge);
-               break;
+               if (bridge)
+                       acpiphp_check_bridge(bridge);
+               else
+                       acpiphp_check_bridge(func->parent);
 
-       case ACPI_NOTIFY_DEVICE_WAKE:
-               /* wake event */
-               dbg("%s: Device wake notify on %s\n", __func__, objname);
                break;
 
        case ACPI_NOTIFY_EJECT_REQUEST:
                /* request device eject */
                dbg("%s: Device eject notify on %s\n", __func__, objname);
-               if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) {
-                       struct acpiphp_slot *slot;
-                       slot = bridge->func->slot;
-                       if (!acpiphp_disable_slot(slot))
-                               acpiphp_eject_slot(slot);
-               }
+               acpiphp_disable_and_eject_slot(func->slot);
                break;
+       }
 
-       case ACPI_NOTIFY_FREQUENCY_MISMATCH:
-               printk(KERN_ERR "Device %s cannot be configured due"
-                               " to a frequency mismatch\n", objname);
-               break;
+       if (bridge)
+               put_bridge(bridge);
+}
 
-       case ACPI_NOTIFY_BUS_MODE_MISMATCH:
-               printk(KERN_ERR "Device %s cannot be configured due"
-                               " to a bus mode mismatch\n", objname);
-               break;
+static void hotplug_event_work(struct work_struct *work)
+{
+       struct acpiphp_context *context;
+       struct acpi_hp_work *hp_work;
 
-       case ACPI_NOTIFY_POWER_FAULT:
-               printk(KERN_ERR "Device %s has suffered a power fault\n",
-                               objname);
-               break;
+       hp_work = container_of(work, struct acpi_hp_work, work);
+       context = hp_work->context;
+       acpi_scan_lock_acquire();
 
-       default:
-               warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
-               break;
-       }
+       hotplug_event(hp_work->handle, hp_work->type, context);
 
        acpi_scan_lock_release();
-       kfree(hp_work); /* allocated in handle_hotplug_event_bridge */
-       put_bridge(bridge);
+       kfree(hp_work); /* allocated in handle_hotplug_event() */
+       put_bridge(context->func.parent);
 }
 
 /**
- * handle_hotplug_event_bridge - handle ACPI event on bridges
+ * handle_hotplug_event - handle ACPI hotplug event
  * @handle: Notify()'ed acpi_handle
  * @type: Notify code
- * @context: pointer to acpiphp_bridge structure
+ * @data: pointer to acpiphp_context structure
  *
- * Handles ACPI event notification on {host,p2p} bridges.
+ * Handles ACPI event notification on slots.
  */
-static void handle_hotplug_event_bridge(acpi_handle handle, u32 type,
-                                       void *context)
+static void handle_hotplug_event(acpi_handle handle, u32 type, void *data)
 {
-       struct acpiphp_bridge *bridge = context;
-
-       /*
-        * Currently the code adds all hotplug events to the kacpid_wq
-        * queue when it should add hotplug events to the kacpi_hotplug_wq.
-        * The proper way to fix this is to reorganize the code so that
-        * drivers (dock, etc.) do not call acpi_os_execute(), etc.
-        * For now just re-add this work to the kacpi_hotplug_wq so we
-        * don't deadlock on hotplug actions.
-        */
-       get_bridge(bridge);
-       alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_bridge);
-}
-
-static void hotplug_event_func(acpi_handle handle, u32 type, void *context)
-{
-       struct acpiphp_func *func = context;
-       char objname[64];
-       struct acpi_buffer buffer = { .length = sizeof(objname),
-                                     .pointer = objname };
-
-       acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
+       struct acpiphp_context *context;
 
        switch (type) {
        case ACPI_NOTIFY_BUS_CHECK:
-               /* bus re-enumerate */
-               dbg("%s: Bus check notify on %s\n", __func__, objname);
-               acpiphp_enable_slot(func->slot);
-               break;
-
        case ACPI_NOTIFY_DEVICE_CHECK:
-               /* device check : re-enumerate from parent bus */
-               dbg("%s: Device check notify on %s\n", __func__, objname);
-               acpiphp_check_bridge(func->slot->bridge);
-               break;
-
-       case ACPI_NOTIFY_DEVICE_WAKE:
-               /* wake event */
-               dbg("%s: Device wake notify on %s\n", __func__, objname);
-               break;
-
        case ACPI_NOTIFY_EJECT_REQUEST:
-               /* request device eject */
-               dbg("%s: Device eject notify on %s\n", __func__, objname);
-               if (!(acpiphp_disable_slot(func->slot)))
-                       acpiphp_eject_slot(func->slot);
                break;
 
-       default:
-               warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
-               break;
-       }
-}
-
-static void _handle_hotplug_event_func(struct work_struct *work)
-{
-       struct acpi_hp_work *hp_work;
-       struct acpiphp_func *func;
+       case ACPI_NOTIFY_DEVICE_WAKE:
+               return;
 
-       hp_work = container_of(work, struct acpi_hp_work, work);
-       func = hp_work->context;
-       acpi_scan_lock_acquire();
+       case ACPI_NOTIFY_FREQUENCY_MISMATCH:
+               acpi_handle_err(handle, "Device cannot be configured due "
+                               "to a frequency mismatch\n");
+               return;
 
-       hotplug_event_func(hp_work->handle, hp_work->type, func);
+       case ACPI_NOTIFY_BUS_MODE_MISMATCH:
+               acpi_handle_err(handle, "Device cannot be configured due "
+                               "to a bus mode mismatch\n");
+               return;
 
-       acpi_scan_lock_release();
-       kfree(hp_work); /* allocated in handle_hotplug_event_func */
-       put_bridge(func->slot->bridge);
-}
+       case ACPI_NOTIFY_POWER_FAULT:
+               acpi_handle_err(handle, "Device has suffered a power fault\n");
+               return;
 
-/**
- * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots)
- * @handle: Notify()'ed acpi_handle
- * @type: Notify code
- * @context: pointer to acpiphp_func structure
- *
- * Handles ACPI event notification on slots.
- */
-static void handle_hotplug_event_func(acpi_handle handle, u32 type,
-                                     void *context)
-{
-       struct acpiphp_func *func = context;
+       default:
+               acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type);
+               return;
+       }
 
-       /*
-        * Currently the code adds all hotplug events to the kacpid_wq
-        * queue when it should add hotplug events to the kacpi_hotplug_wq.
-        * The proper way to fix this is to reorganize the code so that
-        * drivers (dock, etc.) do not call acpi_os_execute(), etc.
-        * For now just re-add this work to the kacpi_hotplug_wq so we
-        * don't deadlock on hotplug actions.
-        */
-       get_bridge(func->slot->bridge);
-       alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_func);
+       mutex_lock(&acpiphp_context_lock);
+       context = acpiphp_get_context(handle);
+       if (context) {
+               get_bridge(context->func.parent);
+               acpiphp_put_context(context);
+               alloc_acpi_hp_work(handle, type, context, hotplug_event_work);
+       }
+       mutex_unlock(&acpiphp_context_lock);
 }
 
 /*
  * Create hotplug slots for the PCI bus.
  * It should always return 0 to avoid skipping following notifiers.
  */
-void acpiphp_enumerate_slots(struct pci_bus *bus, acpi_handle handle)
+void acpiphp_enumerate_slots(struct pci_bus *bus)
 {
-       acpi_handle dummy_handle;
        struct acpiphp_bridge *bridge;
+       acpi_handle handle;
+       acpi_status status;
 
        if (acpiphp_disabled)
                return;
 
-       if (detect_ejectable_slots(handle) <= 0)
+       handle = ACPI_HANDLE(bus->bridge);
+       if (!handle)
                return;
 
        bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
-       if (bridge == NULL) {
-               err("out of memory\n");
+       if (!bridge) {
+               acpi_handle_err(handle, "No memory for bridge object\n");
                return;
        }
 
        INIT_LIST_HEAD(&bridge->slots);
        kref_init(&bridge->ref);
-       bridge->handle = handle;
        bridge->pci_dev = pci_dev_get(bus->self);
        bridge->pci_bus = bus;
 
@@ -1199,31 +955,62 @@ void acpiphp_enumerate_slots(struct pci_bus *bus, acpi_handle handle)
         */
        get_device(&bus->dev);
 
-       if (!pci_is_root_bus(bridge->pci_bus) &&
-           ACPI_SUCCESS(acpi_get_handle(bridge->handle,
-                                       "_EJ0", &dummy_handle))) {
-               dbg("found ejectable p2p bridge\n");
-               bridge->flags |= BRIDGE_HAS_EJ0;
-               bridge->func = acpiphp_bridge_handle_to_function(handle);
+       if (!pci_is_root_bus(bridge->pci_bus)) {
+               struct acpiphp_context *context;
+
+               /*
+                * This bridge should have been registered as a hotplug function
+                * under its parent, so the context has to be there.  If not, we
+                * are in deep goo.
+                */
+               mutex_lock(&acpiphp_context_lock);
+               context = acpiphp_get_context(handle);
+               if (WARN_ON(!context)) {
+                       mutex_unlock(&acpiphp_context_lock);
+                       put_device(&bus->dev);
+                       kfree(bridge);
+                       return;
+               }
+               bridge->context = context;
+               context->bridge = bridge;
+               /* Get a reference to the parent bridge. */
+               get_bridge(context->func.parent);
+               mutex_unlock(&acpiphp_context_lock);
        }
 
-       init_bridge_misc(bridge);
+       /* must be added to the list prior to calling register_slot */
+       mutex_lock(&bridge_mutex);
+       list_add(&bridge->list, &bridge_list);
+       mutex_unlock(&bridge_mutex);
+
+       /* register all slot objects under this bridge */
+       status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
+                                    register_slot, NULL, bridge, NULL);
+       if (ACPI_FAILURE(status)) {
+               acpi_handle_err(handle, "failed to register slots\n");
+               cleanup_bridge(bridge);
+               put_bridge(bridge);
+       }
 }
 
 /* Destroy hotplug slots associated with the PCI bus */
 void acpiphp_remove_slots(struct pci_bus *bus)
 {
-       struct acpiphp_bridge *bridge, *tmp;
+       struct acpiphp_bridge *bridge;
 
        if (acpiphp_disabled)
                return;
 
-       list_for_each_entry_safe(bridge, tmp, &bridge_list, list)
+       mutex_lock(&bridge_mutex);
+       list_for_each_entry(bridge, &bridge_list, list)
                if (bridge->pci_bus == bus) {
+                       mutex_unlock(&bridge_mutex);
                        cleanup_bridge(bridge);
                        put_bridge(bridge);
-                       break;
+                       return;
                }
+
+       mutex_unlock(&bridge_mutex);
 }
 
 /**
@@ -1232,51 +1019,39 @@ void acpiphp_remove_slots(struct pci_bus *bus)
  */
 int acpiphp_enable_slot(struct acpiphp_slot *slot)
 {
-       int retval;
-
        mutex_lock(&slot->crit_sect);
+       /* configure all functions */
+       if (!(slot->flags & SLOT_ENABLED))
+               enable_slot(slot);
 
-       /* wake up all functions */
-       retval = power_on_slot(slot);
-       if (retval)
-               goto err_exit;
-
-       if (get_slot_status(slot) == ACPI_STA_ALL) {
-               /* configure all functions */
-               retval = enable_device(slot);
-               if (retval)
-                       power_off_slot(slot);
-       } else {
-               dbg("%s: Slot status is not ACPI_STA_ALL\n", __func__);
-               power_off_slot(slot);
-       }
-
- err_exit:
        mutex_unlock(&slot->crit_sect);
-       return retval;
+       return 0;
 }
 
 /**
- * acpiphp_disable_slot - power off slot
+ * acpiphp_disable_and_eject_slot - power off and eject slot
  * @slot: ACPI PHP slot
  */
-int acpiphp_disable_slot(struct acpiphp_slot *slot)
+int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot)
 {
+       struct acpiphp_func *func;
        int retval = 0;
 
        mutex_lock(&slot->crit_sect);
 
        /* unconfigure all functions */
-       retval = disable_device(slot);
-       if (retval)
-               goto err_exit;
+       disable_slot(slot);
+
+       list_for_each_entry(func, &slot->funcs, sibling)
+               if (func->flags & FUNC_HAS_EJ0) {
+                       acpi_handle handle = func_to_handle(func);
 
-       /* power off all functions */
-       retval = power_off_slot(slot);
-       if (retval)
-               goto err_exit;
+                       if (ACPI_FAILURE(acpi_evaluate_ej0(handle)))
+                               acpi_handle_err(handle, "_EJ0 failed\n");
+
+                       break;
+               }
 
- err_exit:
        mutex_unlock(&slot->crit_sect);
        return retval;
 }
@@ -1288,7 +1063,7 @@ int acpiphp_disable_slot(struct acpiphp_slot *slot)
  */
 u8 acpiphp_get_power_status(struct acpiphp_slot *slot)
 {
-       return (slot->flags & SLOT_POWEREDON);
+       return (slot->flags & SLOT_ENABLED);
 }
 
 
@@ -1298,11 +1073,7 @@ u8 acpiphp_get_power_status(struct acpiphp_slot *slot)
  */
 u8 acpiphp_get_latch_status(struct acpiphp_slot *slot)
 {
-       unsigned int sta;
-
-       sta = get_slot_status(slot);
-
-       return (sta & ACPI_STA_DEVICE_UI) ? 0 : 1;
+       return !(get_slot_status(slot) & ACPI_STA_DEVICE_UI);
 }
 
 
@@ -1312,9 +1083,5 @@ u8 acpiphp_get_latch_status(struct acpiphp_slot *slot)
  */
 u8 acpiphp_get_adapter_status(struct acpiphp_slot *slot)
 {
-       unsigned int sta;
-
-       sta = get_slot_status(slot);
-
-       return (sta == 0) ? 0 : 1;
+       return !!get_slot_status(slot);
 }
index c35e8ad6db0142f0ddac2b4697cd4edef416cda7..2f5786c8522c2f170d8f57bc08c592e0ef78048a 100644 (file)
@@ -66,7 +66,7 @@ do {                                                  \
 #define IBM_HARDWARE_ID1 "IBM37D0"
 #define IBM_HARDWARE_ID2 "IBM37D4"
 
-#define hpslot_to_sun(A) (((struct slot *)((A)->private))->acpi_slot->sun)
+#define hpslot_to_sun(A) (((struct slot *)((A)->private))->sun)
 
 /* union apci_descriptor - allows access to the
  * various device descriptors that are embedded in the
@@ -270,7 +270,6 @@ static void ibm_handle_events(acpi_handle handle, u32 event, void *context)
 
        if (subevent == 0x80) {
                dbg("%s: generationg bus event\n", __func__);
-               acpi_bus_generate_proc_event(note->device, note->event, detail);
                acpi_bus_generate_netlink_event(note->device->pnp.device_class,
                                                  dev_name(&note->device->dev),
                                                  note->event, detail);
index aac7a40e4a4ac9205441d9c6918a080531117571..0e0d0f7f63fdd83aa551549d38b174cdca8d034d 100644 (file)
@@ -92,7 +92,14 @@ int pciehp_unconfigure_device(struct slot *p_slot)
        if (ret)
                presence = 0;
 
-       list_for_each_entry_safe(dev, temp, &parent->devices, bus_list) {
+       /*
+        * Stopping an SR-IOV PF device removes all the associated VFs,
+        * which will update the bus->devices list and confuse the
+        * iterator.  Therefore, iterate in reverse so we remove the VFs
+        * first, then the PF.  We do the same in pci_stop_bus_device().
+        */
+       list_for_each_entry_safe_reverse(dev, temp, &parent->devices,
+                                        bus_list) {
                pci_dev_get(dev);
                if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && presence) {
                        pci_read_config_byte(dev, PCI_BRIDGE_CONTROL, &bctl);
index de8ffacf9c9b27cd1f758065e5b3f8158bab89b9..21a7182dccd435865347d223ead22e73a02fe0db 100644 (file)
@@ -286,7 +286,6 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
            (!(iov->cap & PCI_SRIOV_CAP_VFM) && (nr_virtfn > initial)))
                return -EINVAL;
 
-       pci_write_config_word(dev, iov->pos + PCI_SRIOV_NUM_VF, nr_virtfn);
        pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_OFFSET, &offset);
        pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_STRIDE, &stride);
        if (!offset || (nr_virtfn > 1 && !stride))
@@ -324,7 +323,7 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
 
                if (!pdev->is_physfn) {
                        pci_dev_put(pdev);
-                       return -ENODEV;
+                       return -ENOSYS;
                }
 
                rc = sysfs_create_link(&dev->dev.kobj,
@@ -334,6 +333,7 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
                        return rc;
        }
 
+       pci_write_config_word(dev, iov->pos + PCI_SRIOV_NUM_VF, nr_virtfn);
        iov->ctrl |= PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE;
        pci_cfg_access_lock(dev);
        pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
@@ -368,6 +368,7 @@ failed:
        iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE);
        pci_cfg_access_lock(dev);
        pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
+       pci_write_config_word(dev, iov->pos + PCI_SRIOV_NUM_VF, 0);
        ssleep(1);
        pci_cfg_access_unlock(dev);
 
@@ -401,6 +402,7 @@ static void sriov_disable(struct pci_dev *dev)
                sysfs_remove_link(&dev->dev.kobj, "dep_link");
 
        iov->num_VFs = 0;
+       pci_write_config_word(dev, iov->pos + PCI_SRIOV_NUM_VF, 0);
 }
 
 static int sriov_init(struct pci_dev *dev, int pos)
@@ -662,7 +664,7 @@ int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn)
        might_sleep();
 
        if (!dev->is_physfn)
-               return -ENODEV;
+               return -ENOSYS;
 
        return sriov_enable(dev, nr_virtfn);
 }
@@ -722,7 +724,7 @@ EXPORT_SYMBOL_GPL(pci_num_vf);
  * @dev: the PCI device
  *
  * Returns number of VFs belonging to this device that are assigned to a guest.
- * If device is not a physical function returns -ENODEV.
+ * If device is not a physical function returns 0.
  */
 int pci_vfs_assigned(struct pci_dev *dev)
 {
@@ -767,12 +769,15 @@ EXPORT_SYMBOL_GPL(pci_vfs_assigned);
  * device's mutex held.
  *
  * Returns 0 if PF is an SRIOV-capable device and
- * value of numvfs valid. If not a PF with VFS, return -EINVAL;
+ * value of numvfs valid. If not a PF return -ENOSYS;
+ * if numvfs is invalid return -EINVAL;
  * if VFs already enabled, return -EBUSY.
  */
 int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs)
 {
-       if (!dev->is_physfn || (numvfs > dev->sriov->total_VFs))
+       if (!dev->is_physfn)
+               return -ENOSYS;
+       if (numvfs > dev->sriov->total_VFs)
                return -EINVAL;
 
        /* Shouldn't change if VFs already enabled */
@@ -786,17 +791,17 @@ int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs)
 EXPORT_SYMBOL_GPL(pci_sriov_set_totalvfs);
 
 /**
- * pci_sriov_get_totalvfs -- get total VFs supported on this devic3
+ * pci_sriov_get_totalvfs -- get total VFs supported on this device
  * @dev: the PCI PF device
  *
  * For a PCIe device with SRIOV support, return the PCIe
  * SRIOV capability value of TotalVFs or the value of driver_max_VFs
- * if the driver reduced it.  Otherwise, -EINVAL.
+ * if the driver reduced it.  Otherwise 0.
  */
 int pci_sriov_get_totalvfs(struct pci_dev *dev)
 {
        if (!dev->is_physfn)
-               return -EINVAL;
+               return 0;
 
        if (dev->sriov->driver_max_VFs)
                return dev->sriov->driver_max_VFs;
index dbdc5f7e2b294fad4adfe3ae676e258c5af6abbe..fb3522957f0171ed6086c995257e816837dbc7b8 100644 (file)
@@ -210,7 +210,7 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
        }
 
        if (!error)
-               dev_info(&dev->dev, "power state changed by ACPI to %s\n",
+               dev_dbg(&dev->dev, "power state changed by ACPI to %s\n",
                         acpi_power_state_string(state_conv[state]));
 
        return error;
@@ -290,24 +290,16 @@ static struct pci_platform_pm_ops acpi_pci_platform_pm = {
 
 void acpi_pci_add_bus(struct pci_bus *bus)
 {
-       acpi_handle handle = NULL;
-
-       if (bus->bridge)
-               handle = ACPI_HANDLE(bus->bridge);
-       if (acpi_pci_disabled || handle == NULL)
+       if (acpi_pci_disabled || !bus->bridge)
                return;
 
-       acpi_pci_slot_enumerate(bus, handle);
-       acpiphp_enumerate_slots(bus, handle);
+       acpi_pci_slot_enumerate(bus);
+       acpiphp_enumerate_slots(bus);
 }
 
 void acpi_pci_remove_bus(struct pci_bus *bus)
 {
-       /*
-        * bus->bridge->acpi_node.handle has already been reset to NULL
-        * when acpi_pci_remove_bus() is called, so don't check ACPI handle.
-        */
-       if (acpi_pci_disabled)
+       if (acpi_pci_disabled || !bus->bridge)
                return;
 
        acpiphp_remove_slots(bus);
index c0dbe1f61362aa058db84ffb971671a6ce35e8cd..7128cfdd64aa9d31c8628be30e7c65b33396dbfb 100644 (file)
@@ -131,19 +131,19 @@ static ssize_t pci_bus_show_cpuaffinity(struct device *dev,
        return ret;
 }
 
-static inline ssize_t pci_bus_show_cpumaskaffinity(struct device *dev,
-                                       struct device_attribute *attr,
-                                       char *buf)
+static ssize_t cpuaffinity_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
 {
        return pci_bus_show_cpuaffinity(dev, 0, attr, buf);
 }
+static DEVICE_ATTR_RO(cpuaffinity);
 
-static inline ssize_t pci_bus_show_cpulistaffinity(struct device *dev,
-                                       struct device_attribute *attr,
-                                       char *buf)
+static ssize_t cpulistaffinity_show(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
 {
        return pci_bus_show_cpuaffinity(dev, 1, attr, buf);
 }
+static DEVICE_ATTR_RO(cpulistaffinity);
 
 /* show resources */
 static ssize_t
@@ -379,6 +379,7 @@ dev_bus_rescan_store(struct device *dev, struct device_attribute *attr,
        }
        return count;
 }
+static DEVICE_ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, dev_bus_rescan_store);
 
 #if defined(CONFIG_PM_RUNTIME) && defined(CONFIG_ACPI)
 static ssize_t d3cold_allowed_store(struct device *dev,
@@ -514,11 +515,20 @@ struct device_attribute pci_dev_attrs[] = {
        __ATTR_NULL,
 };
 
-struct device_attribute pcibus_dev_attrs[] = {
-       __ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, dev_bus_rescan_store),
-       __ATTR(cpuaffinity, S_IRUGO, pci_bus_show_cpumaskaffinity, NULL),
-       __ATTR(cpulistaffinity, S_IRUGO, pci_bus_show_cpulistaffinity, NULL),
-       __ATTR_NULL,
+static struct attribute *pcibus_attrs[] = {
+       &dev_attr_rescan.attr,
+       &dev_attr_cpuaffinity.attr,
+       &dev_attr_cpulistaffinity.attr,
+       NULL,
+};
+
+static const struct attribute_group pcibus_group = {
+       .attrs = pcibus_attrs,
+};
+
+const struct attribute_group *pcibus_groups[] = {
+       &pcibus_group,
+       NULL,
 };
 
 static ssize_t
index e37fea6e178d2dab00d3334848d231117d525013..726f167df7c8f9108bcc248471a8ad20a752192f 100644 (file)
@@ -1992,7 +1992,7 @@ static void pci_add_saved_cap(struct pci_dev *pci_dev,
 }
 
 /**
- * pci_add_save_buffer - allocate buffer for saving given capability registers
+ * pci_add_cap_save_buffer - allocate buffer for saving given capability registers
  * @dev: the PCI device
  * @cap: the capability to allocate the buffer for
  * @size: requested size of the buffer
@@ -2359,6 +2359,27 @@ void pci_enable_acs(struct pci_dev *dev)
        pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl);
 }
 
+static bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags)
+{
+       int pos;
+       u16 cap, ctrl;
+
+       pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ACS);
+       if (!pos)
+               return false;
+
+       /*
+        * Except for egress control, capabilities are either required
+        * or only required if controllable.  Features missing from the
+        * capability field can therefore be assumed as hard-wired enabled.
+        */
+       pci_read_config_word(pdev, pos + PCI_ACS_CAP, &cap);
+       acs_flags &= (cap | PCI_ACS_EC);
+
+       pci_read_config_word(pdev, pos + PCI_ACS_CTRL, &ctrl);
+       return (ctrl & acs_flags) == acs_flags;
+}
+
 /**
  * pci_acs_enabled - test ACS against required flags for a given device
  * @pdev: device to test
@@ -2366,36 +2387,76 @@ void pci_enable_acs(struct pci_dev *dev)
  *
  * Return true if the device supports the provided flags.  Automatically
  * filters out flags that are not implemented on multifunction devices.
+ *
+ * Note that this interface checks the effective ACS capabilities of the
+ * device rather than the actual capabilities.  For instance, most single
+ * function endpoints are not required to support ACS because they have no
+ * opportunity for peer-to-peer access.  We therefore return 'true'
+ * regardless of whether the device exposes an ACS capability.  This makes
+ * it much easier for callers of this function to ignore the actual type
+ * or topology of the device when testing ACS support.
  */
 bool pci_acs_enabled(struct pci_dev *pdev, u16 acs_flags)
 {
-       int pos, ret;
-       u16 ctrl;
+       int ret;
 
        ret = pci_dev_specific_acs_enabled(pdev, acs_flags);
        if (ret >= 0)
                return ret > 0;
 
+       /*
+        * Conventional PCI and PCI-X devices never support ACS, either
+        * effectively or actually.  The shared bus topology implies that
+        * any device on the bus can receive or snoop DMA.
+        */
        if (!pci_is_pcie(pdev))
                return false;
 
-       /* Filter out flags not applicable to multifunction */
-       if (pdev->multifunction)
-               acs_flags &= (PCI_ACS_RR | PCI_ACS_CR |
-                             PCI_ACS_EC | PCI_ACS_DT);
-
-       if (pci_pcie_type(pdev) == PCI_EXP_TYPE_DOWNSTREAM ||
-           pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT ||
-           pdev->multifunction) {
-               pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ACS);
-               if (!pos)
-                       return false;
+       switch (pci_pcie_type(pdev)) {
+       /*
+        * PCI/X-to-PCIe bridges are not specifically mentioned by the spec,
+        * but since their primary inteface is PCI/X, we conservatively
+        * handle them as we would a non-PCIe device.
+        */
+       case PCI_EXP_TYPE_PCIE_BRIDGE:
+       /*
+        * PCIe 3.0, 6.12.1 excludes ACS on these devices.  "ACS is never
+        * applicable... must never implement an ACS Extended Capability...".
+        * This seems arbitrary, but we take a conservative interpretation
+        * of this statement.
+        */
+       case PCI_EXP_TYPE_PCI_BRIDGE:
+       case PCI_EXP_TYPE_RC_EC:
+               return false;
+       /*
+        * PCIe 3.0, 6.12.1.1 specifies that downstream and root ports should
+        * implement ACS in order to indicate their peer-to-peer capabilities,
+        * regardless of whether they are single- or multi-function devices.
+        */
+       case PCI_EXP_TYPE_DOWNSTREAM:
+       case PCI_EXP_TYPE_ROOT_PORT:
+               return pci_acs_flags_enabled(pdev, acs_flags);
+       /*
+        * PCIe 3.0, 6.12.1.2 specifies ACS capabilities that should be
+        * implemented by the remaining PCIe types to indicate peer-to-peer
+        * capabilities, but only when they are part of a multifunciton
+        * device.  The footnote for section 6.12 indicates the specific
+        * PCIe types included here.
+        */
+       case PCI_EXP_TYPE_ENDPOINT:
+       case PCI_EXP_TYPE_UPSTREAM:
+       case PCI_EXP_TYPE_LEG_END:
+       case PCI_EXP_TYPE_RC_END:
+               if (!pdev->multifunction)
+                       break;
 
-               pci_read_config_word(pdev, pos + PCI_ACS_CTRL, &ctrl);
-               if ((ctrl & acs_flags) != acs_flags)
-                       return false;
+               return pci_acs_flags_enabled(pdev, acs_flags);
        }
 
+       /*
+        * PCIe 3.0, 6.12.1.3 specifies no ACS capabilties are applicable
+        * to single function devices with the exception of downstream ports.
+        */
        return true;
 }
 
@@ -3578,6 +3639,49 @@ int pcie_set_mps(struct pci_dev *dev, int mps)
                                                  PCI_EXP_DEVCTL_PAYLOAD, v);
 }
 
+/**
+ * pcie_get_minimum_link - determine minimum link settings of a PCI device
+ * @dev: PCI device to query
+ * @speed: storage for minimum speed
+ * @width: storage for minimum width
+ *
+ * This function will walk up the PCI device chain and determine the minimum
+ * link width and speed of the device.
+ */
+int pcie_get_minimum_link(struct pci_dev *dev, enum pci_bus_speed *speed,
+                         enum pcie_link_width *width)
+{
+       int ret;
+
+       *speed = PCI_SPEED_UNKNOWN;
+       *width = PCIE_LNK_WIDTH_UNKNOWN;
+
+       while (dev) {
+               u16 lnksta;
+               enum pci_bus_speed next_speed;
+               enum pcie_link_width next_width;
+
+               ret = pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnksta);
+               if (ret)
+                       return ret;
+
+               next_speed = pcie_link_speed[lnksta & PCI_EXP_LNKSTA_CLS];
+               next_width = (lnksta & PCI_EXP_LNKSTA_NLW) >>
+                       PCI_EXP_LNKSTA_NLW_SHIFT;
+
+               if (next_speed < *speed)
+                       *speed = next_speed;
+
+               if (next_width < *width)
+                       *width = next_width;
+
+               dev = dev->bus->self;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(pcie_get_minimum_link);
+
 /**
  * pci_select_bars - Make BAR mask from the type of resource
  * @dev: the PCI device for which BAR mask is made
index d1182c4a754e235b25fb2914d658010d05157756..8a00c063d7bc67af7a3256fdd4a81c3d4d87f80b 100644 (file)
@@ -6,6 +6,9 @@
 #define PCI_CFG_SPACE_SIZE     256
 #define PCI_CFG_SPACE_EXP_SIZE 4096
 
+extern const unsigned char pcix_bus_speed[];
+extern const unsigned char pcie_link_speed[];
+
 /* Functions internal to the PCI core code */
 
 int pci_create_sysfs_dev_files(struct pci_dev *pdev);
@@ -151,7 +154,7 @@ static inline int pci_no_d1d2(struct pci_dev *dev)
 
 }
 extern struct device_attribute pci_dev_attrs[];
-extern struct device_attribute pcibus_dev_attrs[];
+extern const struct attribute_group *pcibus_groups[];
 extern struct device_type pci_dev_type;
 extern struct bus_attribute pci_bus_attrs[];
 
index 569f82fc9e22bb826fbfca36ba74b891cc15b0d8..7958e59d6077dcf341e4e76f8bfb902c3ef81e10 100644 (file)
@@ -2,7 +2,7 @@
 # PCI Express Port Bus Configuration
 #
 config PCIEPORTBUS
-       bool "PCI Express support"
+       bool "PCI Express Port Bus support"
        depends on PCI
        help
          This automatically enables PCI Express Port Bus support. Users can
@@ -14,15 +14,12 @@ config PCIEPORTBUS
 # Include service Kconfig here
 #
 config HOTPLUG_PCI_PCIE
-       tristate "PCI Express Hotplug driver"
+       bool "PCI Express Hotplug driver"
        depends on HOTPLUG_PCI && PCIEPORTBUS
        help
          Say Y here if you have a motherboard that supports PCI Express Native
          Hotplug
 
-         To compile this driver as a module, choose M here: the
-         module will be called pciehp.
-
          When in doubt, say N.
 
 source "drivers/pci/pcie/aer/Kconfig"
index 46ada5c098ebed710f24a7deb426720149b219fd..bfd56f9ae57c08341fd993656f0f800b6e219858 100644 (file)
@@ -96,7 +96,7 @@ static void release_pcibus_dev(struct device *dev)
 static struct class pcibus_class = {
        .name           = "pci_bus",
        .dev_release    = &release_pcibus_dev,
-       .dev_attrs      = pcibus_dev_attrs,
+       .dev_groups     = pcibus_groups,
 };
 
 static int __init pcibus_class_init(void)
@@ -513,7 +513,7 @@ static struct pci_host_bridge *pci_alloc_host_bridge(struct pci_bus *b)
        return bridge;
 }
 
-static unsigned char pcix_bus_speed[] = {
+const unsigned char pcix_bus_speed[] = {
        PCI_SPEED_UNKNOWN,              /* 0 */
        PCI_SPEED_66MHz_PCIX,           /* 1 */
        PCI_SPEED_100MHz_PCIX,          /* 2 */
@@ -532,7 +532,7 @@ static unsigned char pcix_bus_speed[] = {
        PCI_SPEED_133MHz_PCIX_533       /* F */
 };
 
-static unsigned char pcie_link_speed[] = {
+const unsigned char pcie_link_speed[] = {
        PCI_SPEED_UNKNOWN,              /* 0 */
        PCIE_SPEED_2_5GT,               /* 1 */
        PCIE_SPEED_5_0GT,               /* 2 */
index e85d23044ae0dcd43b20d0b840a71e551286a310..2e2ea2208f2eca1461254cf793ad2b3930231a6e 100644 (file)
@@ -3295,11 +3295,61 @@ struct pci_dev *pci_get_dma_source(struct pci_dev *dev)
        return pci_dev_get(dev);
 }
 
+/*
+ * AMD has indicated that the devices below do not support peer-to-peer
+ * in any system where they are found in the southbridge with an AMD
+ * IOMMU in the system.  Multifunction devices that do not support
+ * peer-to-peer between functions can claim to support a subset of ACS.
+ * Such devices effectively enable request redirect (RR) and completion
+ * redirect (CR) since all transactions are redirected to the upstream
+ * root complex.
+ *
+ * http://permalink.gmane.org/gmane.comp.emulators.kvm.devel/94086
+ * http://permalink.gmane.org/gmane.comp.emulators.kvm.devel/94102
+ * http://permalink.gmane.org/gmane.comp.emulators.kvm.devel/99402
+ *
+ * 1002:4385 SBx00 SMBus Controller
+ * 1002:439c SB7x0/SB8x0/SB9x0 IDE Controller
+ * 1002:4383 SBx00 Azalia (Intel HDA)
+ * 1002:439d SB7x0/SB8x0/SB9x0 LPC host controller
+ * 1002:4384 SBx00 PCI to PCI Bridge
+ * 1002:4399 SB7x0/SB8x0/SB9x0 USB OHCI2 Controller
+ */
+static int pci_quirk_amd_sb_acs(struct pci_dev *dev, u16 acs_flags)
+{
+#ifdef CONFIG_ACPI
+       struct acpi_table_header *header = NULL;
+       acpi_status status;
+
+       /* Targeting multifunction devices on the SB (appears on root bus) */
+       if (!dev->multifunction || !pci_is_root_bus(dev->bus))
+               return -ENODEV;
+
+       /* The IVRS table describes the AMD IOMMU */
+       status = acpi_get_table("IVRS", 0, &header);
+       if (ACPI_FAILURE(status))
+               return -ENODEV;
+
+       /* Filter out flags not applicable to multifunction */
+       acs_flags &= (PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_EC | PCI_ACS_DT);
+
+       return acs_flags & ~(PCI_ACS_RR | PCI_ACS_CR) ? 0 : 1;
+#else
+       return -ENODEV;
+#endif
+}
+
 static const struct pci_dev_acs_enabled {
        u16 vendor;
        u16 device;
        int (*acs_enabled)(struct pci_dev *dev, u16 acs_flags);
 } pci_dev_acs_enabled[] = {
+       { PCI_VENDOR_ID_ATI, 0x4385, pci_quirk_amd_sb_acs },
+       { PCI_VENDOR_ID_ATI, 0x439c, pci_quirk_amd_sb_acs },
+       { PCI_VENDOR_ID_ATI, 0x4383, pci_quirk_amd_sb_acs },
+       { PCI_VENDOR_ID_ATI, 0x439d, pci_quirk_amd_sb_acs },
+       { PCI_VENDOR_ID_ATI, 0x4384, pci_quirk_amd_sb_acs },
+       { PCI_VENDOR_ID_ATI, 0x4399, pci_quirk_amd_sb_acs },
        { 0 }
 };
 
index d254e237953382bb99768c7cca79b65c3b9aded8..64a7de22d9afe0edb548b3b20f96d7c288e53273 100644 (file)
@@ -300,6 +300,47 @@ static void assign_requested_resources_sorted(struct list_head *head,
        }
 }
 
+static unsigned long pci_fail_res_type_mask(struct list_head *fail_head)
+{
+       struct pci_dev_resource *fail_res;
+       unsigned long mask = 0;
+
+       /* check failed type */
+       list_for_each_entry(fail_res, fail_head, list)
+               mask |= fail_res->flags;
+
+       /*
+        * one pref failed resource will set IORESOURCE_MEM,
+        * as we can allocate pref in non-pref range.
+        * Will release all assigned non-pref sibling resources
+        * according to that bit.
+        */
+       return mask & (IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH);
+}
+
+static bool pci_need_to_release(unsigned long mask, struct resource *res)
+{
+       if (res->flags & IORESOURCE_IO)
+               return !!(mask & IORESOURCE_IO);
+
+       /* check pref at first */
+       if (res->flags & IORESOURCE_PREFETCH) {
+               if (mask & IORESOURCE_PREFETCH)
+                       return true;
+               /* count pref if its parent is non-pref */
+               else if ((mask & IORESOURCE_MEM) &&
+                        !(res->parent->flags & IORESOURCE_PREFETCH))
+                       return true;
+               else
+                       return false;
+       }
+
+       if (res->flags & IORESOURCE_MEM)
+               return !!(mask & IORESOURCE_MEM);
+
+       return false;   /* should not get here */
+}
+
 static void __assign_resources_sorted(struct list_head *head,
                                 struct list_head *realloc_head,
                                 struct list_head *fail_head)
@@ -312,11 +353,24 @@ static void __assign_resources_sorted(struct list_head *head,
         *  if could do that, could get out early.
         *  if could not do that, we still try to assign requested at first,
         *    then try to reassign add_size for some resources.
+        *
+        * Separate three resource type checking if we need to release
+        * assigned resource after requested + add_size try.
+        *      1. if there is io port assign fail, will release assigned
+        *         io port.
+        *      2. if there is pref mmio assign fail, release assigned
+        *         pref mmio.
+        *         if assigned pref mmio's parent is non-pref mmio and there
+        *         is non-pref mmio assign fail, will release that assigned
+        *         pref mmio.
+        *      3. if there is non-pref mmio assign fail or pref mmio
+        *         assigned fail, will release assigned non-pref mmio.
         */
        LIST_HEAD(save_head);
        LIST_HEAD(local_fail_head);
        struct pci_dev_resource *save_res;
-       struct pci_dev_resource *dev_res;
+       struct pci_dev_resource *dev_res, *tmp_res;
+       unsigned long fail_type;
 
        /* Check if optional add_size is there */
        if (!realloc_head || list_empty(realloc_head))
@@ -348,6 +402,19 @@ static void __assign_resources_sorted(struct list_head *head,
                return;
        }
 
+       /* check failed type */
+       fail_type = pci_fail_res_type_mask(&local_fail_head);
+       /* remove not need to be released assigned res from head list etc */
+       list_for_each_entry_safe(dev_res, tmp_res, head, list)
+               if (dev_res->res->parent &&
+                   !pci_need_to_release(fail_type, dev_res->res)) {
+                       /* remove it from realloc_head list */
+                       remove_from_list(realloc_head, dev_res->res);
+                       remove_from_list(&save_head, dev_res->res);
+                       list_del(&dev_res->list);
+                       kfree(dev_res);
+               }
+
        free_list(&local_fail_head);
        /* Release assigned resource */
        list_for_each_entry(dev_res, head, list)
index 8e268da6fdbd56f154c5cf1d12bc70a654bea1df..0e9c169b42f82a782b1166b2c05880ad4e1ad0da 100644 (file)
@@ -1543,7 +1543,6 @@ static void asus_acpi_notify(struct acpi_device *device, u32 event)
 
        /* TODO Find a better way to handle events count. */
        count = asus->event_count[event % 128]++;
-       acpi_bus_generate_proc_event(asus->device, event, count);
        acpi_bus_generate_netlink_event(asus->device->pnp.device_class,
                                        dev_name(&asus->device->dev), event,
                                        count);
index 5d26e70bed6c532d51c0fb326bc97f91e1a8a020..a6afd4108beb0592c15604efa9f779180d5349ef 100644 (file)
@@ -1269,7 +1269,6 @@ static void eeepc_acpi_notify(struct acpi_device *device, u32 event)
        if (event > ACPI_MAX_SYS_NOTIFY)
                return;
        count = eeepc->event_count[event % 128]++;
-       acpi_bus_generate_proc_event(device, event, count);
        acpi_bus_generate_netlink_event(device->pnp.device_class,
                                        dev_name(&device->dev), event,
                                        count);
index 1c9386e7c58ce723ca583714b862604cbcfd25e5..52b8a97efde150f52d393b4e7a6c0be9360bc9ef 100644 (file)
@@ -773,8 +773,6 @@ static void acpi_fujitsu_notify(struct acpi_device *device, u32 event)
                                else
                                        set_lcd_level(newb);
                        }
-                       acpi_bus_generate_proc_event(fujitsu->dev,
-                               ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS, 0);
                        keycode = KEY_BRIGHTNESSUP;
                } else if (oldb > newb) {
                        if (disable_brightness_adjust != 1) {
@@ -783,8 +781,6 @@ static void acpi_fujitsu_notify(struct acpi_device *device, u32 event)
                                else
                                        set_lcd_level(newb);
                        }
-                       acpi_bus_generate_proc_event(fujitsu->dev,
-                               ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS, 0);
                        keycode = KEY_BRIGHTNESSDOWN;
                }
                break;
index 4add9a31bf601cf151c5f0b6ce938de73ba0aa96..984253da365d88426db4e398311e28a2489659e2 100644 (file)
@@ -464,9 +464,6 @@ static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc)
                                 "error getting hotkey status\n"));
                return;
        }
-
-       acpi_bus_generate_proc_event(pcc->device, HKEY_NOTIFY, result);
-
        if (!sparse_keymap_report_event(hotk_input_dev,
                                        result & 0xf, result & 0x80, false))
                ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
index 2ac045f27f10112aa467b867a9b97a9a1790c189..069821b1fc22a9b139c355a675ec51036856820c 100644 (file)
@@ -1275,9 +1275,6 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
                ev_type = HOTKEY;
                sony_laptop_report_input_event(real_ev);
        }
-
-       acpi_bus_generate_proc_event(sony_nc_acpi_device, ev_type, real_ev);
-
        acpi_bus_generate_netlink_event(sony_nc_acpi_device->pnp.device_class,
                        dev_name(&sony_nc_acpi_device->dev), ev_type, real_ev);
 }
@@ -4243,7 +4240,6 @@ static irqreturn_t sony_pic_irq(int irq, void *dev_id)
 
 found:
        sony_laptop_report_input_event(device_event);
-       acpi_bus_generate_proc_event(dev->acpi_dev, 1, device_event);
        sonypi_compat_report_event(device_event);
        return IRQ_HANDLED;
 }
index 54d31c0a9840b45e34e910af232137d4d349d711..be67e5e28d188e07766dd1a1e164c7c76c183693 100644 (file)
@@ -2022,8 +2022,6 @@ static u32 hotkey_driver_mask;            /* events needed by the driver */
 static u32 hotkey_user_mask;           /* events visible to userspace */
 static u32 hotkey_acpi_mask;           /* events enabled in firmware */
 
-static unsigned int hotkey_report_mode;
-
 static u16 *hotkey_keycode_map;
 
 static struct attribute_set *hotkey_dev_attributes;
@@ -2282,10 +2280,6 @@ static struct tp_acpi_drv_struct ibm_hotkey_acpidriver;
 static void tpacpi_hotkey_send_key(unsigned int scancode)
 {
        tpacpi_input_send_key_masked(scancode);
-       if (hotkey_report_mode < 2) {
-               acpi_bus_generate_proc_event(ibm_hotkey_acpidriver.device,
-                               0x80, TP_HKEY_EV_HOTKEY_BASE + scancode);
-       }
 }
 
 static void hotkey_read_nvram(struct tp_nvram_state *n, const u32 m)
@@ -2882,18 +2876,6 @@ static void hotkey_tablet_mode_notify_change(void)
                             "hotkey_tablet_mode");
 }
 
-/* sysfs hotkey report_mode -------------------------------------------- */
-static ssize_t hotkey_report_mode_show(struct device *dev,
-                          struct device_attribute *attr,
-                          char *buf)
-{
-       return snprintf(buf, PAGE_SIZE, "%d\n",
-               (hotkey_report_mode != 0) ? hotkey_report_mode : 1);
-}
-
-static struct device_attribute dev_attr_hotkey_report_mode =
-       __ATTR(hotkey_report_mode, S_IRUGO, hotkey_report_mode_show, NULL);
-
 /* sysfs wakeup reason (pollable) -------------------------------------- */
 static ssize_t hotkey_wakeup_reason_show(struct device *dev,
                           struct device_attribute *attr,
@@ -2935,7 +2917,6 @@ static struct attribute *hotkey_attributes[] __initdata = {
        &dev_attr_hotkey_enable.attr,
        &dev_attr_hotkey_bios_enabled.attr,
        &dev_attr_hotkey_bios_mask.attr,
-       &dev_attr_hotkey_report_mode.attr,
        &dev_attr_hotkey_wakeup_reason.attr,
        &dev_attr_hotkey_wakeup_hotunplug_complete.attr,
        &dev_attr_hotkey_mask.attr,
@@ -3439,11 +3420,6 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
                "initial masks: user=0x%08x, fw=0x%08x, poll=0x%08x\n",
                hotkey_user_mask, hotkey_acpi_mask, hotkey_source_mask);
 
-       dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
-                       "legacy ibm/hotkey event reporting over procfs %s\n",
-                       (hotkey_report_mode < 2) ?
-                               "enabled" : "disabled");
-
        tpacpi_inputdev->open = &hotkey_inputdev_open;
        tpacpi_inputdev->close = &hotkey_inputdev_close;
 
@@ -3737,13 +3713,6 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
                                  "event happened to %s\n", TPACPI_MAIL);
                }
 
-               /* Legacy events */
-               if (!ignore_acpi_ev &&
-                   (send_acpi_ev || hotkey_report_mode < 2)) {
-                       acpi_bus_generate_proc_event(ibm->acpi->device,
-                                                    event, hkey);
-               }
-
                /* netlink events */
                if (!ignore_acpi_ev && send_acpi_ev) {
                        acpi_bus_generate_netlink_event(
@@ -8840,11 +8809,6 @@ module_param(brightness_enable, uint, 0444);
 MODULE_PARM_DESC(brightness_enable,
                 "Enables backlight control when 1, disables when 0");
 
-module_param(hotkey_report_mode, uint, 0444);
-MODULE_PARM_DESC(hotkey_report_mode,
-                "used for backwards compatibility with userspace, "
-                "see documentation");
-
 #ifdef CONFIG_THINKPAD_ACPI_ALSA_SUPPORT
 module_param_named(volume_mode, volume_mode, uint, 0444);
 MODULE_PARM_DESC(volume_mode,
@@ -8975,10 +8939,6 @@ static int __init thinkpad_acpi_module_init(void)
 
        tpacpi_lifecycle = TPACPI_LIFE_INIT;
 
-       /* Parameter checking */
-       if (hotkey_report_mode > 2)
-               return -EINVAL;
-
        /* Driver-level probe */
 
        ret = get_thinkpad_model_data(&thinkpad_id);
index 00e94032531a71c121b6a222efa14338e08ff6b3..12adb43a069317da31958ac4913418c385cedb77 100644 (file)
@@ -154,7 +154,7 @@ static int pnp_bus_match(struct device *dev, struct device_driver *drv)
        return 1;
 }
 
-static int pnp_bus_suspend(struct device *dev, pm_message_t state)
+static int __pnp_bus_suspend(struct device *dev, pm_message_t state)
 {
        struct pnp_dev *pnp_dev = to_pnp_dev(dev);
        struct pnp_driver *pnp_drv = pnp_dev->driver;
@@ -180,6 +180,16 @@ static int pnp_bus_suspend(struct device *dev, pm_message_t state)
        return 0;
 }
 
+static int pnp_bus_suspend(struct device *dev)
+{
+       return __pnp_bus_suspend(dev, PMSG_SUSPEND);
+}
+
+static int pnp_bus_freeze(struct device *dev)
+{
+       return __pnp_bus_suspend(dev, PMSG_FREEZE);
+}
+
 static int pnp_bus_resume(struct device *dev)
 {
        struct pnp_dev *pnp_dev = to_pnp_dev(dev);
@@ -210,14 +220,19 @@ static int pnp_bus_resume(struct device *dev)
        return 0;
 }
 
+static const struct dev_pm_ops pnp_bus_dev_pm_ops = {
+       .suspend = pnp_bus_suspend,
+       .freeze = pnp_bus_freeze,
+       .resume = pnp_bus_resume,
+};
+
 struct bus_type pnp_bus_type = {
        .name    = "pnp",
        .match   = pnp_bus_match,
        .probe   = pnp_device_probe,
        .remove  = pnp_device_remove,
        .shutdown = pnp_device_shutdown,
-       .suspend = pnp_bus_suspend,
-       .resume  = pnp_bus_resume,
+       .pm      = &pnp_bus_dev_pm_ops,
        .dev_attrs = pnp_interface_attrs,
 };
 
index 55cd459a39080d6d162074c74772e9850d88c8f1..34049b0b4c731e352ae48f62c7fd3edcfc71b517 100644 (file)
@@ -131,7 +131,7 @@ static int pnpacpi_disable_resources(struct pnp_dev *dev)
        /* acpi_unregister_gsi(pnp_irq(dev, 0)); */
        ret = 0;
        if (acpi_bus_power_manageable(handle))
-               acpi_bus_set_power(handle, ACPI_STATE_D3);
+               acpi_bus_set_power(handle, ACPI_STATE_D3_COLD);
                /* continue even if acpi_bus_set_power() fails */
        if (ACPI_FAILURE(acpi_evaluate_object(handle, "_DIS", NULL, NULL)))
                ret = -ENODEV;
@@ -174,10 +174,10 @@ static int pnpacpi_suspend(struct pnp_dev *dev, pm_message_t state)
 
        if (acpi_bus_power_manageable(handle)) {
                int power_state = acpi_pm_device_sleep_state(&dev->dev, NULL,
-                                                            ACPI_STATE_D3);
+                                                       ACPI_STATE_D3_COLD);
                if (power_state < 0)
                        power_state = (state.event == PM_EVENT_ON) ?
-                                       ACPI_STATE_D0 : ACPI_STATE_D3;
+                                       ACPI_STATE_D0 : ACPI_STATE_D3_COLD;
 
                /*
                 * acpi_bus_set_power() often fails (keyboard port can't be
index f4f30af2df68c682744cc125ede61da5f87eb4d1..2e8a20cac58848cdd0e2afa6201f3f82f4a88e84 100644 (file)
@@ -1715,11 +1715,13 @@ int rio_unregister_scan(int mport_id, struct rio_scan *scan_ops)
                    (mport_id == RIO_MPORT_ANY && port->nscan == scan_ops))
                        port->nscan = NULL;
 
-       list_for_each_entry(scan, &rio_scans, node)
+       list_for_each_entry(scan, &rio_scans, node) {
                if (scan->mport_id == mport_id) {
                        list_del(&scan->node);
                        kfree(scan);
+                       break;
                }
+       }
 
        mutex_unlock(&rio_mport_list_lock);
 
index 02faf3c4e0d51d13cd6fd7c55b2de4f09776f08f..c2e80d7ca5e26b618a19bfc5aac45e8497651082 100644 (file)
@@ -524,6 +524,8 @@ static int twl_rtc_probe(struct platform_device *pdev)
        if (ret < 0)
                goto out1;
 
+       device_init_wakeup(&pdev->dev, 1);
+
        rtc = rtc_device_register(pdev->name,
                                  &pdev->dev, &twl_rtc_ops, THIS_MODULE);
        if (IS_ERR(rtc)) {
@@ -542,7 +544,6 @@ static int twl_rtc_probe(struct platform_device *pdev)
        }
 
        platform_set_drvdata(pdev, rtc);
-       device_init_wakeup(&pdev->dev, 1);
        return 0;
 
 out2:
index 17150a77898433c27e58b2a8ac9ccb81bd228ddb..451bf99582ff09948c04e6634ca2d381c0d6a45a 100644 (file)
@@ -2392,6 +2392,12 @@ int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr)
                rc = cqr->intrc;
        else
                rc = -EIO;
+
+       /* kick tasklets */
+       dasd_schedule_device_bh(device);
+       if (device->block)
+               dasd_schedule_block_bh(device->block);
+
        return rc;
 }
 
index 58bc6eb49de1da7ee1e3061a7ade5865f1c8d800..2ead7e78c4568ec7fe50ece74c3109d424efa852 100644 (file)
@@ -930,7 +930,7 @@ dasd_use_raw_store(struct device *dev, struct device_attribute *attr,
        if (IS_ERR(devmap))
                return PTR_ERR(devmap);
 
-       if ((strict_strtoul(buf, 10, &val) != 0) || val > 1)
+       if ((kstrtoul(buf, 10, &val) != 0) || val > 1)
                return -EINVAL;
 
        spin_lock(&dasd_devmap_lock);
@@ -1225,7 +1225,7 @@ dasd_expires_store(struct device *dev, struct device_attribute *attr,
        if (IS_ERR(device))
                return -ENODEV;
 
-       if ((strict_strtoul(buf, 10, &val) != 0) ||
+       if ((kstrtoul(buf, 10, &val) != 0) ||
            (val > DASD_EXPIRES_MAX) || val == 0) {
                dasd_put_device(device);
                return -EINVAL;
@@ -1265,7 +1265,7 @@ dasd_retries_store(struct device *dev, struct device_attribute *attr,
        if (IS_ERR(device))
                return -ENODEV;
 
-       if ((strict_strtoul(buf, 10, &val) != 0) ||
+       if ((kstrtoul(buf, 10, &val) != 0) ||
            (val > DASD_RETRIES_MAX)) {
                dasd_put_device(device);
                return -EINVAL;
@@ -1307,7 +1307,7 @@ dasd_timeout_store(struct device *dev, struct device_attribute *attr,
        if (IS_ERR(device) || !device->block)
                return -ENODEV;
 
-       if ((strict_strtoul(buf, 10, &val) != 0) ||
+       if ((kstrtoul(buf, 10, &val) != 0) ||
            val > UINT_MAX / HZ) {
                dasd_put_device(device);
                return -EINVAL;
index 8d11f773a75224a74745f20a03be731ea9dad267..ba99b64e2b3f0fea3b5c04c15b66bcd4f2d5ea3c 100644 (file)
@@ -160,11 +160,13 @@ dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb)
 
        device = cqr->startdev;
        if (cqr->intrc == -ETIMEDOUT) {
-               dev_err(&device->cdev->dev, "cqr %p timeout error", cqr);
+               dev_err(&device->cdev->dev,
+                       "A timeout error occurred for cqr %p", cqr);
                return;
        }
        if (cqr->intrc == -ENOLINK) {
-               dev_err(&device->cdev->dev, "cqr %p transport error", cqr);
+               dev_err(&device->cdev->dev,
+                       "A transport error occurred for cqr %p", cqr);
                return;
        }
        /* dump sense data */
index 444d36183a251c38e2c72fda8084ac33f3bd358b..944156207477448ba0e48393212923fee2abfb16 100644 (file)
@@ -32,7 +32,7 @@ static void sclp_cpu_capability_notify(struct work_struct *work)
        struct device *dev;
 
        s390_adjust_jiffies();
-       pr_warning("cpu capability changed.\n");
+       pr_info("CPU capability may have changed\n");
        get_online_cpus();
        for_each_online_cpu(cpu) {
                dev = get_cpu_device(cpu);
index 91edbd7ee80640d7d624280722843cbfb69093a8..477701822db12e860a7cc8b1d58a5b1f01487252 100644 (file)
@@ -81,15 +81,172 @@ void unregister_adapter_interrupt(struct airq_struct *airq)
 }
 EXPORT_SYMBOL(unregister_adapter_interrupt);
 
-void do_adapter_IO(u8 isc)
+static irqreturn_t do_airq_interrupt(int irq, void *dummy)
 {
+       struct tpi_info *tpi_info;
        struct airq_struct *airq;
        struct hlist_head *head;
 
-       head = &airq_lists[isc];
+       __this_cpu_write(s390_idle.nohz_delay, 1);
+       tpi_info = (struct tpi_info *) &get_irq_regs()->int_code;
+       head = &airq_lists[tpi_info->isc];
        rcu_read_lock();
        hlist_for_each_entry_rcu(airq, head, list)
                if ((*airq->lsi_ptr & airq->lsi_mask) != 0)
                        airq->handler(airq);
        rcu_read_unlock();
+
+       return IRQ_HANDLED;
+}
+
+static struct irqaction airq_interrupt = {
+       .name    = "AIO",
+       .handler = do_airq_interrupt,
+};
+
+void __init init_airq_interrupts(void)
+{
+       irq_set_chip_and_handler(THIN_INTERRUPT,
+                                &dummy_irq_chip, handle_percpu_irq);
+       setup_irq(THIN_INTERRUPT, &airq_interrupt);
+}
+
+/**
+ * airq_iv_create - create an interrupt vector
+ * @bits: number of bits in the interrupt vector
+ * @flags: allocation flags
+ *
+ * Returns a pointer to an interrupt vector structure
+ */
+struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags)
+{
+       struct airq_iv *iv;
+       unsigned long size;
+
+       iv = kzalloc(sizeof(*iv), GFP_KERNEL);
+       if (!iv)
+               goto out;
+       iv->bits = bits;
+       size = BITS_TO_LONGS(bits) * sizeof(unsigned long);
+       iv->vector = kzalloc(size, GFP_KERNEL);
+       if (!iv->vector)
+               goto out_iv;
+       if (flags & AIRQ_IV_ALLOC) {
+               iv->avail = kmalloc(size, GFP_KERNEL);
+               if (!iv->avail)
+                       goto out_vector;
+               memset(iv->avail, 0xff, size);
+               iv->end = 0;
+       } else
+               iv->end = bits;
+       if (flags & AIRQ_IV_DATA) {
+               size = bits * sizeof(unsigned int);
+               iv->data = kzalloc(size, GFP_KERNEL);
+               if (!iv->data)
+                       goto out_alloc;
+       }
+       spin_lock_init(&iv->lock);
+       return iv;
+
+out_alloc:
+       kfree(iv->avail);
+out_vector:
+       kfree(iv->vector);
+out_iv:
+       kfree(iv);
+out:
+       return NULL;
+}
+EXPORT_SYMBOL(airq_iv_create);
+
+/**
+ * airq_iv_release - release an interrupt vector
+ * @iv: pointer to interrupt vector structure
+ */
+void airq_iv_release(struct airq_iv *iv)
+{
+       kfree(iv->data);
+       kfree(iv->vector);
+       kfree(iv->avail);
+       kfree(iv);
+}
+EXPORT_SYMBOL(airq_iv_release);
+
+/**
+ * airq_iv_alloc_bit - allocate an irq bit from an interrupt vector
+ * @iv: pointer to an interrupt vector structure
+ *
+ * Returns the bit number of the allocated irq, or -1UL if no bit
+ * is available or the AIRQ_IV_ALLOC flag has not been specified
+ */
+unsigned long airq_iv_alloc_bit(struct airq_iv *iv)
+{
+       const unsigned long be_to_le = BITS_PER_LONG - 1;
+       unsigned long bit;
+
+       if (!iv->avail)
+               return -1UL;
+       spin_lock(&iv->lock);
+       bit = find_first_bit_left(iv->avail, iv->bits);
+       if (bit < iv->bits) {
+               clear_bit(bit ^ be_to_le, iv->avail);
+               if (bit >= iv->end)
+                       iv->end = bit + 1;
+       } else
+               bit = -1UL;
+       spin_unlock(&iv->lock);
+       return bit;
+
+}
+EXPORT_SYMBOL(airq_iv_alloc_bit);
+
+/**
+ * airq_iv_free_bit - free an irq bit of an interrupt vector
+ * @iv: pointer to interrupt vector structure
+ * @bit: number of the irq bit to free
+ */
+void airq_iv_free_bit(struct airq_iv *iv, unsigned long bit)
+{
+       const unsigned long be_to_le = BITS_PER_LONG - 1;
+
+       if (!iv->avail)
+               return;
+       spin_lock(&iv->lock);
+       /* Clear (possibly left over) interrupt bit */
+       clear_bit(bit ^ be_to_le, iv->vector);
+       /* Make the bit position available again */
+       set_bit(bit ^ be_to_le, iv->avail);
+       if (bit == iv->end - 1) {
+               /* Find new end of bit-field */
+               while (--iv->end > 0)
+                       if (!test_bit((iv->end - 1) ^ be_to_le, iv->avail))
+                               break;
+       }
+       spin_unlock(&iv->lock);
+}
+EXPORT_SYMBOL(airq_iv_free_bit);
+
+/**
+ * airq_iv_scan - scan interrupt vector for non-zero bits
+ * @iv: pointer to interrupt vector structure
+ * @start: bit number to start the search
+ * @end: bit number to end the search
+ *
+ * Returns the bit number of the next non-zero interrupt bit, or
+ * -1UL if the scan completed without finding any more any non-zero bits.
+ */
+unsigned long airq_iv_scan(struct airq_iv *iv, unsigned long start,
+                          unsigned long end)
+{
+       const unsigned long be_to_le = BITS_PER_LONG - 1;
+       unsigned long bit;
+
+       /* Find non-zero bit starting from 'ivs->next'. */
+       bit = find_next_bit_left(iv->vector, end, start);
+       if (bit >= end)
+               return -1UL;
+       /* Clear interrupt bit (find left uses big-endian bit numbers) */
+       clear_bit(bit ^ be_to_le, iv->vector);
+       return bit;
 }
+EXPORT_SYMBOL(airq_iv_scan);
index 84846c2b96d34bdf3f0f1461038d76c9627e2704..959135a01847940a5ecee33ae902b83cf8ecfe44 100644 (file)
@@ -137,7 +137,7 @@ static ssize_t ccwgroup_online_store(struct device *dev,
        if (!try_module_get(gdrv->driver.owner))
                return -EINVAL;
 
-       ret = strict_strtoul(buf, 0, &value);
+       ret = kstrtoul(buf, 0, &value);
        if (ret)
                goto out;
 
index 4eeb4a6bf2074cd0f72a988ab6ee5f5ea23cb764..d7da67a31c77f606ef68445f9da446b521a4abf1 100644 (file)
@@ -561,37 +561,23 @@ out:
 }
 
 /*
- * do_IRQ() handles all normal I/O device IRQ's (the special
- *         SMP cross-CPU interrupts have their own specific
- *         handlers).
- *
+ * do_cio_interrupt() handles all normal I/O device IRQ's
  */
-void __irq_entry do_IRQ(struct pt_regs *regs)
+static irqreturn_t do_cio_interrupt(int irq, void *dummy)
 {
-       struct tpi_info *tpi_info = (struct tpi_info *) &regs->int_code;
+       struct tpi_info *tpi_info;
        struct subchannel *sch;
        struct irb *irb;
-       struct pt_regs *old_regs;
 
-       old_regs = set_irq_regs(regs);
-       irq_enter();
        __this_cpu_write(s390_idle.nohz_delay, 1);
-       if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator)
-               /* Serve timer interrupts first. */
-               clock_comparator_work();
-
-       kstat_incr_irqs_this_cpu(IO_INTERRUPT, NULL);
+       tpi_info = (struct tpi_info *) &get_irq_regs()->int_code;
        irb = (struct irb *) &S390_lowcore.irb;
-       if (tpi_info->adapter_IO) {
-               do_adapter_IO(tpi_info->isc);
-               goto out;
-       }
        sch = (struct subchannel *)(unsigned long) tpi_info->intparm;
        if (!sch) {
                /* Clear pending interrupt condition. */
                inc_irq_stat(IRQIO_CIO);
                tsch(tpi_info->schid, irb);
-               goto out;
+               return IRQ_HANDLED;
        }
        spin_lock(sch->lock);
        /* Store interrupt response block to lowcore. */
@@ -606,9 +592,23 @@ void __irq_entry do_IRQ(struct pt_regs *regs)
        } else
                inc_irq_stat(IRQIO_CIO);
        spin_unlock(sch->lock);
-out:
-       irq_exit();
-       set_irq_regs(old_regs);
+
+       return IRQ_HANDLED;
+}
+
+static struct irq_desc *irq_desc_io;
+
+static struct irqaction io_interrupt = {
+       .name    = "IO",
+       .handler = do_cio_interrupt,
+};
+
+void __init init_cio_interrupts(void)
+{
+       irq_set_chip_and_handler(IO_INTERRUPT,
+                                &dummy_irq_chip, handle_percpu_irq);
+       setup_irq(IO_INTERRUPT, &io_interrupt);
+       irq_desc_io = irq_to_desc(IO_INTERRUPT);
 }
 
 #ifdef CONFIG_CCW_CONSOLE
@@ -635,7 +635,7 @@ void cio_tsch(struct subchannel *sch)
                local_bh_disable();
                irq_enter();
        }
-       kstat_incr_irqs_this_cpu(IO_INTERRUPT, NULL);
+       kstat_incr_irqs_this_cpu(IO_INTERRUPT, irq_desc_io);
        if (sch->driver && sch->driver->irq)
                sch->driver->irq(sch);
        else
index d62f5e7f3cf100c217718614edabea5d5470a151..d42f67412bd895b7b5e7857bf1f168d47e3bd3db 100644 (file)
@@ -121,9 +121,6 @@ extern int cio_commit_config(struct subchannel *sch);
 int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key);
 int cio_tm_intrg(struct subchannel *sch);
 
-void do_adapter_IO(u8 isc);
-void do_IRQ(struct pt_regs *);
-
 /* Use with care. */
 #ifdef CONFIG_CCW_CONSOLE
 extern struct subchannel *cio_probe_console(void);
index 4495e0627a40ad8168fe99c34d90c82adc960ee5..23054f8fa9fc2ef8735caed6bdf4d53dc557cf9e 100644 (file)
@@ -1182,7 +1182,7 @@ static ssize_t cmb_enable_store(struct device *dev,
        int ret;
        unsigned long val;
 
-       ret = strict_strtoul(buf, 16, &val);
+       ret = kstrtoul(buf, 16, &val);
        if (ret)
                return ret;
 
index 1ebe5d3ddebb28e7caddb0ec742bc76ce1307f78..4eb2a54e64f25c5f2e9221645e14a9d79d952b9b 100644 (file)
@@ -740,7 +740,7 @@ css_cm_enable_store(struct device *dev, struct device_attribute *attr,
        int ret;
        unsigned long val;
 
-       ret = strict_strtoul(buf, 16, &val);
+       ret = kstrtoul(buf, 16, &val);
        if (ret)
                return ret;
        mutex_lock(&css->mutex);
index 1ab5f6c36d9b4439db490797ca62aa239f04f7fa..e4a7ab2bb629f76358896e1389072c391fe3504c 100644 (file)
@@ -564,7 +564,7 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr,
                ret = 0;
        } else {
                force = 0;
-               ret = strict_strtoul(buf, 16, &i);
+               ret = kstrtoul(buf, 16, &i);
        }
        if (ret)
                goto out;
index d1c8025b0b037605c73f331b6ebd3178feed2767..adef5f5de118a7ed9b320b3cea07672bc511ec36 100644 (file)
@@ -208,7 +208,7 @@ static ssize_t qeth_l3_dev_sniffer_store(struct device *dev,
                goto out;
        }
 
-       rc = strict_strtoul(buf, 16, &i);
+       rc = kstrtoul(buf, 16, &i);
        if (rc) {
                rc = -EINVAL;
                goto out;
index f2db5fe7bdc2ba8f8a9c0cbb8458593494eef98a..62f00da09ad1b42f29f812f3ff8dc583ff850130 100644 (file)
@@ -581,8 +581,10 @@ struct iscsi_kwqe_init1 {
 #define ISCSI_KWQE_INIT1_DELAYED_ACK_ENABLE_SHIFT 4
 #define ISCSI_KWQE_INIT1_KEEP_ALIVE_ENABLE (0x1<<5)
 #define ISCSI_KWQE_INIT1_KEEP_ALIVE_ENABLE_SHIFT 5
-#define ISCSI_KWQE_INIT1_RESERVED1 (0x3<<6)
-#define ISCSI_KWQE_INIT1_RESERVED1_SHIFT 6
+#define ISCSI_KWQE_INIT1_TIME_STAMPS_ENABLE (0x1<<6)
+#define ISCSI_KWQE_INIT1_TIME_STAMPS_ENABLE_SHIFT 6
+#define ISCSI_KWQE_INIT1_RESERVED1 (0x1<<7)
+#define ISCSI_KWQE_INIT1_RESERVED1_SHIFT 7
        u16 cq_num_wqes;
 #elif defined(__LITTLE_ENDIAN)
        u16 cq_num_wqes;
@@ -593,8 +595,10 @@ struct iscsi_kwqe_init1 {
 #define ISCSI_KWQE_INIT1_DELAYED_ACK_ENABLE_SHIFT 4
 #define ISCSI_KWQE_INIT1_KEEP_ALIVE_ENABLE (0x1<<5)
 #define ISCSI_KWQE_INIT1_KEEP_ALIVE_ENABLE_SHIFT 5
-#define ISCSI_KWQE_INIT1_RESERVED1 (0x3<<6)
-#define ISCSI_KWQE_INIT1_RESERVED1_SHIFT 6
+#define ISCSI_KWQE_INIT1_TIME_STAMPS_ENABLE (0x1<<6)
+#define ISCSI_KWQE_INIT1_TIME_STAMPS_ENABLE_SHIFT 6
+#define ISCSI_KWQE_INIT1_RESERVED1 (0x1<<7)
+#define ISCSI_KWQE_INIT1_RESERVED1_SHIFT 7
        u8 cq_log_wqes_per_page;
 #endif
 #if defined(__BIG_ENDIAN)
index 34552bf1c023d6468af7aea32afcc70ab0f88953..55548dc5cec39da14ec4b23c33ae4d1a609d30e6 100644 (file)
@@ -530,7 +530,7 @@ static int esp_need_to_nego_sync(struct esp_target_data *tp)
 static int esp_alloc_lun_tag(struct esp_cmd_entry *ent,
                             struct esp_lun_data *lp)
 {
-       if (!ent->tag[0]) {
+       if (!ent->orig_tag[0]) {
                /* Non-tagged, slot already taken?  */
                if (lp->non_tagged_cmd)
                        return -EBUSY;
@@ -564,9 +564,9 @@ static int esp_alloc_lun_tag(struct esp_cmd_entry *ent,
                        return -EBUSY;
        }
 
-       BUG_ON(lp->tagged_cmds[ent->tag[1]]);
+       BUG_ON(lp->tagged_cmds[ent->orig_tag[1]]);
 
-       lp->tagged_cmds[ent->tag[1]] = ent;
+       lp->tagged_cmds[ent->orig_tag[1]] = ent;
        lp->num_tagged++;
 
        return 0;
@@ -575,9 +575,9 @@ static int esp_alloc_lun_tag(struct esp_cmd_entry *ent,
 static void esp_free_lun_tag(struct esp_cmd_entry *ent,
                             struct esp_lun_data *lp)
 {
-       if (ent->tag[0]) {
-               BUG_ON(lp->tagged_cmds[ent->tag[1]] != ent);
-               lp->tagged_cmds[ent->tag[1]] = NULL;
+       if (ent->orig_tag[0]) {
+               BUG_ON(lp->tagged_cmds[ent->orig_tag[1]] != ent);
+               lp->tagged_cmds[ent->orig_tag[1]] = NULL;
                lp->num_tagged--;
        } else {
                BUG_ON(lp->non_tagged_cmd != ent);
@@ -667,6 +667,8 @@ static struct esp_cmd_entry *find_and_prep_issuable_command(struct esp *esp)
                        ent->tag[0] = 0;
                        ent->tag[1] = 0;
                }
+               ent->orig_tag[0] = ent->tag[0];
+               ent->orig_tag[1] = ent->tag[1];
 
                if (esp_alloc_lun_tag(ent, lp) < 0)
                        continue;
index 28e22acf87ea94f9c703086689da850174495573..cd68805e8d787e1d2ca9acaedd667d87bc201eb7 100644 (file)
@@ -271,6 +271,7 @@ struct esp_cmd_entry {
 #define ESP_CMD_FLAG_AUTOSENSE 0x04 /* Doing automatic REQUEST_SENSE */
 
        u8                      tag[2];
+       u8                      orig_tag[2];
 
        u8                      status;
        u8                      message;
index 2168258fb2c3a2cf5374a3592a302062d75bb305..74b88efde6ad408123de6a9b96ec37460195fe82 100644 (file)
@@ -751,7 +751,7 @@ static void __virtscsi_set_affinity(struct virtio_scsi *vscsi, bool affinity)
 
                vscsi->affinity_hint_set = true;
        } else {
-               for (i = 0; i < vscsi->num_queues - VIRTIO_SCSI_VQ_BASE; i++)
+               for (i = 0; i < vscsi->num_queues; i++)
                        virtqueue_set_affinity(vscsi->req_vqs[i].vq, -1);
 
                vscsi->affinity_hint_set = false;
index 36171fd2826bff5a113b43262c7c749ac87492e8..2cd9b0e44a41cede503dbb9e588020e7a949406b 100644 (file)
@@ -138,7 +138,7 @@ config SSB_DRIVER_MIPS
 
 config SSB_SFLASH
        bool "SSB serial flash support"
-       depends on SSB_DRIVER_MIPS && BROKEN
+       depends on SSB_DRIVER_MIPS
        default y
 
 # Assumption: We are on embedded, if we compile the MIPS core.
index e84cf04f441690e0d518e05a4b59976a80860662..50328de712fa6bb199fad05303bc28b05d46c6ed 100644 (file)
@@ -151,8 +151,8 @@ int ssb_sflash_init(struct ssb_chipcommon *cc)
        sflash->size = sflash->blocksize * sflash->numblocks;
        sflash->present = true;
 
-       pr_info("Found %s serial flash (blocksize: 0x%X, blocks: %d)\n",
-               e->name, e->blocksize, e->numblocks);
+       pr_info("Found %s serial flash (size: %dKiB, blocksize: 0x%X, blocks: %d)\n",
+               e->name, sflash->size / 1024, e->blocksize, e->numblocks);
 
        /* Prepare platform device, but don't register it yet. It's too early,
         * malloc (required by device_private_init) is not available yet. */
@@ -160,7 +160,5 @@ int ssb_sflash_init(struct ssb_chipcommon *cc)
                                         sflash->size;
        ssb_sflash_dev.dev.platform_data = sflash;
 
-       pr_err("Serial flash support is not implemented yet!\n");
-
-       return -ENOTSUPP;
+       return 0;
 }
index 2faa391006db68165def2bc6badb0be69743d380..28c8b0bcf5b2a2da86f3987389831670ccf574b6 100644 (file)
@@ -240,10 +240,6 @@ static int unregister_from_lirc(struct igorplug *ir)
        dprintk(DRIVER_NAME "[%d]: calling lirc_unregister_driver\n", devnum);
        lirc_unregister_driver(d->minor);
 
-       kfree(d);
-       ir->d = NULL;
-       kfree(ir);
-
        return devnum;
 }
 
@@ -377,20 +373,16 @@ static int igorplugusb_remote_poll(void *data, struct lirc_buffer *buf)
        return -ENODATA;
 }
 
-
-
 static int igorplugusb_remote_probe(struct usb_interface *intf,
                                    const struct usb_device_id *id)
 {
-       struct usb_device *dev = NULL;
+       struct usb_device *dev;
        struct usb_host_interface *idesc = NULL;
        struct usb_endpoint_descriptor *ep;
        struct igorplug *ir = NULL;
        struct lirc_driver *driver = NULL;
        int devnum, pipe, maxp;
-       int minor = 0;
        char buf[63], name[128] = "";
-       int mem_failure = 0;
        int ret;
 
        dprintk(DRIVER_NAME ": usb probe called.\n");
@@ -416,24 +408,18 @@ static int igorplugusb_remote_probe(struct usb_interface *intf,
        dprintk(DRIVER_NAME "[%d]: bytes_in_key=%zu maxp=%d\n",
                devnum, CODE_LENGTH, maxp);
 
-       mem_failure = 0;
-       ir = kzalloc(sizeof(struct igorplug), GFP_KERNEL);
-       if (!ir) {
-               mem_failure = 1;
-               goto mem_failure_switch;
-       }
-       driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
-       if (!driver) {
-               mem_failure = 2;
-               goto mem_failure_switch;
-       }
+       ir = devm_kzalloc(&intf->dev, sizeof(*ir), GFP_KERNEL);
+       if (!ir)
+               return -ENOMEM;
+
+       driver = devm_kzalloc(&intf->dev, sizeof(*driver), GFP_KERNEL);
+       if (!driver)
+               return -ENOMEM;
 
        ir->buf_in = usb_alloc_coherent(dev, DEVICE_BUFLEN + DEVICE_HEADERLEN,
                                        GFP_ATOMIC, &ir->dma_in);
-       if (!ir->buf_in) {
-               mem_failure = 3;
-               goto mem_failure_switch;
-       }
+       if (!ir->buf_in)
+               return -ENOMEM;
 
        strcpy(driver->name, DRIVER_NAME " ");
        driver->minor = -1;
@@ -449,27 +435,14 @@ static int igorplugusb_remote_probe(struct usb_interface *intf,
        driver->dev = &intf->dev;
        driver->owner = THIS_MODULE;
 
-       minor = lirc_register_driver(driver);
-       if (minor < 0)
-               mem_failure = 9;
-
-mem_failure_switch:
-
-       switch (mem_failure) {
-       case 9:
+       ret = lirc_register_driver(driver);
+       if (ret < 0) {
                usb_free_coherent(dev, DEVICE_BUFLEN + DEVICE_HEADERLEN,
                        ir->buf_in, ir->dma_in);
-       case 3:
-               kfree(driver);
-       case 2:
-               kfree(ir);
-       case 1:
-               printk(DRIVER_NAME "[%d]: out of memory (code=%d)\n",
-                       devnum, mem_failure);
-               return -ENOMEM;
+               return ret;
        }
 
-       driver->minor = minor;
+       driver->minor = ret;
        ir->d = driver;
        ir->devnum = devnum;
        ir->usbdev = dev;
@@ -502,7 +475,6 @@ mem_failure_switch:
        return 0;
 }
 
-
 static void igorplugusb_remote_disconnect(struct usb_interface *intf)
 {
        struct usb_device *usbdev = interface_to_usbdev(intf);
index dcceed29d31ae415818d1fceecc6518cbc017845..81972fa47bebab17ad635a4d855d5cd691f5daad 100644 (file)
@@ -1811,10 +1811,12 @@ static int zcache_comp_init(void)
 #else
        if (*zcache_comp_name != '\0') {
                ret = crypto_has_comp(zcache_comp_name, 0, 0);
-               if (!ret)
+               if (!ret) {
                        pr_info("zcache: %s not supported\n",
                                        zcache_comp_name);
-               goto out;
+                       ret = 1;
+                       goto out;
+               }
        }
        if (!ret)
                strcpy(zcache_comp_name, "lzo");
index cbf1d155b7b2a8c80ef782443edbf77c0e7f5595..22f280aa4f2c521b5829a6ea5e72b8c05f2265d9 100644 (file)
@@ -773,6 +773,6 @@ module_init(arc_serial_init);
 module_exit(arc_serial_exit);
 
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("plat-arcfpga/uart");
+MODULE_ALIAS("platform:" DRIVER_NAME);
 MODULE_AUTHOR("Vineet Gupta");
 MODULE_DESCRIPTION("ARC(Synopsys) On-Chip(fpga) serial driver");
index 4f5f161896a139852e46f93f30239be979838bda..f85b8e6d0346fc472fbc835b0451a706ce46aab3 100644 (file)
@@ -678,11 +678,18 @@ static void mxs_auart_settermios(struct uart_port *u,
 
 static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
 {
-       u32 istatus, istat;
+       u32 istat;
        struct mxs_auart_port *s = context;
        u32 stat = readl(s->port.membase + AUART_STAT);
 
-       istatus = istat = readl(s->port.membase + AUART_INTR);
+       istat = readl(s->port.membase + AUART_INTR);
+
+       /* ack irq */
+       writel(istat & (AUART_INTR_RTIS
+               | AUART_INTR_TXIS
+               | AUART_INTR_RXIS
+               | AUART_INTR_CTSMIS),
+                       s->port.membase + AUART_INTR_CLR);
 
        if (istat & AUART_INTR_CTSMIS) {
                uart_handle_cts_change(&s->port, stat & AUART_STAT_CTS);
@@ -702,12 +709,6 @@ static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
                istat &= ~AUART_INTR_TXIS;
        }
 
-       writel(istatus & (AUART_INTR_RTIS
-               | AUART_INTR_TXIS
-               | AUART_INTR_RXIS
-               | AUART_INTR_CTSMIS),
-                       s->port.membase + AUART_INTR_CLR);
-
        return IRQ_HANDLED;
 }
 
@@ -850,7 +851,7 @@ auart_console_write(struct console *co, const char *str, unsigned int count)
        struct mxs_auart_port *s;
        struct uart_port *port;
        unsigned int old_ctrl0, old_ctrl2;
-       unsigned int to = 1000;
+       unsigned int to = 20000;
 
        if (co->index >= MXS_AUART_PORTS || co->index < 0)
                return;
@@ -871,18 +872,23 @@ auart_console_write(struct console *co, const char *str, unsigned int count)
 
        uart_console_write(port, str, count, mxs_auart_console_putchar);
 
-       /*
-        * Finally, wait for transmitter to become empty
-        * and restore the TCR
-        */
+       /* Finally, wait for transmitter to become empty ... */
        while (readl(port->membase + AUART_STAT) & AUART_STAT_BUSY) {
+               udelay(1);
                if (!to--)
                        break;
-               udelay(1);
        }
 
-       writel(old_ctrl0, port->membase + AUART_CTRL0);
-       writel(old_ctrl2, port->membase + AUART_CTRL2);
+       /*
+        * ... and restore the TCR if we waited long enough for the transmitter
+        * to be idle. This might keep the transmitter enabled although it is
+        * unused, but that is better than to disable it while it is still
+        * transmitting.
+        */
+       if (!(readl(port->membase + AUART_STAT) & AUART_STAT_BUSY)) {
+               writel(old_ctrl0, port->membase + AUART_CTRL0);
+               writel(old_ctrl2, port->membase + AUART_CTRL2);
+       }
 
        clk_disable(s->clk);
 }
index 7477e0ea5cdb886607e023ae06ce8cc92bb2edde..5ef9300b04669d22a04263950dd51e25262b2d6a 100644 (file)
@@ -52,6 +52,7 @@
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
 #include <linux/gpio.h>
+#include <linux/of.h>
 
 #ifdef CONFIG_SUPERH
 #include <asm/sh_bios.h>
@@ -2437,6 +2438,112 @@ static int sci_remove(struct platform_device *dev)
        return 0;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id of_sci_match[] = {
+       { .compatible = "renesas,sci-SCI-uart",
+               .data = (void *)PORT_SCI },
+       { .compatible = "renesas,sci-SCIF-uart",
+               .data = (void *)PORT_SCIF },
+       { .compatible = "renesas,sci-IRDA-uart",
+               .data = (void *)PORT_IRDA },
+       { .compatible = "renesas,sci-SCIFA-uart",
+               .data = (void *)PORT_SCIFA },
+       { .compatible = "renesas,sci-SCIFB-uart",
+               .data = (void *)PORT_SCIFB },
+       {},
+};
+MODULE_DEVICE_TABLE(of, of_sci_match);
+
+static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev,
+                                                               int *dev_id)
+{
+       struct plat_sci_port *p;
+       struct device_node *np = pdev->dev.of_node;
+       const struct of_device_id *match;
+       struct resource *res;
+       const __be32 *prop;
+       int i, irq, val;
+
+       match = of_match_node(of_sci_match, pdev->dev.of_node);
+       if (!match || !match->data) {
+               dev_err(&pdev->dev, "OF match error\n");
+               return NULL;
+       }
+
+       p = devm_kzalloc(&pdev->dev, sizeof(struct plat_sci_port), GFP_KERNEL);
+       if (!p) {
+               dev_err(&pdev->dev, "failed to allocate DT config data\n");
+               return NULL;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "failed to get I/O memory\n");
+               return NULL;
+       }
+       p->mapbase = res->start;
+
+       for (i = 0; i < SCIx_NR_IRQS; i++) {
+               irq = platform_get_irq(pdev, i);
+               if (irq < 0) {
+                       dev_err(&pdev->dev, "failed to get irq data %d\n", i);
+                       return NULL;
+               }
+               p->irqs[i] = irq;
+       }
+
+       prop = of_get_property(np, "cell-index", NULL);
+       if (!prop) {
+               dev_err(&pdev->dev, "required DT prop cell-index missing\n");
+               return NULL;
+       }
+       *dev_id = be32_to_cpup(prop);
+
+       prop = of_get_property(np, "renesas,scscr", NULL);
+       if (!prop) {
+               dev_err(&pdev->dev, "required DT prop scscr missing\n");
+               return NULL;
+       }
+       p->scscr = be32_to_cpup(prop);
+
+       prop = of_get_property(np, "renesas,scbrr-algo-id", NULL);
+       if (!prop) {
+               dev_err(&pdev->dev, "required DT prop scbrr-algo-id missing\n");
+               return NULL;
+       }
+       val = be32_to_cpup(prop);
+       if (val <= SCBRR_ALGO_INVALID || val >= SCBRR_NR_ALGOS) {
+               dev_err(&pdev->dev, "DT prop scbrr-algo-id out of range\n");
+               return NULL;
+       }
+       p->scbrr_algo_id = val;
+
+       p->flags = UPF_IOREMAP;
+       if (of_get_property(np, "renesas,autoconf", NULL))
+               p->flags |= UPF_BOOT_AUTOCONF;
+
+       prop = of_get_property(np, "renesas,regtype", NULL);
+       if (prop) {
+               val = be32_to_cpup(prop);
+               if (val < SCIx_PROBE_REGTYPE || val >= SCIx_NR_REGTYPES) {
+                       dev_err(&pdev->dev, "DT prop regtype out of range\n");
+                       return NULL;
+               }
+               p->regtype = val;
+       }
+
+       p->type = (unsigned int)match->data;
+
+       return p;
+}
+#else
+static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev,
+                                                               int *dev_id)
+{
+       return NULL;
+}
+#endif /* CONFIG_OF */
+
 static int sci_probe_single(struct platform_device *dev,
                                      unsigned int index,
                                      struct plat_sci_port *p,
@@ -2469,9 +2576,9 @@ static int sci_probe_single(struct platform_device *dev,
 
 static int sci_probe(struct platform_device *dev)
 {
-       struct plat_sci_port *p = dev->dev.platform_data;
-       struct sci_port *sp = &sci_ports[dev->id];
-       int ret;
+       struct plat_sci_port *p;
+       struct sci_port *sp;
+       int ret, dev_id = dev->id;
 
        /*
         * If we've come here via earlyprintk initialization, head off to
@@ -2481,9 +2588,20 @@ static int sci_probe(struct platform_device *dev)
        if (is_early_platform_device(dev))
                return sci_probe_earlyprintk(dev);
 
+       if (dev->dev.of_node)
+               p = sci_parse_dt(dev, &dev_id);
+       else
+               p = dev->dev.platform_data;
+
+       if (!p) {
+               dev_err(&dev->dev, "no setup data supplied\n");
+               return -EINVAL;
+       }
+
+       sp = &sci_ports[dev_id];
        platform_set_drvdata(dev, sp);
 
-       ret = sci_probe_single(dev, dev->id, p, sp);
+       ret = sci_probe_single(dev, dev_id, p, sp);
        if (ret)
                return ret;
 
@@ -2535,6 +2653,7 @@ static struct platform_driver sci_driver = {
                .name   = "sh-sci",
                .owner  = THIS_MODULE,
                .pm     = &sci_dev_pm_ops,
+               .of_match_table = of_match_ptr(of_sci_match),
        },
 };
 
index 121aeb9393e1172e75fe5972a7c4b8ab4640557f..f597e88a705d1fa8e65cf36ae98a61f84f20b9a3 100644 (file)
@@ -256,10 +256,9 @@ void tty_port_tty_hangup(struct tty_port *port, bool check_clocal)
 {
        struct tty_struct *tty = tty_port_tty_get(port);
 
-       if (tty && (!check_clocal || !C_CLOCAL(tty))) {
+       if (tty && (!check_clocal || !C_CLOCAL(tty)))
                tty_hangup(tty);
-               tty_kref_put(tty);
-       }
+       tty_kref_put(tty);
 }
 EXPORT_SYMBOL_GPL(tty_port_tty_hangup);
 
index eb2aa2e5a842f48eae096d29e279572982e215b8..d1bd8ef1f9c1d48b7e0566220149deaf0de10da4 100644 (file)
@@ -12,7 +12,7 @@ if USB_CHIPIDEA
 
 config USB_CHIPIDEA_UDC
        bool "ChipIdea device controller"
-       depends on USB_GADGET=y || USB_CHIPIDEA=m
+       depends on USB_GADGET=y || (USB_CHIPIDEA=m && USB_GADGET=m)
        help
          Say Y here to enable device controller functionality of the
          ChipIdea driver.
@@ -20,7 +20,7 @@ config USB_CHIPIDEA_UDC
 config USB_CHIPIDEA_HOST
        bool "ChipIdea host controller"
        depends on USB=y
-       depends on USB_EHCI_HCD=y || USB_CHIPIDEA=m
+       depends on USB_EHCI_HCD=y || (USB_CHIPIDEA=m && USB_EHCI_HCD=m)
        select USB_EHCI_ROOT_HUB_TT
        help
          Say Y here to enable host controller functionality of the
index aefa0261220c048322a62059ddc35f9df047e7bb..1b23e354f9fb371f5851206b58944b0221109600 100644 (file)
@@ -50,7 +50,7 @@
 #define PORTSC_PTC            (0x0FUL << 16)
 /* PTS and PTW for non lpm version only */
 #define PORTSC_PTS(d)                                          \
-       ((((d) & 0x3) << 30) | (((d) & 0x4) ? BIT(25) : 0))
+       (u32)((((d) & 0x3) << 30) | (((d) & 0x4) ? BIT(25) : 0))
 #define PORTSC_PTW            BIT(28)
 #define PORTSC_STS            BIT(29)
 
@@ -59,7 +59,7 @@
 #define DEVLC_PSPD_HS         (0x02UL << 25)
 #define DEVLC_PTW             BIT(27)
 #define DEVLC_STS             BIT(28)
-#define DEVLC_PTS(d)          (((d) & 0x7) << 29)
+#define DEVLC_PTS(d)          (u32)(((d) & 0x7) << 29)
 
 /* Encoding for DEVLC_PTS and PORTSC_PTS */
 #define PTS_UTMI              0
index f48712ffe261470487f7be0476ad7d89d8a808cf..c1c113ef950c86d9c4170cebaa47a91426cf74fa 100644 (file)
@@ -449,14 +449,20 @@ fail:
 
 static int __exit eth_unbind(struct usb_composite_dev *cdev)
 {
-       if (has_rndis())
+       if (has_rndis()) {
+               usb_put_function(f_rndis);
                usb_put_function_instance(fi_rndis);
-       if (use_eem)
+       }
+       if (use_eem) {
+               usb_put_function(f_eem);
                usb_put_function_instance(fi_eem);
-       else if (can_support_ecm(cdev->gadget))
+       } else if (can_support_ecm(cdev->gadget)) {
+               usb_put_function(f_ecm);
                usb_put_function_instance(fi_ecm);
-       else
+       } else {
+               usb_put_function(f_geth);
                usb_put_function_instance(fi_geth);
+       }
        return 0;
 }
 
index 1bf26e9f38cd3c4573331ff77d6a9caa55a0be7e..eb3aa817a662616810a4c9d9c6232c1e8f2a2e2f 100644 (file)
@@ -488,7 +488,6 @@ static int pn_bind(struct usb_configuration *c, struct usb_function *f)
        struct usb_ep *ep;
        int status, i;
 
-#ifndef USBF_PHONET_INCLUDED
        struct f_phonet_opts *phonet_opts;
 
        phonet_opts = container_of(f->fi, struct f_phonet_opts, func_inst);
@@ -507,7 +506,6 @@ static int pn_bind(struct usb_configuration *c, struct usb_function *f)
                        return status;
                phonet_opts->bound = true;
        }
-#endif
 
        /* Reserve interface IDs */
        status = usb_interface_id(c, f);
index 032b96a51ce4e06a517f35070542067a002275e2..2a1ebefd8f9eb31318fc861fbc010214148db18d 100644 (file)
@@ -160,10 +160,8 @@ static __init int rndis_do_config(struct usb_configuration *c)
                return ret;
 
        f_acm_rndis = usb_get_function(fi_acm);
-       if (IS_ERR(f_acm_rndis)) {
-               ret = PTR_ERR(f_acm_rndis);
-               goto err_func_acm;
-       }
+       if (IS_ERR(f_acm_rndis))
+               return PTR_ERR(f_acm_rndis);
 
        ret = usb_add_function(c, f_acm_rndis);
        if (ret)
@@ -178,7 +176,6 @@ err_fsg:
        usb_remove_function(c, f_acm_rndis);
 err_conf:
        usb_put_function(f_acm_rndis);
-err_func_acm:
        return ret;
 }
 
@@ -226,7 +223,7 @@ static __init int cdc_do_config(struct usb_configuration *c)
        /* implicit port_num is zero */
        f_acm_multi = usb_get_function(fi_acm);
        if (IS_ERR(f_acm_multi))
-               goto err_func_acm;
+               return PTR_ERR(f_acm_multi);
 
        ret = usb_add_function(c, f_acm_multi);
        if (ret)
@@ -241,7 +238,6 @@ err_fsg:
        usb_remove_function(c, f_acm_multi);
 err_conf:
        usb_put_function(f_acm_multi);
-err_func_acm:
        return ret;
 }
 
index c28ac9872030ab1487a4dd74ffb5ee54af950d67..13e25f80fc201f347784ace2f35c7003850f381a 100644 (file)
@@ -109,7 +109,7 @@ void usb_gadget_set_state(struct usb_gadget *gadget,
                enum usb_device_state state)
 {
        gadget->state = state;
-       sysfs_notify(&gadget->dev.kobj, NULL, "status");
+       sysfs_notify(&gadget->dev.kobj, NULL, "state");
 }
 EXPORT_SYMBOL_GPL(usb_gadget_set_state);
 
index 6708a3b78ad8b3d06130dabefe2c2e11e78fa106..f44e8b5e00c94b3b22ddf06b632041e0c462b060 100644 (file)
@@ -481,7 +481,7 @@ static u64 omap2430_dmamask = DMA_BIT_MASK(32);
 
 static int omap2430_probe(struct platform_device *pdev)
 {
-       struct resource                 musb_resources[2];
+       struct resource                 musb_resources[3];
        struct musb_hdrc_platform_data  *pdata = pdev->dev.platform_data;
        struct omap_musb_board_data     *data;
        struct platform_device          *musb;
@@ -581,6 +581,11 @@ static int omap2430_probe(struct platform_device *pdev)
        musb_resources[1].end = pdev->resource[1].end;
        musb_resources[1].flags = pdev->resource[1].flags;
 
+       musb_resources[2].name = pdev->resource[2].name;
+       musb_resources[2].start = pdev->resource[2].start;
+       musb_resources[2].end = pdev->resource[2].end;
+       musb_resources[2].flags = pdev->resource[2].flags;
+
        ret = platform_device_add_resources(musb, musb_resources,
                        ARRAY_SIZE(musb_resources));
        if (ret) {
index 2c06a8969a9f793153d6f6f0546be9d5eb1ff8a0..6f8a9ca96ae753f31b637d0f0c08c1d27a550699 100644 (file)
@@ -1156,7 +1156,7 @@ static u64 tusb_dmamask = DMA_BIT_MASK(32);
 
 static int tusb_probe(struct platform_device *pdev)
 {
-       struct resource musb_resources[2];
+       struct resource musb_resources[3];
        struct musb_hdrc_platform_data  *pdata = pdev->dev.platform_data;
        struct platform_device          *musb;
        struct tusb6010_glue            *glue;
@@ -1199,6 +1199,11 @@ static int tusb_probe(struct platform_device *pdev)
        musb_resources[1].end = pdev->resource[1].end;
        musb_resources[1].flags = pdev->resource[1].flags;
 
+       musb_resources[2].name = pdev->resource[2].name;
+       musb_resources[2].start = pdev->resource[2].start;
+       musb_resources[2].end = pdev->resource[2].end;
+       musb_resources[2].flags = pdev->resource[2].flags;
+
        ret = platform_device_add_resources(musb, musb_resources,
                        ARRAY_SIZE(musb_resources));
        if (ret) {
index 8c3a42ea910cd1d6ef7b503bf4a753f7f521e343..7eef9b33fde66c78405509adf6ca8b461f8045c7 100644 (file)
@@ -719,6 +719,13 @@ config USB_SERIAL_FLASHLOADER
          To compile this driver as a module, choose M here: the
          module will be called flashloader.
 
+config USB_SERIAL_SUUNTO
+       tristate "USB Suunto ANT+ driver"
+       help
+         Say Y here if you want to use the Suunto ANT+ USB device.
+
+         To compile this driver as a module, choose M here: the
+         module will be called suunto.
 
 config USB_SERIAL_DEBUG
        tristate "USB Debugging Device"
index f7130114488f8b95a4ee1c8570c61417cfcdb97b..a14a870d993fe3bc1ea60001c9f1dcb6637c620a 100644 (file)
@@ -54,6 +54,7 @@ obj-$(CONFIG_USB_SERIAL_SIEMENS_MPI)          += siemens_mpi.o
 obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS)                += sierra.o
 obj-$(CONFIG_USB_SERIAL_SPCP8X5)               += spcp8x5.o
 obj-$(CONFIG_USB_SERIAL_SSU100)                        += ssu100.o
+obj-$(CONFIG_USB_SERIAL_SUUNTO)                        += suunto.o
 obj-$(CONFIG_USB_SERIAL_SYMBOL)                        += symbolserial.o
 obj-$(CONFIG_USB_SERIAL_WWAN)                  += usb_wwan.o
 obj-$(CONFIG_USB_SERIAL_TI)                    += ti_usb_3410_5052.o
index 7260ec66034715e7a065d0f5fe6441f49a37f6b4..b65e657c641da56a1545be79e22a13a9fdad653c 100644 (file)
@@ -735,9 +735,34 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_NDI_AURORA_SCU_PID),
                .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk },
        { USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) },
-       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_SERIAL_VX7_PID) },
-       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_CT29B_PID) },
-       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_RTS01_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_S03_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_59_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_57A_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_57B_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29A_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29B_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29F_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_62B_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_S01_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_63_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29C_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_81B_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_82B_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_K5D_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_K4Y_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_K5G_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_S05_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_60_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_61_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_62_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_63B_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_64_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_65_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_92_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_92D_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_W5R_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_A5R_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_PW1_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_PHI_FISCO_PID) },
        { USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) },
index 6dd79253205dd7ec54278ddb078f08346cdbb4f8..1b8af461b522c65a111983226ba1e704f012ac8c 100644 (file)
 /*
  * RT Systems programming cables for various ham radios
  */
-#define RTSYSTEMS_VID                  0x2100  /* Vendor ID */
-#define RTSYSTEMS_SERIAL_VX7_PID       0x9e52  /* Serial converter for VX-7 Radios using FT232RL */
-#define RTSYSTEMS_CT29B_PID            0x9e54  /* CT29B Radio Cable */
-#define RTSYSTEMS_RTS01_PID            0x9e57  /* USB-RTS01 Radio Cable */
-
+#define RTSYSTEMS_VID          0x2100  /* Vendor ID */
+#define RTSYSTEMS_USB_S03_PID  0x9001  /* RTS-03 USB to Serial Adapter */
+#define RTSYSTEMS_USB_59_PID   0x9e50  /* USB-59 USB to 8 pin plug */
+#define RTSYSTEMS_USB_57A_PID  0x9e51  /* USB-57A USB to 4pin 3.5mm plug */
+#define RTSYSTEMS_USB_57B_PID  0x9e52  /* USB-57B USB to extended 4pin 3.5mm plug */
+#define RTSYSTEMS_USB_29A_PID  0x9e53  /* USB-29A USB to 3.5mm stereo plug */
+#define RTSYSTEMS_USB_29B_PID  0x9e54  /* USB-29B USB to 6 pin mini din */
+#define RTSYSTEMS_USB_29F_PID  0x9e55  /* USB-29F USB to 6 pin modular plug */
+#define RTSYSTEMS_USB_62B_PID  0x9e56  /* USB-62B USB to 8 pin mini din plug*/
+#define RTSYSTEMS_USB_S01_PID  0x9e57  /* USB-RTS01 USB to 3.5 mm stereo plug*/
+#define RTSYSTEMS_USB_63_PID   0x9e58  /* USB-63 USB to 9 pin female*/
+#define RTSYSTEMS_USB_29C_PID  0x9e59  /* USB-29C USB to 4 pin modular plug*/
+#define RTSYSTEMS_USB_81B_PID  0x9e5A  /* USB-81 USB to 8 pin mini din plug*/
+#define RTSYSTEMS_USB_82B_PID  0x9e5B  /* USB-82 USB to 2.5 mm stereo plug*/
+#define RTSYSTEMS_USB_K5D_PID  0x9e5C  /* USB-K5D USB to 8 pin modular plug*/
+#define RTSYSTEMS_USB_K4Y_PID  0x9e5D  /* USB-K4Y USB to 2.5/3.5 mm plugs*/
+#define RTSYSTEMS_USB_K5G_PID  0x9e5E  /* USB-K5G USB to 8 pin modular plug*/
+#define RTSYSTEMS_USB_S05_PID  0x9e5F  /* USB-RTS05 USB to 2.5 mm stereo plug*/
+#define RTSYSTEMS_USB_60_PID   0x9e60  /* USB-60 USB to 6 pin din*/
+#define RTSYSTEMS_USB_61_PID   0x9e61  /* USB-61 USB to 6 pin mini din*/
+#define RTSYSTEMS_USB_62_PID   0x9e62  /* USB-62 USB to 8 pin mini din*/
+#define RTSYSTEMS_USB_63B_PID  0x9e63  /* USB-63 USB to 9 pin female*/
+#define RTSYSTEMS_USB_64_PID   0x9e64  /* USB-64 USB to 9 pin male*/
+#define RTSYSTEMS_USB_65_PID   0x9e65  /* USB-65 USB to 9 pin female null modem*/
+#define RTSYSTEMS_USB_92_PID   0x9e66  /* USB-92 USB to 12 pin plug*/
+#define RTSYSTEMS_USB_92D_PID  0x9e67  /* USB-92D USB to 12 pin plug data*/
+#define RTSYSTEMS_USB_W5R_PID  0x9e68  /* USB-W5R USB to 8 pin modular plug*/
+#define RTSYSTEMS_USB_A5R_PID  0x9e69  /* USB-A5R USB to 8 pin modular plug*/
+#define RTSYSTEMS_USB_PW1_PID  0x9e6A  /* USB-PW1 USB to 8 pin modular plug*/
 
 /*
  * Physik Instrumente
index 603fb70dde8005ddfcf9743e2f3f8d0acd616bb5..d953d674f22295a0aac144a7f9958c8dbb4df6a6 100644 (file)
 #define LED_ON_MS      500
 #define LED_OFF_MS     500
 
-static int device_type;
+enum mos7840_flag {
+       MOS7840_FLAG_CTRL_BUSY,
+       MOS7840_FLAG_LED_BUSY,
+};
 
 static const struct usb_device_id id_table[] = {
        {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)},
@@ -238,9 +241,12 @@ struct moschip_port {
 
        /* For device(s) with LED indicator */
        bool has_led;
-       bool led_flag;
        struct timer_list led_timer1;   /* Timer for LED on */
        struct timer_list led_timer2;   /* Timer for LED off */
+       struct urb *led_urb;
+       struct usb_ctrlrequest *led_dr;
+
+       unsigned long flags;
 };
 
 /*
@@ -460,10 +466,10 @@ static void mos7840_control_callback(struct urb *urb)
        case -ESHUTDOWN:
                /* this urb is terminated, clean up */
                dev_dbg(dev, "%s - urb shutting down with status: %d\n", __func__, status);
-               return;
+               goto out;
        default:
                dev_dbg(dev, "%s - nonzero urb status received: %d\n", __func__, status);
-               return;
+               goto out;
        }
 
        dev_dbg(dev, "%s urb buffer size is %d\n", __func__, urb->actual_length);
@@ -476,6 +482,8 @@ static void mos7840_control_callback(struct urb *urb)
                mos7840_handle_new_msr(mos7840_port, regval);
        else if (mos7840_port->MsrLsr == 1)
                mos7840_handle_new_lsr(mos7840_port, regval);
+out:
+       clear_bit_unlock(MOS7840_FLAG_CTRL_BUSY, &mos7840_port->flags);
 }
 
 static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg,
@@ -486,6 +494,9 @@ static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg,
        unsigned char *buffer = mcs->ctrl_buf;
        int ret;
 
+       if (test_and_set_bit_lock(MOS7840_FLAG_CTRL_BUSY, &mcs->flags))
+               return -EBUSY;
+
        dr->bRequestType = MCS_RD_RTYPE;
        dr->bRequest = MCS_RDREQ;
        dr->wValue = cpu_to_le16(Wval); /* 0 */
@@ -497,6 +508,9 @@ static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg,
                             mos7840_control_callback, mcs);
        mcs->control_urb->transfer_buffer_length = 2;
        ret = usb_submit_urb(mcs->control_urb, GFP_ATOMIC);
+       if (ret)
+               clear_bit_unlock(MOS7840_FLAG_CTRL_BUSY, &mcs->flags);
+
        return ret;
 }
 
@@ -523,7 +537,7 @@ static void mos7840_set_led_async(struct moschip_port *mcs, __u16 wval,
                                __u16 reg)
 {
        struct usb_device *dev = mcs->port->serial->dev;
-       struct usb_ctrlrequest *dr = mcs->dr;
+       struct usb_ctrlrequest *dr = mcs->led_dr;
 
        dr->bRequestType = MCS_WR_RTYPE;
        dr->bRequest = MCS_WRREQ;
@@ -531,10 +545,10 @@ static void mos7840_set_led_async(struct moschip_port *mcs, __u16 wval,
        dr->wIndex = cpu_to_le16(reg);
        dr->wLength = cpu_to_le16(0);
 
-       usb_fill_control_urb(mcs->control_urb, dev, usb_sndctrlpipe(dev, 0),
+       usb_fill_control_urb(mcs->led_urb, dev, usb_sndctrlpipe(dev, 0),
                (unsigned char *)dr, NULL, 0, mos7840_set_led_callback, NULL);
 
-       usb_submit_urb(mcs->control_urb, GFP_ATOMIC);
+       usb_submit_urb(mcs->led_urb, GFP_ATOMIC);
 }
 
 static void mos7840_set_led_sync(struct usb_serial_port *port, __u16 reg,
@@ -560,7 +574,19 @@ static void mos7840_led_flag_off(unsigned long arg)
 {
        struct moschip_port *mcs = (struct moschip_port *) arg;
 
-       mcs->led_flag = false;
+       clear_bit_unlock(MOS7840_FLAG_LED_BUSY, &mcs->flags);
+}
+
+static void mos7840_led_activity(struct usb_serial_port *port)
+{
+       struct moschip_port *mos7840_port = usb_get_serial_port_data(port);
+
+       if (test_and_set_bit_lock(MOS7840_FLAG_LED_BUSY, &mos7840_port->flags))
+               return;
+
+       mos7840_set_led_async(mos7840_port, 0x0301, MODEM_CONTROL_REGISTER);
+       mod_timer(&mos7840_port->led_timer1,
+                               jiffies + msecs_to_jiffies(LED_ON_MS));
 }
 
 /*****************************************************************************
@@ -758,14 +784,8 @@ static void mos7840_bulk_in_callback(struct urb *urb)
                return;
        }
 
-       /* Turn on LED */
-       if (mos7840_port->has_led && !mos7840_port->led_flag) {
-               mos7840_port->led_flag = true;
-               mos7840_set_led_async(mos7840_port, 0x0301,
-                                       MODEM_CONTROL_REGISTER);
-               mod_timer(&mos7840_port->led_timer1,
-                               jiffies + msecs_to_jiffies(LED_ON_MS));
-       }
+       if (mos7840_port->has_led)
+               mos7840_led_activity(port);
 
        mos7840_port->read_urb_busy = true;
        retval = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
@@ -816,18 +836,6 @@ static void mos7840_bulk_out_data_callback(struct urb *urb)
 /************************************************************************/
 /*       D R I V E R  T T Y  I N T E R F A C E  F U N C T I O N S       */
 /************************************************************************/
-#ifdef MCSSerialProbe
-static int mos7840_serial_probe(struct usb_serial *serial,
-                               const struct usb_device_id *id)
-{
-
-       /*need to implement the mode_reg reading and updating\
-          structures usb_serial_ device_type\
-          (i.e num_ports, num_bulkin,bulkout etc) */
-       /* Also we can update the changes  attach */
-       return 1;
-}
-#endif
 
 /*****************************************************************************
  * mos7840_open
@@ -1454,13 +1462,8 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,
        data1 = urb->transfer_buffer;
        dev_dbg(&port->dev, "bulkout endpoint is %d\n", port->bulk_out_endpointAddress);
 
-       /* Turn on LED */
-       if (mos7840_port->has_led && !mos7840_port->led_flag) {
-               mos7840_port->led_flag = true;
-               mos7840_set_led_sync(port, MODEM_CONTROL_REGISTER, 0x0301);
-               mod_timer(&mos7840_port->led_timer1,
-                               jiffies + msecs_to_jiffies(LED_ON_MS));
-       }
+       if (mos7840_port->has_led)
+               mos7840_led_activity(port);
 
        /* send it down the pipe */
        status = usb_submit_urb(urb, GFP_ATOMIC);
@@ -2187,38 +2190,48 @@ static int mos7810_check(struct usb_serial *serial)
        return 0;
 }
 
-static int mos7840_calc_num_ports(struct usb_serial *serial)
+static int mos7840_probe(struct usb_serial *serial,
+                               const struct usb_device_id *id)
 {
-       __u16 data = 0x00;
+       u16 product = serial->dev->descriptor.idProduct;
        u8 *buf;
-       int mos7840_num_ports;
+       int device_type;
+
+       if (product == MOSCHIP_DEVICE_ID_7810 ||
+               product == MOSCHIP_DEVICE_ID_7820) {
+               device_type = product;
+               goto out;
+       }
 
        buf = kzalloc(VENDOR_READ_LENGTH, GFP_KERNEL);
-       if (buf) {
-               usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+       if (!buf)
+               return -ENOMEM;
+
+       usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
                        MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, buf,
                        VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT);
-               data = *buf;
-               kfree(buf);
-       }
 
-       if (serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7810 ||
-               serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7820) {
-               device_type = serial->dev->descriptor.idProduct;
-       } else {
-               /* For a MCS7840 device GPIO0 must be set to 1 */
-               if ((data & 0x01) == 1)
-                       device_type = MOSCHIP_DEVICE_ID_7840;
-               else if (mos7810_check(serial))
-                       device_type = MOSCHIP_DEVICE_ID_7810;
-               else
-                       device_type = MOSCHIP_DEVICE_ID_7820;
-       }
+       /* For a MCS7840 device GPIO0 must be set to 1 */
+       if (buf[0] & 0x01)
+               device_type = MOSCHIP_DEVICE_ID_7840;
+       else if (mos7810_check(serial))
+               device_type = MOSCHIP_DEVICE_ID_7810;
+       else
+               device_type = MOSCHIP_DEVICE_ID_7820;
+
+       kfree(buf);
+out:
+       usb_set_serial_data(serial, (void *)(unsigned long)device_type);
+
+       return 0;
+}
+
+static int mos7840_calc_num_ports(struct usb_serial *serial)
+{
+       int device_type = (unsigned long)usb_get_serial_data(serial);
+       int mos7840_num_ports;
 
        mos7840_num_ports = (device_type >> 4) & 0x000F;
-       serial->num_bulk_in = mos7840_num_ports;
-       serial->num_bulk_out = mos7840_num_ports;
-       serial->num_ports = mos7840_num_ports;
 
        return mos7840_num_ports;
 }
@@ -2226,6 +2239,7 @@ static int mos7840_calc_num_ports(struct usb_serial *serial)
 static int mos7840_port_probe(struct usb_serial_port *port)
 {
        struct usb_serial *serial = port->serial;
+       int device_type = (unsigned long)usb_get_serial_data(serial);
        struct moschip_port *mos7840_port;
        int status;
        int pnum;
@@ -2401,6 +2415,14 @@ static int mos7840_port_probe(struct usb_serial_port *port)
        if (device_type == MOSCHIP_DEVICE_ID_7810) {
                mos7840_port->has_led = true;
 
+               mos7840_port->led_urb = usb_alloc_urb(0, GFP_KERNEL);
+               mos7840_port->led_dr = kmalloc(sizeof(*mos7840_port->led_dr),
+                                                               GFP_KERNEL);
+               if (!mos7840_port->led_urb || !mos7840_port->led_dr) {
+                       status = -ENOMEM;
+                       goto error;
+               }
+
                init_timer(&mos7840_port->led_timer1);
                mos7840_port->led_timer1.function = mos7840_led_off;
                mos7840_port->led_timer1.expires =
@@ -2413,8 +2435,6 @@ static int mos7840_port_probe(struct usb_serial_port *port)
                        jiffies + msecs_to_jiffies(LED_OFF_MS);
                mos7840_port->led_timer2.data = (unsigned long)mos7840_port;
 
-               mos7840_port->led_flag = false;
-
                /* Turn off LED */
                mos7840_set_led_sync(port, MODEM_CONTROL_REGISTER, 0x0300);
        }
@@ -2436,6 +2456,8 @@ out:
        }
        return 0;
 error:
+       kfree(mos7840_port->led_dr);
+       usb_free_urb(mos7840_port->led_urb);
        kfree(mos7840_port->dr);
        kfree(mos7840_port->ctrl_buf);
        usb_free_urb(mos7840_port->control_urb);
@@ -2456,6 +2478,10 @@ static int mos7840_port_remove(struct usb_serial_port *port)
 
                del_timer_sync(&mos7840_port->led_timer1);
                del_timer_sync(&mos7840_port->led_timer2);
+
+               usb_kill_urb(mos7840_port->led_urb);
+               usb_free_urb(mos7840_port->led_urb);
+               kfree(mos7840_port->led_dr);
        }
        usb_kill_urb(mos7840_port->control_urb);
        usb_free_urb(mos7840_port->control_urb);
@@ -2482,9 +2508,7 @@ static struct usb_serial_driver moschip7840_4port_device = {
        .throttle = mos7840_throttle,
        .unthrottle = mos7840_unthrottle,
        .calc_num_ports = mos7840_calc_num_ports,
-#ifdef MCSSerialProbe
-       .probe = mos7840_serial_probe,
-#endif
+       .probe = mos7840_probe,
        .ioctl = mos7840_ioctl,
        .set_termios = mos7840_set_termios,
        .break_ctl = mos7840_break,
diff --git a/drivers/usb/serial/suunto.c b/drivers/usb/serial/suunto.c
new file mode 100644 (file)
index 0000000..2248e7a
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Suunto ANT+ USB Driver
+ *
+ * Copyright (C) 2013 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+ * Copyright (C) 2013 Linux Foundation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation only.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include <linux/uaccess.h>
+
+static const struct usb_device_id id_table[] = {
+       { USB_DEVICE(0x0fcf, 0x1008) },
+       { },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static struct usb_serial_driver suunto_device = {
+       .driver = {
+               .owner =        THIS_MODULE,
+               .name =         KBUILD_MODNAME,
+       },
+       .id_table =             id_table,
+       .num_ports =            1,
+};
+
+static struct usb_serial_driver * const serial_drivers[] = {
+       &suunto_device,
+       NULL,
+};
+
+module_usb_serial_driver(serial_drivers, id_table);
+MODULE_LICENSE("GPL");
index c5179e269df64ade2de20a384b6732a6922c9bcf..cef6002acbd49aa078568fe2fe9ea4511230e861 100644 (file)
@@ -137,8 +137,27 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev)
         */
        pci_write_config_word(pdev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE);
 
-       if (vdev->reset_works)
-               __pci_reset_function(pdev);
+       /*
+        * Careful, device_lock may already be held.  This is the case if
+        * a driver unbind is blocked.  Try to get the locks ourselves to
+        * prevent a deadlock.
+        */
+       if (vdev->reset_works) {
+               bool reset_done = false;
+
+               if (pci_cfg_access_trylock(pdev)) {
+                       if (device_trylock(&pdev->dev)) {
+                               __pci_reset_function_locked(pdev);
+                               reset_done = true;
+                               device_unlock(&pdev->dev);
+                       }
+                       pci_cfg_access_unlock(pdev);
+               }
+
+               if (!reset_done)
+                       pr_warn("%s: Unable to acquire locks for reset of %s\n",
+                               __func__, dev_name(&pdev->dev));
+       }
 
        pci_restore_state(pdev);
 }
index c488da5db7c7f1b0bda8e3b7559971ebfba0c442..842f4507883e1b1d10c99d343e35e450abf56db0 100644 (file)
@@ -494,27 +494,6 @@ static int vfio_group_nb_add_dev(struct vfio_group *group, struct device *dev)
        return 0;
 }
 
-static int vfio_group_nb_del_dev(struct vfio_group *group, struct device *dev)
-{
-       struct vfio_device *device;
-
-       /*
-        * Expect to fall out here.  If a device was in use, it would
-        * have been bound to a vfio sub-driver, which would have blocked
-        * in .remove at vfio_del_group_dev.  Sanity check that we no
-        * longer track the device, so it's safe to remove.
-        */
-       device = vfio_group_get_device(group, dev);
-       if (likely(!device))
-               return 0;
-
-       WARN("Device %s removed from live group %d!\n", dev_name(dev),
-            iommu_group_id(group->iommu_group));
-
-       vfio_device_put(device);
-       return 0;
-}
-
 static int vfio_group_nb_verify(struct vfio_group *group, struct device *dev)
 {
        /* We don't care what happens when the group isn't in use */
@@ -531,13 +510,11 @@ static int vfio_iommu_group_notifier(struct notifier_block *nb,
        struct device *dev = data;
 
        /*
-        * Need to go through a group_lock lookup to get a reference or
-        * we risk racing a group being removed.  Leave a WARN_ON for
-        * debuging, but if the group no longer exists, a spurious notify
-        * is harmless.
+        * Need to go through a group_lock lookup to get a reference or we
+        * risk racing a group being removed.  Ignore spurious notifies.
         */
        group = vfio_group_try_get(group);
-       if (WARN_ON(!group))
+       if (!group)
                return NOTIFY_OK;
 
        switch (action) {
@@ -545,7 +522,13 @@ static int vfio_iommu_group_notifier(struct notifier_block *nb,
                vfio_group_nb_add_dev(group, dev);
                break;
        case IOMMU_GROUP_NOTIFY_DEL_DEVICE:
-               vfio_group_nb_del_dev(group, dev);
+               /*
+                * Nothing to do here.  If the device is in use, then the
+                * vfio sub-driver should block the remove callback until
+                * it is unused.  If the device is unused or attached to a
+                * stub driver, then it should be released and we don't
+                * care that it will be going away.
+                */
                break;
        case IOMMU_GROUP_NOTIFY_BIND_DRIVER:
                pr_debug("%s: Device %s, group %d binding to driver\n",
index a89c15de9f45c885f3dc7fe76bad22bde184013d..9b0f12c5c2842f783501821d7c6bb4a9527f936f 100644 (file)
@@ -435,8 +435,8 @@ static int correct_chipset(struct atyfb_par *par)
        const char *name;
        int i;
 
-       for (i = ARRAY_SIZE(aty_chips); i > 0; i--)
-               if (par->pci_id == aty_chips[i - 1].pci_id)
+       for (i = (int)ARRAY_SIZE(aty_chips) - 1; i >= 0; i--)
+               if (par->pci_id == aty_chips[i].pci_id)
                        break;
 
        if (i < 0)
index 8c527e5b293cbe5bf91718f5c1f68b0ffbcc4c44..796e5112ceeeb1f139bf947197e96ea2af42ee60 100644 (file)
@@ -587,8 +587,7 @@ static int nuc900fb_probe(struct platform_device *pdev)
        fbinfo->flags                   = FBINFO_FLAG_DEFAULT;
        fbinfo->pseudo_palette          = &fbi->pseudo_pal;
 
-       ret = request_irq(irq, nuc900fb_irqhandler, 0,
-                         pdev->name, fbinfo);
+       ret = request_irq(irq, nuc900fb_irqhandler, 0, pdev->name, fbi);
        if (ret) {
                dev_err(&pdev->dev, "cannot register irq handler %d -err %d\n",
                        irq, ret);
index b2a8912f6435ac504e4b09361c12dbe8b7d01bc6..a9ac3ce2d0e9de56aaab9f836b0037fe62651596 100644 (file)
@@ -713,7 +713,7 @@ static int sgivwfb_mmap(struct fb_info *info,
        r = vm_iomap_memory(vma, sgivwfb_mem_phys, sgivwfb_mem_size);
 
        printk(KERN_DEBUG "sgivwfb: mmap framebuffer P(%lx)->V(%lx)\n",
-              offset, vma->vm_start);
+               sgivwfb_mem_phys + (vma->vm_pgoff << PAGE_SHIFT), vma->vm_start);
 
        return r;
 }
index a8c6c43a4658565c8b21fa38a3baaf1c5bd82e36..1265b25f9f99993efd8d094716acb65563d8570f 100644 (file)
@@ -567,7 +567,7 @@ static int sh7760fb_remove(struct platform_device *dev)
        fb_dealloc_cmap(&info->cmap);
        sh7760fb_free_mem(info);
        if (par->irq >= 0)
-               free_irq(par->irq, par);
+               free_irq(par->irq, &par->vsync);
        iounmap(par->base);
        release_mem_region(par->ioarea->start, resource_size(par->ioarea));
        framebuffer_release(info);
index 830ded45fd4758a9a3d9ba6c6640653ac9b32490..2827333703d96d151b86952470c590a5d2820636 100644 (file)
@@ -1265,7 +1265,6 @@ static void vga16fb_imageblit(struct fb_info *info, const struct fb_image *image
 
 static void vga16fb_destroy(struct fb_info *info)
 {
-       struct platform_device *dev = container_of(info->device, struct platform_device, dev);
        iounmap(info->screen_base);
        fb_dealloc_cmap(&info->cmap);
        /* XXX unshare VGA regions */
index f3d4a69e1e4e9058c4c4cc605705f1d62d923a48..6629b29a820221eedfe774a1cd4c62163bd29bb1 100644 (file)
@@ -341,8 +341,8 @@ static int xilinxfb_assign(struct platform_device *pdev,
 
        if (drvdata->flags & BUS_ACCESS_FLAG) {
                /* Put a banner in the log (for DEBUG) */
-               dev_dbg(dev, "regs: phys=%x, virt=%p\n", drvdata->regs_phys,
-                                       drvdata->regs);
+               dev_dbg(dev, "regs: phys=%pa, virt=%p\n",
+                       &drvdata->regs_phys, drvdata->regs);
        }
        /* Put a banner in the log (for DEBUG) */
        dev_dbg(dev, "fb: phys=%llx, virt=%p, size=%x\n",
index 9e02d60a364b00d271efb0b4d4eda046a25fbf08..23eae5cb69c21e16d2f71ce2c29e1b307ba3c05c 100644 (file)
@@ -145,7 +145,7 @@ config SWIOTLB_XEN
 
 config XEN_TMEM
        tristate
-       depends on !ARM
+       depends on !ARM && !ARM64
        default m if (CLEANCACHE || FRONTSWAP)
        help
          Shim to interface in-kernel Transcendent Memory hooks
index eabd0ee1c2bc2f298d0938515e204b42430e9852..14fe79d8634abfe2307d53e65e151f403c86bcad 100644 (file)
@@ -1,9 +1,8 @@
-ifneq ($(CONFIG_ARM),y)
-obj-y  += manage.o
+ifeq ($(filter y, $(CONFIG_ARM) $(CONFIG_ARM64)),)
 obj-$(CONFIG_HOTPLUG_CPU)              += cpu_hotplug.o
 endif
 obj-$(CONFIG_X86)                      += fallback.o
-obj-y  += grant-table.o features.o events.o balloon.o
+obj-y  += grant-table.o features.o events.o balloon.o manage.o
 obj-y  += xenbus/
 
 nostackp := $(call cc-option, -fno-stack-protector)
index 119d42a2bf57808135462d70606bd650ce525081..90307c0b630c14b10faf01eb1b764e6578cbc72e 100644 (file)
 #include <asm/xen/hypercall.h>
 #include <asm/xen/hypervisor.h>
 
-int xen_acpi_notify_hypervisor_state(u8 sleep_state,
-                                    u32 pm1a_cnt, u32 pm1b_cnt)
+static int xen_acpi_notify_hypervisor_state(u8 sleep_state,
+                                           u32 val_a, u32 val_b,
+                                           bool extended)
 {
+       unsigned int bits = extended ? 8 : 16;
+
        struct xen_platform_op op = {
                .cmd = XENPF_enter_acpi_sleep,
                .interface_version = XENPF_INTERFACE_VERSION,
-               .u = {
-                       .enter_acpi_sleep = {
-                               .pm1a_cnt_val = (u16)pm1a_cnt,
-                               .pm1b_cnt_val = (u16)pm1b_cnt,
-                               .sleep_state = sleep_state,
-                       },
+               .u.enter_acpi_sleep = {
+                       .val_a = (u16)val_a,
+                       .val_b = (u16)val_b,
+                       .sleep_state = sleep_state,
+                       .flags = extended ? XENPF_ACPI_SLEEP_EXTENDED : 0,
                },
        };
 
-       if ((pm1a_cnt & 0xffff0000) || (pm1b_cnt & 0xffff0000)) {
-               WARN(1, "Using more than 16bits of PM1A/B 0x%x/0x%x!"
-                    "Email xen-devel@lists.xensource.com  Thank you.\n", \
-                    pm1a_cnt, pm1b_cnt);
+       if (WARN((val_a & (~0 << bits)) || (val_b & (~0 << bits)),
+                "Using more than %u bits of sleep control values %#x/%#x!"
+                "Email xen-devel@lists.xen.org - Thank you.\n", \
+                bits, val_a, val_b))
                return -1;
-       }
 
        HYPERVISOR_dom0_op(&op);
        return 1;
 }
+
+int xen_acpi_notify_hypervisor_sleep(u8 sleep_state,
+                                    u32 pm1a_cnt, u32 pm1b_cnt)
+{
+       return xen_acpi_notify_hypervisor_state(sleep_state, pm1a_cnt,
+                                               pm1b_cnt, false);
+}
+
+int xen_acpi_notify_hypervisor_extended_sleep(u8 sleep_state,
+                                    u32 val_a, u32 val_b)
+{
+       return xen_acpi_notify_hypervisor_state(sleep_state, val_a,
+                                               val_b, true);
+}
index 8feecf01d55c95c9241080cf36823f197b3b2d5c..b6165e047f48083c5a254dc66a6f4bc3e6e9ddb9 100644 (file)
@@ -379,18 +379,12 @@ static long evtchn_ioctl(struct file *file,
                if (unbind.port >= NR_EVENT_CHANNELS)
                        break;
 
-               spin_lock_irq(&port_user_lock);
-
                rc = -ENOTCONN;
-               if (get_port_user(unbind.port) != u) {
-                       spin_unlock_irq(&port_user_lock);
+               if (get_port_user(unbind.port) != u)
                        break;
-               }
 
                disable_irq(irq_from_evtchn(unbind.port));
 
-               spin_unlock_irq(&port_user_lock);
-
                evtchn_unbind_from_user(u, unbind.port);
 
                rc = 0;
@@ -490,26 +484,15 @@ static int evtchn_release(struct inode *inode, struct file *filp)
        int i;
        struct per_user_data *u = filp->private_data;
 
-       spin_lock_irq(&port_user_lock);
-
-       free_page((unsigned long)u->ring);
-
        for (i = 0; i < NR_EVENT_CHANNELS; i++) {
                if (get_port_user(i) != u)
                        continue;
 
                disable_irq(irq_from_evtchn(i));
-       }
-
-       spin_unlock_irq(&port_user_lock);
-
-       for (i = 0; i < NR_EVENT_CHANNELS; i++) {
-               if (get_port_user(i) != u)
-                       continue;
-
                evtchn_unbind_from_user(get_port_user(i), i);
        }
 
+       free_page((unsigned long)u->ring);
        kfree(u->name);
        kfree(u);
 
index 6ed8a9df4472edc36b91b70ca3a0f463f237108d..34b20bfa4e8c3cf813194a45c4545e01c1d88eb1 100644 (file)
@@ -115,7 +115,6 @@ static int xenbus_frontend_dev_resume(struct device *dev)
                        return -EFAULT;
                }
 
-               INIT_WORK(&xdev->work, xenbus_frontend_delayed_resume);
                queue_work(xenbus_frontend_wq, &xdev->work);
 
                return 0;
@@ -124,6 +123,16 @@ static int xenbus_frontend_dev_resume(struct device *dev)
        return xenbus_dev_resume(dev);
 }
 
+static int xenbus_frontend_dev_probe(struct device *dev)
+{
+       if (xen_store_domain_type == XS_LOCAL) {
+               struct xenbus_device *xdev = to_xenbus_device(dev);
+               INIT_WORK(&xdev->work, xenbus_frontend_delayed_resume);
+       }
+
+       return xenbus_dev_probe(dev);
+}
+
 static const struct dev_pm_ops xenbus_pm_ops = {
        .suspend        = xenbus_dev_suspend,
        .resume         = xenbus_frontend_dev_resume,
@@ -142,7 +151,7 @@ static struct xen_bus_type xenbus_frontend = {
                .name           = "xen",
                .match          = xenbus_match,
                .uevent         = xenbus_uevent_frontend,
-               .probe          = xenbus_dev_probe,
+               .probe          = xenbus_frontend_dev_probe,
                .remove         = xenbus_dev_remove,
                .shutdown       = xenbus_dev_shutdown,
                .dev_attrs      = xenbus_dev_attrs,
@@ -474,7 +483,11 @@ static int __init xenbus_probe_frontend_init(void)
 
        register_xenstore_notifier(&xenstore_notifier);
 
-       xenbus_frontend_wq = create_workqueue("xenbus_frontend");
+       if (xen_store_domain_type == XS_LOCAL) {
+               xenbus_frontend_wq = create_workqueue("xenbus_frontend");
+               if (!xenbus_frontend_wq)
+                       pr_warn("create xenbus frontend workqueue failed, S3 resume is likely to fail\n");
+       }
 
        return 0;
 }
index 25b018efb8abd8bb82189daf711a9fa4372f3c54..94de6d1482e2e076c4b3d10451c39fc245cce6ef 100644 (file)
@@ -146,7 +146,7 @@ static umode_t p9mode2unixmode(struct v9fs_session_info *v9ses,
                char type = 0, ext[32];
                int major = -1, minor = -1;
 
-               strncpy(ext, stat->extension, sizeof(ext));
+               strlcpy(ext, stat->extension, sizeof(ext));
                sscanf(ext, "%c %u %u", &type, &major, &minor);
                switch (type) {
                case 'c':
@@ -1186,7 +1186,7 @@ v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,
                         * this even with .u extension. So check
                         * for non NULL stat->extension
                         */
-                       strncpy(ext, stat->extension, sizeof(ext));
+                       strlcpy(ext, stat->extension, sizeof(ext));
                        /* HARDLINKCOUNT %u */
                        sscanf(ext, "%13s %u", tag_name, &i_nlink);
                        if (!strncmp(tag_name, "HARDLINKCOUNT", 13))
index 89dec7f789a44335c500e8a2d89fc3f13dac6c5e..b3192da97cabec0e3feb69c64d0749ca05d25237 100644 (file)
@@ -45,7 +45,6 @@ static int load_aout_library(struct file*);
  */
 static int aout_core_dump(struct coredump_params *cprm)
 {
-       struct file *file = cprm->file;
        mm_segment_t fs;
        int has_dumped = 0;
        void __user *dump_start;
@@ -85,10 +84,10 @@ static int aout_core_dump(struct coredump_params *cprm)
 
        set_fs(KERNEL_DS);
 /* struct user */
-       if (!dump_write(file, &dump, sizeof(dump)))
+       if (!dump_emit(cprm, &dump, sizeof(dump)))
                goto end_coredump;
 /* Now dump all of the user data.  Include malloced stuff as well */
-       if (!dump_seek(cprm->file, PAGE_SIZE - sizeof(dump)))
+       if (!dump_align(cprm, PAGE_SIZE))
                goto end_coredump;
 /* now we start writing out the user space info */
        set_fs(USER_DS);
@@ -96,14 +95,14 @@ static int aout_core_dump(struct coredump_params *cprm)
        if (dump.u_dsize != 0) {
                dump_start = START_DATA(dump);
                dump_size = dump.u_dsize << PAGE_SHIFT;
-               if (!dump_write(file, dump_start, dump_size))
+               if (!dump_emit(cprm, dump_start, dump_size))
                        goto end_coredump;
        }
 /* Now prepare to dump the stack area */
        if (dump.u_ssize != 0) {
                dump_start = START_STACK(dump);
                dump_size = dump.u_ssize << PAGE_SHIFT;
-               if (!dump_write(file, dump_start, dump_size))
+               if (!dump_emit(cprm, dump_start, dump_size))
                        goto end_coredump;
        }
 end_coredump:
index 100edcc5e3122323eb8f4087305e623c666eceb0..7d863a4de5a51aed378cbb4172015789f491f7f7 100644 (file)
@@ -1225,35 +1225,32 @@ static int notesize(struct memelfnote *en)
        return sz;
 }
 
-#define DUMP_WRITE(addr, nr, foffset)  \
-       do { if (!dump_write(file, (addr), (nr))) return 0; *foffset += (nr); } while(0)
-
-static int alignfile(struct file *file, loff_t *foffset)
+static int alignfile(struct coredump_params *cprm)
 {
        static const char buf[4] = { 0, };
-       DUMP_WRITE(buf, roundup(*foffset, 4) - *foffset, foffset);
-       return 1;
+       return dump_emit(cprm, buf, roundup(cprm->written, 4) - cprm->written);
 }
 
-static int writenote(struct memelfnote *men, struct file *file,
-                       loff_t *foffset)
+static int writenote(struct memelfnote *men, struct coredump_params *cprm)
 {
        struct elf_note en;
        en.n_namesz = strlen(men->name) + 1;
        en.n_descsz = men->datasz;
        en.n_type = men->type;
 
-       DUMP_WRITE(&en, sizeof(en), foffset);
-       DUMP_WRITE(men->name, en.n_namesz, foffset);
-       if (!alignfile(file, foffset))
+       if (!dump_emit(cprm, &en, sizeof(en)))
+               return 0;
+       if (!dump_emit(cprm, men->name, en.n_namesz))
+               return 0;
+       if (!alignfile(cprm))
                return 0;
-       DUMP_WRITE(men->data, men->datasz, foffset);
-       if (!alignfile(file, foffset))
+       if (!dump_emit(cprm, men->data, men->datasz))
+               return 0;
+       if (!alignfile(cprm))
                return 0;
 
        return 1;
 }
-#undef DUMP_WRITE
 
 static void fill_elf_header(struct elfhdr *elf, int segs,
                            u16 machine, u32 flags)
@@ -1702,7 +1699,7 @@ static size_t get_note_info_size(struct elf_note_info *info)
  * process-wide notes are interleaved after the first thread-specific note.
  */
 static int write_note_info(struct elf_note_info *info,
-                          struct file *file, loff_t *foffset)
+                          struct coredump_params *cprm)
 {
        bool first = 1;
        struct elf_thread_core_info *t = info->thread;
@@ -1710,21 +1707,21 @@ static int write_note_info(struct elf_note_info *info,
        do {
                int i;
 
-               if (!writenote(&t->notes[0], file, foffset))
+               if (!writenote(&t->notes[0], cprm))
                        return 0;
 
-               if (first && !writenote(&info->psinfo, file, foffset))
+               if (first && !writenote(&info->psinfo, cprm))
                        return 0;
-               if (first && !writenote(&info->signote, file, foffset))
+               if (first && !writenote(&info->signote, cprm))
                        return 0;
-               if (first && !writenote(&info->auxv, file, foffset))
+               if (first && !writenote(&info->auxv, cprm))
                        return 0;
-               if (first && !writenote(&info->files, file, foffset))
+               if (first && !writenote(&info->files, cprm))
                        return 0;
 
                for (i = 1; i < info->thread_notes; ++i)
                        if (t->notes[i].data &&
-                           !writenote(&t->notes[i], file, foffset))
+                           !writenote(&t->notes[i], cprm))
                                return 0;
 
                first = 0;
@@ -1930,13 +1927,13 @@ static size_t get_note_info_size(struct elf_note_info *info)
 }
 
 static int write_note_info(struct elf_note_info *info,
-                          struct file *file, loff_t *foffset)
+                          struct coredump_params *cprm)
 {
        int i;
        struct list_head *t;
 
        for (i = 0; i < info->numnote; i++)
-               if (!writenote(info->notes + i, file, foffset))
+               if (!writenote(info->notes + i, cprm))
                        return 0;
 
        /* write out the thread status notes section */
@@ -1945,7 +1942,7 @@ static int write_note_info(struct elf_note_info *info,
                                list_entry(t, struct elf_thread_status, list);
 
                for (i = 0; i < tmp->num_notes; i++)
-                       if (!writenote(&tmp->notes[i], file, foffset))
+                       if (!writenote(&tmp->notes[i], cprm))
                                return 0;
        }
 
@@ -2040,10 +2037,9 @@ static int elf_core_dump(struct coredump_params *cprm)
        int has_dumped = 0;
        mm_segment_t fs;
        int segs;
-       size_t size = 0;
        struct vm_area_struct *vma, *gate_vma;
        struct elfhdr *elf = NULL;
-       loff_t offset = 0, dataoff, foffset;
+       loff_t offset = 0, dataoff;
        struct elf_note_info info;
        struct elf_phdr *phdr4note = NULL;
        struct elf_shdr *shdr4extnum = NULL;
@@ -2099,7 +2095,6 @@ static int elf_core_dump(struct coredump_params *cprm)
 
        offset += sizeof(*elf);                         /* Elf header */
        offset += segs * sizeof(struct elf_phdr);       /* Program headers */
-       foffset = offset;
 
        /* Write notes phdr entry */
        {
@@ -2130,13 +2125,10 @@ static int elf_core_dump(struct coredump_params *cprm)
 
        offset = dataoff;
 
-       size += sizeof(*elf);
-       if (size > cprm->limit || !dump_write(cprm->file, elf, sizeof(*elf)))
+       if (!dump_emit(cprm, elf, sizeof(*elf)))
                goto end_coredump;
 
-       size += sizeof(*phdr4note);
-       if (size > cprm->limit
-           || !dump_write(cprm->file, phdr4note, sizeof(*phdr4note)))
+       if (!dump_emit(cprm, phdr4note, sizeof(*phdr4note)))
                goto end_coredump;
 
        /* Write program headers for segments dump */
@@ -2158,24 +2150,22 @@ static int elf_core_dump(struct coredump_params *cprm)
                        phdr.p_flags |= PF_X;
                phdr.p_align = ELF_EXEC_PAGESIZE;
 
-               size += sizeof(phdr);
-               if (size > cprm->limit
-                   || !dump_write(cprm->file, &phdr, sizeof(phdr)))
+               if (!dump_emit(cprm, &phdr, sizeof(phdr)))
                        goto end_coredump;
        }
 
-       if (!elf_core_write_extra_phdrs(cprm->file, offset, &size, cprm->limit))
+       if (!elf_core_write_extra_phdrs(cprm, offset))
                goto end_coredump;
 
        /* write out the notes section */
-       if (!write_note_info(&info, cprm->file, &foffset))
+       if (!write_note_info(&info, cprm))
                goto end_coredump;
 
-       if (elf_coredump_extra_notes_write(cprm->file, &foffset))
+       if (elf_coredump_extra_notes_write(cprm))
                goto end_coredump;
 
        /* Align to page */
-       if (!dump_seek(cprm->file, dataoff - foffset))
+       if (!dump_align(cprm, ELF_EXEC_PAGESIZE))
                goto end_coredump;
 
        for (vma = first_vma(current, gate_vma); vma != NULL;
@@ -2192,28 +2182,22 @@ static int elf_core_dump(struct coredump_params *cprm)
                        page = get_dump_page(addr);
                        if (page) {
                                void *kaddr = kmap(page);
-                               stop = ((size += PAGE_SIZE) > cprm->limit) ||
-                                       !dump_write(cprm->file, kaddr,
-                                                   PAGE_SIZE);
+                               stop = !dump_emit(cprm, kaddr, PAGE_SIZE);
                                kunmap(page);
                                page_cache_release(page);
                        } else
-                               stop = !dump_seek(cprm->file, PAGE_SIZE);
+                               stop = !dump_skip(cprm, PAGE_SIZE);
                        if (stop)
                                goto end_coredump;
                }
        }
 
-       if (!elf_core_write_extra_data(cprm->file, &size, cprm->limit))
+       if (!elf_core_write_extra_data(cprm))
                goto end_coredump;
 
-       if (e_phnum == PN_XNUM) {
-               size += sizeof(*shdr4extnum);
-               if (size > cprm->limit
-                   || !dump_write(cprm->file, shdr4extnum,
-                                  sizeof(*shdr4extnum)))
+       if (e_phnum == PN_XNUM)
+               if (!dump_emit(cprm, shdr4extnum, sizeof(*shdr4extnum)))
                        goto end_coredump;
-       }
 
 end_coredump:
        set_fs(fs);
index c166f325a1839b1ecf83ae0b068f13e8a26495c2..85c23c4969998a619849dc4c39ccf5ec19ce747e 100644 (file)
@@ -1207,7 +1207,7 @@ static int maydump(struct vm_area_struct *vma, unsigned long mm_flags)
        }
 
        /* If we may not read the contents, don't allow us to dump
-        * them either. "dump_write()" can't handle it anyway.
+        * them either. "dump_emit()" can't handle it anyway.
         */
        if (!(vma->vm_flags & VM_READ)) {
                kdcore("%08lx: %08lx: no (!read)", vma->vm_start, vma->vm_flags);
@@ -1267,35 +1267,26 @@ static int notesize(struct memelfnote *en)
 
 /* #define DEBUG */
 
-#define DUMP_WRITE(addr, nr, foffset)  \
-       do { if (!dump_write(file, (addr), (nr))) return 0; *foffset += (nr); } while(0)
-
-static int alignfile(struct file *file, loff_t *foffset)
-{
-       static const char buf[4] = { 0, };
-       DUMP_WRITE(buf, roundup(*foffset, 4) - *foffset, foffset);
-       return 1;
-}
-
-static int writenote(struct memelfnote *men, struct file *file,
-                       loff_t *foffset)
+static int writenote(struct memelfnote *men, struct coredump_params *cprm)
 {
        struct elf_note en;
        en.n_namesz = strlen(men->name) + 1;
        en.n_descsz = men->datasz;
        en.n_type = men->type;
 
-       DUMP_WRITE(&en, sizeof(en), foffset);
-       DUMP_WRITE(men->name, en.n_namesz, foffset);
-       if (!alignfile(file, foffset))
+       if (!dump_emit(cprm, &en, sizeof(en)))
                return 0;
-       DUMP_WRITE(men->data, men->datasz, foffset);
-       if (!alignfile(file, foffset))
+       if (!dump_emit(cprm, men->name, en.n_namesz))
+               return 0;
+       if (!dump_align(cprm, 4))
+               return 0;
+       if (!dump_emit(cprm, men->data, men->datasz))
+               return 0;
+       if (!dump_align(cprm, 4))
                return 0;
 
        return 1;
 }
-#undef DUMP_WRITE
 
 static inline void fill_elf_fdpic_header(struct elfhdr *elf, int segs)
 {
@@ -1501,8 +1492,7 @@ static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum,
  * dump the segments for an MMU process
  */
 #ifdef CONFIG_MMU
-static int elf_fdpic_dump_segments(struct file *file, size_t *size,
-                          unsigned long *limit, unsigned long mm_flags)
+static int elf_fdpic_dump_segments(struct coredump_params *cprm)
 {
        struct vm_area_struct *vma;
        int err = 0;
@@ -1510,7 +1500,7 @@ static int elf_fdpic_dump_segments(struct file *file, size_t *size,
        for (vma = current->mm->mmap; vma; vma = vma->vm_next) {
                unsigned long addr;
 
-               if (!maydump(vma, mm_flags))
+               if (!maydump(vma, cprm->mm_flags))
                        continue;
 
                for (addr = vma->vm_start; addr < vma->vm_end;
@@ -1518,14 +1508,11 @@ static int elf_fdpic_dump_segments(struct file *file, size_t *size,
                        struct page *page = get_dump_page(addr);
                        if (page) {
                                void *kaddr = kmap(page);
-                               *size += PAGE_SIZE;
-                               if (*size > *limit)
-                                       err = -EFBIG;
-                               else if (!dump_write(file, kaddr, PAGE_SIZE))
+                               if (!dump_emit(cprm, kaddr, PAGE_SIZE))
                                        err = -EIO;
                                kunmap(page);
                                page_cache_release(page);
-                       } else if (!dump_seek(file, PAGE_SIZE))
+                       } else if (!dump_skip(cprm, PAGE_SIZE))
                                err = -EFBIG;
                        if (err)
                                goto out;
@@ -1540,19 +1527,15 @@ out:
  * dump the segments for a NOMMU process
  */
 #ifndef CONFIG_MMU
-static int elf_fdpic_dump_segments(struct file *file, size_t *size,
-                          unsigned long *limit, unsigned long mm_flags)
+static int elf_fdpic_dump_segments(struct coredump_params *cprm)
 {
        struct vm_area_struct *vma;
 
        for (vma = current->mm->mmap; vma; vma = vma->vm_next) {
-               if (!maydump(vma, mm_flags))
+               if (!maydump(vma, cprm->mm_flags))
                        continue;
 
-               if ((*size += PAGE_SIZE) > *limit)
-                       return -EFBIG;
-
-               if (!dump_write(file, (void *) vma->vm_start,
+               if (!dump_emit(cprm, (void *) vma->vm_start,
                                vma->vm_end - vma->vm_start))
                        return -EIO;
        }
@@ -1585,7 +1568,6 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
        int has_dumped = 0;
        mm_segment_t fs;
        int segs;
-       size_t size = 0;
        int i;
        struct vm_area_struct *vma;
        struct elfhdr *elf = NULL;
@@ -1755,13 +1737,10 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
 
        offset = dataoff;
 
-       size += sizeof(*elf);
-       if (size > cprm->limit || !dump_write(cprm->file, elf, sizeof(*elf)))
+       if (!dump_emit(cprm, elf, sizeof(*elf)))
                goto end_coredump;
 
-       size += sizeof(*phdr4note);
-       if (size > cprm->limit
-           || !dump_write(cprm->file, phdr4note, sizeof(*phdr4note)))
+       if (!dump_emit(cprm, phdr4note, sizeof(*phdr4note)))
                goto end_coredump;
 
        /* write program headers for segments dump */
@@ -1785,18 +1764,16 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
                        phdr.p_flags |= PF_X;
                phdr.p_align = ELF_EXEC_PAGESIZE;
 
-               size += sizeof(phdr);
-               if (size > cprm->limit
-                   || !dump_write(cprm->file, &phdr, sizeof(phdr)))
+               if (!dump_emit(cprm, &phdr, sizeof(phdr)))
                        goto end_coredump;
        }
 
-       if (!elf_core_write_extra_phdrs(cprm->file, offset, &size, cprm->limit))
+       if (!elf_core_write_extra_phdrs(cprm, offset))
                goto end_coredump;
 
        /* write out the notes section */
        for (i = 0; i < numnote; i++)
-               if (!writenote(notes + i, cprm->file, &foffset))
+               if (!writenote(notes + i, cprm))
                        goto end_coredump;
 
        /* write out the thread status notes section */
@@ -1805,33 +1782,29 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
                                list_entry(t, struct elf_thread_status, list);
 
                for (i = 0; i < tmp->num_notes; i++)
-                       if (!writenote(&tmp->notes[i], cprm->file, &foffset))
+                       if (!writenote(&tmp->notes[i], cprm))
                                goto end_coredump;
        }
 
-       if (!dump_seek(cprm->file, dataoff - foffset))
+       if (!dump_align(cprm, ELF_EXEC_PAGESIZE))
                goto end_coredump;
 
-       if (elf_fdpic_dump_segments(cprm->file, &size, &cprm->limit,
-                                   cprm->mm_flags) < 0)
+       if (elf_fdpic_dump_segments(cprm) < 0)
                goto end_coredump;
 
-       if (!elf_core_write_extra_data(cprm->file, &size, cprm->limit))
+       if (!elf_core_write_extra_data(cprm))
                goto end_coredump;
 
        if (e_phnum == PN_XNUM) {
-               size += sizeof(*shdr4extnum);
-               if (size > cprm->limit
-                   || !dump_write(cprm->file, shdr4extnum,
-                                  sizeof(*shdr4extnum)))
+               if (!dump_emit(cprm, shdr4extnum, sizeof(*shdr4extnum)))
                        goto end_coredump;
        }
 
-       if (cprm->file->f_pos != offset) {
+       if (cprm->written != offset) {
                /* Sanity check */
                printk(KERN_WARNING
-                      "elf_core_dump: file->f_pos (%lld) != offset (%lld)\n",
-                      cprm->file->f_pos, offset);
+                      "elf_core_dump: cprm->written (%lld) != offset (%lld)\n",
+                      (long long)cprm->written, offset);
        }
 
 end_coredump:
index a40ceda47a3218ee53c2167d8844899c5de3e9cf..868b61d56cac77f3a8328d5ba4851ec7947fe827 100644 (file)
@@ -793,6 +793,8 @@ static int ceph_link(struct dentry *old_dentry, struct inode *dir,
        req->r_locked_dir = dir;
        req->r_dentry_drop = CEPH_CAP_FILE_SHARED;
        req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
+       /* release LINK_SHARED on source inode (mds will lock it) */
+       req->r_old_inode_drop = CEPH_CAP_LINK_SHARED;
        err = ceph_mdsc_do_request(mdsc, dir, req);
        if (err) {
                d_drop(dentry);
index f3a2abf28a77df362faf5c38dc471a64dcbfdffc..2f5edff2f9805b9d1630edf56384fa45cb70f49b 100644 (file)
@@ -1465,7 +1465,14 @@ static void ceph_vmtruncate_work(struct work_struct *work)
        struct inode *inode = &ci->vfs_inode;
 
        dout("vmtruncate_work %p\n", inode);
-       mutex_lock(&inode->i_mutex);
+       if (!mutex_trylock(&inode->i_mutex)) {
+               /*
+                * the i_mutex can be hold by a writer who is waiting for
+                * caps. wake up waiters, they will do pending vmtruncate.
+                */
+               wake_up_all(&ci->i_cap_wq);
+               mutex_lock(&inode->i_mutex);
+       }
        __ceph_do_pending_vmtruncate(inode);
        mutex_unlock(&inode->i_mutex);
        iput(inode);
index e0b4ef31d3c870c9e73fecad303e9f9957542385..a5ce62eb7806daf0722d1950f26015a11e67275c 100644 (file)
@@ -196,8 +196,10 @@ static long ceph_ioctl_get_dataloc(struct file *file, void __user *arg)
        r = ceph_calc_file_object_mapping(&ci->i_layout, dl.file_offset, len,
                                          &dl.object_no, &dl.object_offset,
                                          &olen);
-       if (r < 0)
+       if (r < 0) {
+               up_read(&osdc->map_sem);
                return -EIO;
+       }
        dl.file_offset -= dl.object_offset;
        dl.object_size = ceph_file_layout_object_size(ci->i_layout);
        dl.block_size = ceph_file_layout_su(ci->i_layout);
index 45e57cc38200448da67b1ce2c896efff555f0e73..fc6f4f3a1a9d6c4c2f8b0c7afa1eb20d8029febf 100644 (file)
@@ -43,17 +43,18 @@ cifs_crypto_shash_md5_allocate(struct TCP_Server_Info *server)
        server->secmech.md5 = crypto_alloc_shash("md5", 0, 0);
        if (IS_ERR(server->secmech.md5)) {
                cifs_dbg(VFS, "could not allocate crypto md5\n");
-               return PTR_ERR(server->secmech.md5);
+               rc = PTR_ERR(server->secmech.md5);
+               server->secmech.md5 = NULL;
+               return rc;
        }
 
        size = sizeof(struct shash_desc) +
                        crypto_shash_descsize(server->secmech.md5);
        server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL);
        if (!server->secmech.sdescmd5) {
-               rc = -ENOMEM;
                crypto_free_shash(server->secmech.md5);
                server->secmech.md5 = NULL;
-               return rc;
+               return -ENOMEM;
        }
        server->secmech.sdescmd5->shash.tfm = server->secmech.md5;
        server->secmech.sdescmd5->shash.flags = 0x0;
@@ -421,7 +422,7 @@ find_domain_name(struct cifs_ses *ses, const struct nls_table *nls_cp)
                if (blobptr + attrsize > blobend)
                        break;
                if (type == NTLMSSP_AV_NB_DOMAIN_NAME) {
-                       if (!attrsize)
+                       if (!attrsize || attrsize >= CIFS_MAX_DOMAINNAME_LEN)
                                break;
                        if (!ses->domainName) {
                                ses->domainName =
@@ -591,6 +592,7 @@ CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash)
 
 static int crypto_hmacmd5_alloc(struct TCP_Server_Info *server)
 {
+       int rc;
        unsigned int size;
 
        /* check if already allocated */
@@ -600,7 +602,9 @@ static int crypto_hmacmd5_alloc(struct TCP_Server_Info *server)
        server->secmech.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0);
        if (IS_ERR(server->secmech.hmacmd5)) {
                cifs_dbg(VFS, "could not allocate crypto hmacmd5\n");
-               return PTR_ERR(server->secmech.hmacmd5);
+               rc = PTR_ERR(server->secmech.hmacmd5);
+               server->secmech.hmacmd5 = NULL;
+               return rc;
        }
 
        size = sizeof(struct shash_desc) +
index 4bdd547dbf6fb3d10a2b2b962b710b722d0b9685..85ea98d139fc5643b0606b67959bb1f320037d80 100644 (file)
@@ -147,18 +147,17 @@ cifs_read_super(struct super_block *sb)
                goto out_no_root;
        }
 
+       if (cifs_sb_master_tcon(cifs_sb)->nocase)
+               sb->s_d_op = &cifs_ci_dentry_ops;
+       else
+               sb->s_d_op = &cifs_dentry_ops;
+
        sb->s_root = d_make_root(inode);
        if (!sb->s_root) {
                rc = -ENOMEM;
                goto out_no_root;
        }
 
-       /* do that *after* d_make_root() - we want NULL ->d_op for root here */
-       if (cifs_sb_master_tcon(cifs_sb)->nocase)
-               sb->s_d_op = &cifs_ci_dentry_ops;
-       else
-               sb->s_d_op = &cifs_dentry_ops;
-
 #ifdef CONFIG_CIFS_NFSD_EXPORT
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
                cifs_dbg(FYI, "export ops supported\n");
index 1fdc370410576e1a3f5a36a133245468160ae4b4..52ca861ed35e4fe3fbf78ec387ff401fb0e8fb94 100644 (file)
@@ -44,6 +44,7 @@
 #define MAX_TREE_SIZE (2 + MAX_SERVER_SIZE + 1 + MAX_SHARE_SIZE + 1)
 #define MAX_SERVER_SIZE 15
 #define MAX_SHARE_SIZE 80
+#define CIFS_MAX_DOMAINNAME_LEN 256 /* max domain name length */
 #define MAX_USERNAME_SIZE 256  /* reasonable maximum for current servers */
 #define MAX_PASSWORD_SIZE 512  /* max for windows seems to be 256 wide chars */
 
@@ -369,6 +370,9 @@ struct smb_version_operations {
        void (*generate_signingkey)(struct TCP_Server_Info *server);
        int (*calc_signature)(struct smb_rqst *rqst,
                                   struct TCP_Server_Info *server);
+       int (*query_mf_symlink)(const unsigned char *path, char *pbuf,
+                       unsigned int *pbytes_read, struct cifs_sb_info *cifs_sb,
+                       unsigned int xid);
 };
 
 struct smb_version_values {
index f7e584d047e202e0185f4936a71ef189e1a2781a..b29a012bed33a24b6ba45b17f95c70303e3e3014 100644 (file)
@@ -497,5 +497,7 @@ void cifs_writev_complete(struct work_struct *work);
 struct cifs_writedata *cifs_writedata_alloc(unsigned int nr_pages,
                                                work_func_t complete);
 void cifs_writedata_release(struct kref *refcount);
-
+int open_query_close_cifs_symlink(const unsigned char *path, char *pbuf,
+                       unsigned int *pbytes_read, struct cifs_sb_info *cifs_sb,
+                       unsigned int xid);
 #endif                 /* _CIFSPROTO_H */
index fa68813396b5acb7e7a2e5a65e1202d740688cbb..d67c550c49806254da76ca6f7dd32d29144c3c16 100644 (file)
@@ -1675,7 +1675,8 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                        if (string == NULL)
                                goto out_nomem;
 
-                       if (strnlen(string, 256) == 256) {
+                       if (strnlen(string, CIFS_MAX_DOMAINNAME_LEN)
+                                       == CIFS_MAX_DOMAINNAME_LEN) {
                                printk(KERN_WARNING "CIFS: domain name too"
                                                    " long\n");
                                goto cifs_parse_mount_err;
@@ -2276,8 +2277,8 @@ cifs_put_smb_ses(struct cifs_ses *ses)
 
 #ifdef CONFIG_KEYS
 
-/* strlen("cifs:a:") + INET6_ADDRSTRLEN + 1 */
-#define CIFSCREDS_DESC_SIZE (7 + INET6_ADDRSTRLEN + 1)
+/* strlen("cifs:a:") + CIFS_MAX_DOMAINNAME_LEN + 1 */
+#define CIFSCREDS_DESC_SIZE (7 + CIFS_MAX_DOMAINNAME_LEN + 1)
 
 /* Populate username and pw fields from keyring if possible */
 static int
index 1e57f36ea1b2f84ac43c486cf6aa9cff4b2280a0..7e36ae34e9479b2614d61c919d393291593ef28f 100644 (file)
@@ -647,6 +647,7 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
                                     oflags, &oplock, &cfile->fid.netfid, xid);
                if (rc == 0) {
                        cifs_dbg(FYI, "posix reopen succeeded\n");
+                       oparms.reconnect = true;
                        goto reopen_success;
                }
                /*
index b83c3f5646bde6e21e80806541a00987198a5ce1..562044f700e56bf27997bf7ef7490bddf6bc1c91 100644 (file)
@@ -305,67 +305,89 @@ CIFSCouldBeMFSymlink(const struct cifs_fattr *fattr)
 }
 
 int
-CIFSCheckMFSymlink(struct cifs_fattr *fattr,
-                  const unsigned char *path,
-                  struct cifs_sb_info *cifs_sb, unsigned int xid)
+open_query_close_cifs_symlink(const unsigned char *path, char *pbuf,
+                       unsigned int *pbytes_read, struct cifs_sb_info *cifs_sb,
+                       unsigned int xid)
 {
        int rc;
        int oplock = 0;
        __u16 netfid = 0;
        struct tcon_link *tlink;
-       struct cifs_tcon *pTcon;
+       struct cifs_tcon *ptcon;
        struct cifs_io_parms io_parms;
-       u8 *buf;
-       char *pbuf;
-       unsigned int bytes_read = 0;
        int buf_type = CIFS_NO_BUFFER;
-       unsigned int link_len = 0;
        FILE_ALL_INFO file_info;
 
-       if (!CIFSCouldBeMFSymlink(fattr))
-               /* it's not a symlink */
-               return 0;
-
        tlink = cifs_sb_tlink(cifs_sb);
        if (IS_ERR(tlink))
                return PTR_ERR(tlink);
-       pTcon = tlink_tcon(tlink);
+       ptcon = tlink_tcon(tlink);
 
-       rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ,
+       rc = CIFSSMBOpen(xid, ptcon, path, FILE_OPEN, GENERIC_READ,
                         CREATE_NOT_DIR, &netfid, &oplock, &file_info,
                         cifs_sb->local_nls,
                         cifs_sb->mnt_cifs_flags &
                                CIFS_MOUNT_MAP_SPECIAL_CHR);
-       if (rc != 0)
-               goto out;
+       if (rc != 0) {
+               cifs_put_tlink(tlink);
+               return rc;
+       }
 
        if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
-               CIFSSMBClose(xid, pTcon, netfid);
+               CIFSSMBClose(xid, ptcon, netfid);
+               cifs_put_tlink(tlink);
                /* it's not a symlink */
-               goto out;
+               return rc;
        }
 
-       buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
-       if (!buf) {
-               rc = -ENOMEM;
-               goto out;
-       }
-       pbuf = buf;
        io_parms.netfid = netfid;
        io_parms.pid = current->tgid;
-       io_parms.tcon = pTcon;
+       io_parms.tcon = ptcon;
        io_parms.offset = 0;
        io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
 
-       rc = CIFSSMBRead(xid, &io_parms, &bytes_read, &pbuf, &buf_type);
-       CIFSSMBClose(xid, pTcon, netfid);
-       if (rc != 0) {
-               kfree(buf);
+       rc = CIFSSMBRead(xid, &io_parms, pbytes_read, &pbuf, &buf_type);
+       CIFSSMBClose(xid, ptcon, netfid);
+       cifs_put_tlink(tlink);
+       return rc;
+}
+
+
+int
+CIFSCheckMFSymlink(struct cifs_fattr *fattr,
+                  const unsigned char *path,
+                  struct cifs_sb_info *cifs_sb, unsigned int xid)
+{
+       int rc = 0;
+       u8 *buf = NULL;
+       unsigned int link_len = 0;
+       unsigned int bytes_read = 0;
+       struct cifs_tcon *ptcon;
+
+       if (!CIFSCouldBeMFSymlink(fattr))
+               /* it's not a symlink */
+               return 0;
+
+       buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
+       if (!buf) {
+               rc = -ENOMEM;
                goto out;
        }
 
+       ptcon = tlink_tcon(cifs_sb_tlink(cifs_sb));
+       if ((ptcon->ses) && (ptcon->ses->server->ops->query_mf_symlink))
+               rc = ptcon->ses->server->ops->query_mf_symlink(path, buf,
+                                                &bytes_read, cifs_sb, xid);
+       else
+               goto out;
+
+       if (rc != 0)
+               goto out;
+
+       if (bytes_read == 0) /* not a symlink */
+               goto out;
+
        rc = CIFSParseMFSymlink(buf, bytes_read, &link_len, NULL);
-       kfree(buf);
        if (rc == -EINVAL) {
                /* it's not a symlink */
                rc = 0;
@@ -381,7 +403,7 @@ CIFSCheckMFSymlink(struct cifs_fattr *fattr,
        fattr->cf_mode |= S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO;
        fattr->cf_dtype = DT_LNK;
 out:
-       cifs_put_tlink(tlink);
+       kfree(buf);
        return rc;
 }
 
index 79358e341fd2ea63cff42e6d608c58f65b5f9804..08dd37bb23aac8ea04fe979743f8c963990a80f7 100644 (file)
@@ -197,7 +197,7 @@ static void unicode_domain_string(char **pbcc_area, struct cifs_ses *ses,
                bytes_ret = 0;
        } else
                bytes_ret = cifs_strtoUTF16((__le16 *) bcc_ptr, ses->domainName,
-                                           256, nls_cp);
+                                           CIFS_MAX_DOMAINNAME_LEN, nls_cp);
        bcc_ptr += 2 * bytes_ret;
        bcc_ptr += 2;  /* account for null terminator */
 
@@ -255,8 +255,8 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifs_ses *ses,
 
        /* copy domain */
        if (ses->domainName != NULL) {
-               strncpy(bcc_ptr, ses->domainName, 256);
-               bcc_ptr += strnlen(ses->domainName, 256);
+               strncpy(bcc_ptr, ses->domainName, CIFS_MAX_DOMAINNAME_LEN);
+               bcc_ptr += strnlen(ses->domainName, CIFS_MAX_DOMAINNAME_LEN);
        } /* else we will send a null domain name
             so the server will default to its own domain */
        *bcc_ptr = 0;
index 6457690731a220b58fa2be3f55bd6bf430f27b8b..60943978aec35bb06360adb7e060802d5775bee1 100644 (file)
@@ -944,6 +944,7 @@ struct smb_version_operations smb1_operations = {
        .mand_lock = cifs_mand_lock,
        .mand_unlock_range = cifs_unlock_range,
        .push_mand_locks = cifs_push_mandatory_locks,
+       .query_mf_symlink = open_query_close_cifs_symlink,
 };
 
 struct smb_version_values smb1_values = {
index 301b191270b9bcf09edbea5ad47100267f32e859..4f2300d020c7e517a6fa89be5d955fa4b12753da 100644 (file)
@@ -42,6 +42,7 @@
 static int
 smb2_crypto_shash_allocate(struct TCP_Server_Info *server)
 {
+       int rc;
        unsigned int size;
 
        if (server->secmech.sdeschmacsha256 != NULL)
@@ -50,7 +51,9 @@ smb2_crypto_shash_allocate(struct TCP_Server_Info *server)
        server->secmech.hmacsha256 = crypto_alloc_shash("hmac(sha256)", 0, 0);
        if (IS_ERR(server->secmech.hmacsha256)) {
                cifs_dbg(VFS, "could not allocate crypto hmacsha256\n");
-               return PTR_ERR(server->secmech.hmacsha256);
+               rc = PTR_ERR(server->secmech.hmacsha256);
+               server->secmech.hmacsha256 = NULL;
+               return rc;
        }
 
        size = sizeof(struct shash_desc) +
@@ -87,7 +90,9 @@ smb3_crypto_shash_allocate(struct TCP_Server_Info *server)
                server->secmech.sdeschmacsha256 = NULL;
                crypto_free_shash(server->secmech.hmacsha256);
                server->secmech.hmacsha256 = NULL;
-               return PTR_ERR(server->secmech.cmacaes);
+               rc = PTR_ERR(server->secmech.cmacaes);
+               server->secmech.cmacaes = NULL;
+               return rc;
        }
 
        size = sizeof(struct shash_desc) +
index 72f816d6cad99d4d1f81433e928d42e540295188..fb4e2b7ea07b3555a6b32fb05eebd7ba6fd24a88 100644 (file)
@@ -675,45 +675,59 @@ fail:
        return;
 }
 
-/*
- * Core dumping helper functions.  These are the only things you should
- * do on a core-file: use only these functions to write out all the
- * necessary info.
- */
-int dump_write(struct file *file, const void *addr, int nr)
+bool dump_emit(struct coredump_params *cprm, const void *addr, size_t size)
 {
-       return !dump_interrupted() &&
-               access_ok(VERIFY_READ, addr, nr) &&
-               file->f_op->write(file, addr, nr, &file->f_pos) == nr;
+       struct file *file;
+       loff_t pos;
+       if (size > cprm->limit - cprm->written || dump_interrupted() ||
+           !access_ok(VERIFY_READ, addr, size))
+               return false;
+       file = cprm->file;
+       pos = file->f_pos;
+       if (file->f_op->write(file, addr, size, &pos) != size)
+               return false;
+       file->f_pos = pos;
+       cprm->written += size;
+       return true;
 }
-EXPORT_SYMBOL(dump_write);
+EXPORT_SYMBOL(dump_emit);
 
-int dump_seek(struct file *file, loff_t off)
+bool dump_skip(struct coredump_params *cprm, size_t off)
 {
-       int ret = 1;
+       loff_t new = cprm->written + off;
+       struct file *file = cprm->file;
+
+       if (!off)
+               return true;
+
+       if (new > cprm->limit)
+               return false;
 
        if (file->f_op->llseek && file->f_op->llseek != no_llseek) {
                if (dump_interrupted() ||
-                   file->f_op->llseek(file, off, SEEK_CUR) < 0)
-                       return 0;
+                   file->f_op->llseek(file, new, SEEK_SET) < 0)
+                       return false;
+               cprm->written = new;
        } else {
                char *buf = (char *)get_zeroed_page(GFP_KERNEL);
-
                if (!buf)
-                       return 0;
-               while (off > 0) {
+                       return false;
+               while (off) {
                        unsigned long n = off;
-
                        if (n > PAGE_SIZE)
                                n = PAGE_SIZE;
-                       if (!dump_write(file, buf, n)) {
-                               ret = 0;
-                               break;
-                       }
+                       if (!dump_emit(cprm, buf, n))
+                               return false;
                        off -= n;
                }
                free_page((unsigned long)buf);
        }
-       return ret;
+       return true;
+}
+EXPORT_SYMBOL(dump_skip);
+
+bool dump_align(struct coredump_params *cprm, int align)
+{
+       return dump_skip(cprm, roundup(cprm->written, align) - cprm->written);
 }
-EXPORT_SYMBOL(dump_seek);
+EXPORT_SYMBOL(dump_align);
index 27a6ba9aaeec7e410c1002b72cd81c344c3d76ef..0e90f0c91b931c74d2c0fdd51b9c54de3330e32f 100644 (file)
@@ -267,10 +267,7 @@ void dlm_callback_work(struct work_struct *work)
 int dlm_callback_start(struct dlm_ls *ls)
 {
        ls->ls_callback_wq = alloc_workqueue("dlm_callback",
-                                            WQ_UNBOUND |
-                                            WQ_MEM_RECLAIM |
-                                            WQ_NON_REENTRANT,
-                                            0);
+                                            WQ_UNBOUND | WQ_MEM_RECLAIM, 0);
        if (!ls->ls_callback_wq) {
                log_print("can't start dlm_callback workqueue");
                return -ENOMEM;
index c47f147507227fda66d6b1a59e6922ab60e36ff9..c50c76190373a06bdb1a7971a935e7a5d00d9888 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/seq_file.h>
 #include <linux/log2.h>
 #include <linux/cleancache.h>
+#include <linux/namei.h>
 
 #include <asm/uaccess.h>
 
@@ -819,6 +820,7 @@ enum {
        Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl,
        Opt_reservation, Opt_noreservation, Opt_noload, Opt_nobh, Opt_bh,
        Opt_commit, Opt_journal_update, Opt_journal_inum, Opt_journal_dev,
+       Opt_journal_path,
        Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
        Opt_data_err_abort, Opt_data_err_ignore,
        Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
@@ -860,6 +862,7 @@ static const match_table_t tokens = {
        {Opt_journal_update, "journal=update"},
        {Opt_journal_inum, "journal=%u"},
        {Opt_journal_dev, "journal_dev=%u"},
+       {Opt_journal_path, "journal_path=%s"},
        {Opt_abort, "abort"},
        {Opt_data_journal, "data=journal"},
        {Opt_data_ordered, "data=ordered"},
@@ -975,6 +978,11 @@ static int parse_options (char *options, struct super_block *sb,
        int option;
        kuid_t uid;
        kgid_t gid;
+       char *journal_path;
+       struct inode *journal_inode;
+       struct path path;
+       int error;
+
 #ifdef CONFIG_QUOTA
        int qfmt;
 #endif
@@ -1129,6 +1137,41 @@ static int parse_options (char *options, struct super_block *sb,
                                return 0;
                        *journal_devnum = option;
                        break;
+               case Opt_journal_path:
+                       if (is_remount) {
+                               ext3_msg(sb, KERN_ERR, "error: cannot specify "
+                                      "journal on remount");
+                               return 0;
+                       }
+
+                       journal_path = match_strdup(&args[0]);
+                       if (!journal_path) {
+                               ext3_msg(sb, KERN_ERR, "error: could not dup "
+                                       "journal device string");
+                               return 0;
+                       }
+
+                       error = kern_path(journal_path, LOOKUP_FOLLOW, &path);
+                       if (error) {
+                               ext3_msg(sb, KERN_ERR, "error: could not find "
+                                       "journal device path: error %d", error);
+                               kfree(journal_path);
+                               return 0;
+                       }
+
+                       journal_inode = path.dentry->d_inode;
+                       if (!S_ISBLK(journal_inode->i_mode)) {
+                               ext3_msg(sb, KERN_ERR, "error: journal path %s "
+                                       "is not a block device", journal_path);
+                               path_put(&path);
+                               kfree(journal_path);
+                               return 0;
+                       }
+
+                       *journal_devnum = new_encode_dev(journal_inode->i_rdev);
+                       path_put(&path);
+                       kfree(journal_path);
+                       break;
                case Opt_noload:
                        set_opt (sbi->s_mount_opt, NOLOAD);
                        break;
index 66a6b85a51d8ab1a1724f10858648876b09f8b4b..c5a5c390a5cc6a91dc524de04f10526ff55674c1 100644 (file)
@@ -182,7 +182,7 @@ const struct address_space_operations f2fs_meta_aops = {
        .set_page_dirty = f2fs_set_meta_page_dirty,
 };
 
-int check_orphan_space(struct f2fs_sb_info *sbi)
+int acquire_orphan_inode(struct f2fs_sb_info *sbi)
 {
        unsigned int max_orphans;
        int err = 0;
@@ -197,10 +197,19 @@ int check_orphan_space(struct f2fs_sb_info *sbi)
        mutex_lock(&sbi->orphan_inode_mutex);
        if (sbi->n_orphans >= max_orphans)
                err = -ENOSPC;
+       else
+               sbi->n_orphans++;
        mutex_unlock(&sbi->orphan_inode_mutex);
        return err;
 }
 
+void release_orphan_inode(struct f2fs_sb_info *sbi)
+{
+       mutex_lock(&sbi->orphan_inode_mutex);
+       sbi->n_orphans--;
+       mutex_unlock(&sbi->orphan_inode_mutex);
+}
+
 void add_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
 {
        struct list_head *head, *this;
@@ -229,21 +238,18 @@ retry:
                list_add(&new->list, this->prev);
        else
                list_add_tail(&new->list, head);
-
-       sbi->n_orphans++;
 out:
        mutex_unlock(&sbi->orphan_inode_mutex);
 }
 
 void remove_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
 {
-       struct list_head *this, *next, *head;
+       struct list_head *head;
        struct orphan_inode_entry *orphan;
 
        mutex_lock(&sbi->orphan_inode_mutex);
        head = &sbi->orphan_inode_list;
-       list_for_each_safe(this, next, head) {
-               orphan = list_entry(this, struct orphan_inode_entry, list);
+       list_for_each_entry(orphan, head, list) {
                if (orphan->ino == ino) {
                        list_del(&orphan->list);
                        kmem_cache_free(orphan_entry_slab, orphan);
index 035f9a345cdf23446abbdaa26e8ac28340b715a0..19cd7c6e964c96bee257fdad7ee4424a2b2b5f41 100644 (file)
@@ -39,7 +39,7 @@ static void __set_data_blkaddr(struct dnode_of_data *dn, block_t new_addr)
 
        wait_on_page_writeback(node_page);
 
-       rn = (struct f2fs_node *)page_address(node_page);
+       rn = F2FS_NODE(node_page);
 
        /* Get physical address of data block */
        addr_array = blkaddr_in_node(rn);
@@ -365,7 +365,6 @@ static void read_end_io(struct bio *bio, int err)
                }
                unlock_page(page);
        } while (bvec >= bio->bi_io_vec);
-       kfree(bio->bi_private);
        bio_put(bio);
 }
 
index 0d6c6aafb235b140b3ba44ab7245ba37212b2a27..a84b0a8e6854cd6e2faba8a84124d350378343f1 100644 (file)
@@ -29,7 +29,7 @@ static DEFINE_MUTEX(f2fs_stat_mutex);
 
 static void update_general_status(struct f2fs_sb_info *sbi)
 {
-       struct f2fs_stat_info *si = sbi->stat_info;
+       struct f2fs_stat_info *si = F2FS_STAT(sbi);
        int i;
 
        /* valid check of the segment numbers */
@@ -83,7 +83,7 @@ static void update_general_status(struct f2fs_sb_info *sbi)
  */
 static void update_sit_info(struct f2fs_sb_info *sbi)
 {
-       struct f2fs_stat_info *si = sbi->stat_info;
+       struct f2fs_stat_info *si = F2FS_STAT(sbi);
        unsigned int blks_per_sec, hblks_per_sec, total_vblocks, bimodal, dist;
        struct sit_info *sit_i = SIT_I(sbi);
        unsigned int segno, vblocks;
@@ -118,7 +118,7 @@ static void update_sit_info(struct f2fs_sb_info *sbi)
  */
 static void update_mem_info(struct f2fs_sb_info *sbi)
 {
-       struct f2fs_stat_info *si = sbi->stat_info;
+       struct f2fs_stat_info *si = F2FS_STAT(sbi);
        unsigned npages;
 
        if (si->base_mem)
@@ -253,21 +253,21 @@ static int stat_show(struct seq_file *s, void *v)
                           si->nats, NM_WOUT_THRESHOLD);
                seq_printf(s, "  - SITs: %5d\n  - free_nids: %5d\n",
                           si->sits, si->fnids);
-               seq_printf(s, "\nDistribution of User Blocks:");
-               seq_printf(s, " [ valid | invalid | free ]\n");
-               seq_printf(s, "  [");
+               seq_puts(s, "\nDistribution of User Blocks:");
+               seq_puts(s, " [ valid | invalid | free ]\n");
+               seq_puts(s, "  [");
 
                for (j = 0; j < si->util_valid; j++)
-                       seq_printf(s, "-");
-               seq_printf(s, "|");
+                       seq_putc(s, '-');
+               seq_putc(s, '|');
 
                for (j = 0; j < si->util_invalid; j++)
-                       seq_printf(s, "-");
-               seq_printf(s, "|");
+                       seq_putc(s, '-');
+               seq_putc(s, '|');
 
                for (j = 0; j < si->util_free; j++)
-                       seq_printf(s, "-");
-               seq_printf(s, "]\n\n");
+                       seq_putc(s, '-');
+               seq_puts(s, "]\n\n");
                seq_printf(s, "SSR: %u blocks in %u segments\n",
                           si->block_count[SSR], si->segment_count[SSR]);
                seq_printf(s, "LFS: %u blocks in %u segments\n",
@@ -305,11 +305,10 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi)
        struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
        struct f2fs_stat_info *si;
 
-       sbi->stat_info = kzalloc(sizeof(struct f2fs_stat_info), GFP_KERNEL);
-       if (!sbi->stat_info)
+       si = kzalloc(sizeof(struct f2fs_stat_info), GFP_KERNEL);
+       if (!si)
                return -ENOMEM;
 
-       si = sbi->stat_info;
        si->all_area_segs = le32_to_cpu(raw_super->segment_count);
        si->sit_area_segs = le32_to_cpu(raw_super->segment_count_sit);
        si->nat_area_segs = le32_to_cpu(raw_super->segment_count_nat);
@@ -319,6 +318,7 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi)
        si->main_area_zones = si->main_area_sections /
                                le32_to_cpu(raw_super->secs_per_zone);
        si->sbi = sbi;
+       sbi->stat_info = si;
 
        mutex_lock(&f2fs_stat_mutex);
        list_add_tail(&si->stat_list, &f2fs_stat_list);
@@ -329,13 +329,13 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi)
 
 void f2fs_destroy_stats(struct f2fs_sb_info *sbi)
 {
-       struct f2fs_stat_info *si = sbi->stat_info;
+       struct f2fs_stat_info *si = F2FS_STAT(sbi);
 
        mutex_lock(&f2fs_stat_mutex);
        list_del(&si->stat_list);
        mutex_unlock(&f2fs_stat_mutex);
 
-       kfree(sbi->stat_info);
+       kfree(si);
 }
 
 void __init f2fs_create_root_stats(void)
index 62f0d5977c64f3526e0720653fe33039c85355e3..384c6daf9a89a668b25bf2a22a193ac9f23f6a8a 100644 (file)
@@ -270,12 +270,27 @@ static void init_dent_inode(const struct qstr *name, struct page *ipage)
        struct f2fs_node *rn;
 
        /* copy name info. to this inode page */
-       rn = (struct f2fs_node *)page_address(ipage);
+       rn = F2FS_NODE(ipage);
        rn->i.i_namelen = cpu_to_le32(name->len);
        memcpy(rn->i.i_name, name->name, name->len);
        set_page_dirty(ipage);
 }
 
+int update_dent_inode(struct inode *inode, const struct qstr *name)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       struct page *page;
+
+       page = get_node_page(sbi, inode->i_ino);
+       if (IS_ERR(page))
+               return PTR_ERR(page);
+
+       init_dent_inode(name, page);
+       f2fs_put_page(page, 1);
+
+       return 0;
+}
+
 static int make_empty_dir(struct inode *inode,
                struct inode *parent, struct page *page)
 {
@@ -557,6 +572,8 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
 
                if (inode->i_nlink == 0)
                        add_orphan_inode(sbi, inode->i_ino);
+               else
+                       release_orphan_inode(sbi);
        }
 
        if (bit_pos == NR_DENTRY_IN_BLOCK) {
index 467d42d65c488a0ed3841b01e798841d0e48a395..78777cdb89de3581e98839cc250acc095ce6752b 100644 (file)
@@ -350,6 +350,7 @@ enum page_type {
 
 struct f2fs_sb_info {
        struct super_block *sb;                 /* pointer to VFS super block */
+       struct proc_dir_entry *s_proc;          /* proc entry */
        struct buffer_head *raw_super_buf;      /* buffer head of raw sb */
        struct f2fs_super_block *raw_super;     /* raw super block pointer */
        int s_dirty;                            /* dirty flag for checkpoint */
@@ -454,6 +455,11 @@ static inline struct f2fs_checkpoint *F2FS_CKPT(struct f2fs_sb_info *sbi)
        return (struct f2fs_checkpoint *)(sbi->ckpt);
 }
 
+static inline struct f2fs_node *F2FS_NODE(struct page *page)
+{
+       return (struct f2fs_node *)page_address(page);
+}
+
 static inline struct f2fs_nm_info *NM_I(struct f2fs_sb_info *sbi)
 {
        return (struct f2fs_nm_info *)(sbi->nm_info);
@@ -812,7 +818,7 @@ static inline struct kmem_cache *f2fs_kmem_cache_create(const char *name,
 
 static inline bool IS_INODE(struct page *page)
 {
-       struct f2fs_node *p = (struct f2fs_node *)page_address(page);
+       struct f2fs_node *p = F2FS_NODE(page);
        return RAW_IS_INODE(p);
 }
 
@@ -826,7 +832,7 @@ static inline block_t datablock_addr(struct page *node_page,
 {
        struct f2fs_node *raw_node;
        __le32 *addr_array;
-       raw_node = (struct f2fs_node *)page_address(node_page);
+       raw_node = F2FS_NODE(node_page);
        addr_array = blkaddr_in_node(raw_node);
        return le32_to_cpu(addr_array[offset]);
 }
@@ -947,6 +953,7 @@ struct f2fs_dir_entry *f2fs_parent_dir(struct inode *, struct page **);
 ino_t f2fs_inode_by_name(struct inode *, struct qstr *);
 void f2fs_set_link(struct inode *, struct f2fs_dir_entry *,
                                struct page *, struct inode *);
+int update_dent_inode(struct inode *, const struct qstr *);
 int __f2fs_add_link(struct inode *, const struct qstr *, struct inode *);
 void f2fs_delete_entry(struct f2fs_dir_entry *, struct page *, struct inode *);
 int f2fs_make_empty(struct inode *, struct inode *);
@@ -1037,7 +1044,8 @@ void destroy_segment_manager(struct f2fs_sb_info *);
 struct page *grab_meta_page(struct f2fs_sb_info *, pgoff_t);
 struct page *get_meta_page(struct f2fs_sb_info *, pgoff_t);
 long sync_meta_pages(struct f2fs_sb_info *, enum page_type, long);
-int check_orphan_space(struct f2fs_sb_info *);
+int acquire_orphan_inode(struct f2fs_sb_info *);
+void release_orphan_inode(struct f2fs_sb_info *);
 void add_orphan_inode(struct f2fs_sb_info *, nid_t);
 void remove_orphan_inode(struct f2fs_sb_info *, nid_t);
 int recover_orphan_inodes(struct f2fs_sb_info *);
@@ -1112,11 +1120,16 @@ struct f2fs_stat_info {
        unsigned base_mem, cache_mem;
 };
 
+static inline struct f2fs_stat_info *F2FS_STAT(struct f2fs_sb_info *sbi)
+{
+       return (struct f2fs_stat_info*)sbi->stat_info;
+}
+
 #define stat_inc_call_count(si)        ((si)->call_count++)
 
 #define stat_inc_seg_count(sbi, type)                                  \
        do {                                                            \
-               struct f2fs_stat_info *si = sbi->stat_info;             \
+               struct f2fs_stat_info *si = F2FS_STAT(sbi);             \
                (si)->tot_segs++;                                       \
                if (type == SUM_TYPE_DATA)                              \
                        si->data_segs++;                                \
@@ -1129,14 +1142,14 @@ struct f2fs_stat_info {
 
 #define stat_inc_data_blk_count(sbi, blks)                             \
        do {                                                            \
-               struct f2fs_stat_info *si = sbi->stat_info;             \
+               struct f2fs_stat_info *si = F2FS_STAT(sbi);             \
                stat_inc_tot_blk_count(si, blks);                       \
                si->data_blks += (blks);                                \
        } while (0)
 
 #define stat_inc_node_blk_count(sbi, blks)                             \
        do {                                                            \
-               struct f2fs_stat_info *si = sbi->stat_info;             \
+               struct f2fs_stat_info *si = F2FS_STAT(sbi);             \
                stat_inc_tot_blk_count(si, blks);                       \
                si->node_blks += (blks);                                \
        } while (0)
index d2d2b7dbdcc12b348ca89899f500748716c2104c..c2deb27ffb7205c85fa5065fec17979f3260d204 100644 (file)
@@ -112,11 +112,13 @@ static int get_parent_ino(struct inode *inode, nid_t *pino)
        if (!dentry)
                return 0;
 
-       inode = igrab(dentry->d_parent->d_inode);
-       dput(dentry);
+       if (update_dent_inode(inode, &dentry->d_name)) {
+               dput(dentry);
+               return 0;
+       }
 
-       *pino = inode->i_ino;
-       iput(inode);
+       *pino = parent_ino(dentry);
+       dput(dentry);
        return 1;
 }
 
@@ -147,9 +149,10 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
 
        mutex_lock(&inode->i_mutex);
 
-       if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
-               goto out;
-
+       /*
+        * Both of fdatasync() and fsync() are able to be recovered from
+        * sudden-power-off.
+        */
        if (!S_ISREG(inode->i_mode) || inode->i_nlink != 1)
                need_cp = true;
        else if (file_wrong_pino(inode))
@@ -205,7 +208,7 @@ int truncate_data_blocks_range(struct dnode_of_data *dn, int count)
        struct f2fs_node *raw_node;
        __le32 *addr;
 
-       raw_node = page_address(dn->node_page);
+       raw_node = F2FS_NODE(dn->node_page);
        addr = blkaddr_in_node(raw_node) + ofs;
 
        for ( ; count > 0; count--, addr++, dn->ofs_in_node++) {
index 2b2d45d19e3ea1e1101ff893a2ce9e0f19e607ea..debf74308045c6ca046c065a711f5c50773b2f3a 100644 (file)
@@ -56,7 +56,7 @@ static int do_read_inode(struct inode *inode)
        if (IS_ERR(node_page))
                return PTR_ERR(node_page);
 
-       rn = page_address(node_page);
+       rn = F2FS_NODE(node_page);
        ri = &(rn->i);
 
        inode->i_mode = le16_to_cpu(ri->i_mode);
@@ -153,7 +153,7 @@ void update_inode(struct inode *inode, struct page *node_page)
 
        wait_on_page_writeback(node_page);
 
-       rn = page_address(node_page);
+       rn = F2FS_NODE(node_page);
        ri = &(rn->i);
 
        ri->i_mode = cpu_to_le16(inode->i_mode);
index 64c07169df050b4b358186540031365bd67f4b56..4e475181280c4a8865513f89297a17ca14af07f0 100644 (file)
@@ -239,7 +239,7 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
        if (!de)
                goto fail;
 
-       err = check_orphan_space(sbi);
+       err = acquire_orphan_inode(sbi);
        if (err) {
                kunmap(page);
                f2fs_put_page(page, 0);
@@ -393,7 +393,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
        struct inode *old_inode = old_dentry->d_inode;
        struct inode *new_inode = new_dentry->d_inode;
        struct page *old_dir_page;
-       struct page *old_page;
+       struct page *old_page, *new_page;
        struct f2fs_dir_entry *old_dir_entry = NULL;
        struct f2fs_dir_entry *old_entry;
        struct f2fs_dir_entry *new_entry;
@@ -415,7 +415,6 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
        ilock = mutex_lock_op(sbi);
 
        if (new_inode) {
-               struct page *new_page;
 
                err = -ENOTEMPTY;
                if (old_dir_entry && !f2fs_empty_dir(new_inode))
@@ -427,14 +426,27 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
                if (!new_entry)
                        goto out_dir;
 
+               err = acquire_orphan_inode(sbi);
+               if (err)
+                       goto put_out_dir;
+
+               if (update_dent_inode(old_inode, &new_dentry->d_name)) {
+                       release_orphan_inode(sbi);
+                       goto put_out_dir;
+               }
+
                f2fs_set_link(new_dir, new_entry, new_page, old_inode);
 
                new_inode->i_ctime = CURRENT_TIME;
                if (old_dir_entry)
                        drop_nlink(new_inode);
                drop_nlink(new_inode);
+
                if (!new_inode->i_nlink)
                        add_orphan_inode(sbi, new_inode->i_ino);
+               else
+                       release_orphan_inode(sbi);
+
                update_inode_page(new_inode);
        } else {
                err = f2fs_add_link(new_dentry, old_inode);
@@ -467,6 +479,8 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
        mutex_unlock_op(sbi, ilock);
        return 0;
 
+put_out_dir:
+       f2fs_put_page(new_page, 1);
 out_dir:
        if (old_dir_entry) {
                kunmap(old_dir_page);
index b418aee09573f6d4aff7c4f821ee4faf86d98b0b..f5172e271d46788b1e52566c9ffaec3a2fc184dc 100644 (file)
@@ -565,7 +565,7 @@ static int truncate_nodes(struct dnode_of_data *dn, unsigned int nofs,
                return PTR_ERR(page);
        }
 
-       rn = (struct f2fs_node *)page_address(page);
+       rn = F2FS_NODE(page);
        if (depth < 3) {
                for (i = ofs; i < NIDS_PER_BLOCK; i++, freed++) {
                        child_nid = le32_to_cpu(rn->in.nid[i]);
@@ -698,7 +698,7 @@ restart:
        set_new_dnode(&dn, inode, page, NULL, 0);
        unlock_page(page);
 
-       rn = page_address(page);
+       rn = F2FS_NODE(page);
        switch (level) {
        case 0:
        case 1:
@@ -1484,8 +1484,8 @@ int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page)
        SetPageUptodate(ipage);
        fill_node_footer(ipage, ino, ino, 0, true);
 
-       src = (struct f2fs_node *)page_address(page);
-       dst = (struct f2fs_node *)page_address(ipage);
+       src = F2FS_NODE(page);
+       dst = F2FS_NODE(ipage);
 
        memcpy(dst, src, (unsigned long)&src->i.i_ext - (unsigned long)&src->i);
        dst->i.i_size = 0;
@@ -1535,7 +1535,7 @@ int restore_node_summary(struct f2fs_sb_info *sbi,
                        goto out;
 
                lock_page(page);
-               rn = (struct f2fs_node *)page_address(page);
+               rn = F2FS_NODE(page);
                sum_entry->nid = rn->footer.nid;
                sum_entry->version = 0;
                sum_entry->ofs_in_node = 0;
index c65fb4f4230f699ba7647c820b328942b43b8490..87349c4ea0ef4aa2e7d84cebfb33b9d82810be56 100644 (file)
@@ -155,8 +155,7 @@ static inline void set_to_next_nat(struct f2fs_nm_info *nm_i, nid_t start_nid)
 static inline void fill_node_footer(struct page *page, nid_t nid,
                                nid_t ino, unsigned int ofs, bool reset)
 {
-       void *kaddr = page_address(page);
-       struct f2fs_node *rn = (struct f2fs_node *)kaddr;
+       struct f2fs_node *rn = F2FS_NODE(page);
        if (reset)
                memset(rn, 0, sizeof(*rn));
        rn->footer.nid = cpu_to_le32(nid);
@@ -166,10 +165,8 @@ static inline void fill_node_footer(struct page *page, nid_t nid,
 
 static inline void copy_node_footer(struct page *dst, struct page *src)
 {
-       void *src_addr = page_address(src);
-       void *dst_addr = page_address(dst);
-       struct f2fs_node *src_rn = (struct f2fs_node *)src_addr;
-       struct f2fs_node *dst_rn = (struct f2fs_node *)dst_addr;
+       struct f2fs_node *src_rn = F2FS_NODE(src);
+       struct f2fs_node *dst_rn = F2FS_NODE(dst);
        memcpy(&dst_rn->footer, &src_rn->footer, sizeof(struct node_footer));
 }
 
@@ -177,45 +174,40 @@ static inline void fill_node_footer_blkaddr(struct page *page, block_t blkaddr)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(page->mapping->host->i_sb);
        struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
-       void *kaddr = page_address(page);
-       struct f2fs_node *rn = (struct f2fs_node *)kaddr;
+       struct f2fs_node *rn = F2FS_NODE(page);
+
        rn->footer.cp_ver = ckpt->checkpoint_ver;
        rn->footer.next_blkaddr = cpu_to_le32(blkaddr);
 }
 
 static inline nid_t ino_of_node(struct page *node_page)
 {
-       void *kaddr = page_address(node_page);
-       struct f2fs_node *rn = (struct f2fs_node *)kaddr;
+       struct f2fs_node *rn = F2FS_NODE(node_page);
        return le32_to_cpu(rn->footer.ino);
 }
 
 static inline nid_t nid_of_node(struct page *node_page)
 {
-       void *kaddr = page_address(node_page);
-       struct f2fs_node *rn = (struct f2fs_node *)kaddr;
+       struct f2fs_node *rn = F2FS_NODE(node_page);
        return le32_to_cpu(rn->footer.nid);
 }
 
 static inline unsigned int ofs_of_node(struct page *node_page)
 {
-       void *kaddr = page_address(node_page);
-       struct f2fs_node *rn = (struct f2fs_node *)kaddr;
+       struct f2fs_node *rn = F2FS_NODE(node_page);
        unsigned flag = le32_to_cpu(rn->footer.flag);
        return flag >> OFFSET_BIT_SHIFT;
 }
 
 static inline unsigned long long cpver_of_node(struct page *node_page)
 {
-       void *kaddr = page_address(node_page);
-       struct f2fs_node *rn = (struct f2fs_node *)kaddr;
+       struct f2fs_node *rn = F2FS_NODE(node_page);
        return le64_to_cpu(rn->footer.cp_ver);
 }
 
 static inline block_t next_blkaddr_of_node(struct page *node_page)
 {
-       void *kaddr = page_address(node_page);
-       struct f2fs_node *rn = (struct f2fs_node *)kaddr;
+       struct f2fs_node *rn = F2FS_NODE(node_page);
        return le32_to_cpu(rn->footer.next_blkaddr);
 }
 
@@ -250,7 +242,7 @@ static inline bool IS_DNODE(struct page *node_page)
 
 static inline void set_nid(struct page *p, int off, nid_t nid, bool i)
 {
-       struct f2fs_node *rn = (struct f2fs_node *)page_address(p);
+       struct f2fs_node *rn = F2FS_NODE(p);
 
        wait_on_page_writeback(p);
 
@@ -263,7 +255,8 @@ static inline void set_nid(struct page *p, int off, nid_t nid, bool i)
 
 static inline nid_t get_nid(struct page *p, int off, bool i)
 {
-       struct f2fs_node *rn = (struct f2fs_node *)page_address(p);
+       struct f2fs_node *rn = F2FS_NODE(p);
+
        if (i)
                return le32_to_cpu(rn->i.i_nid[off - NODE_DIR1_BLOCK]);
        return le32_to_cpu(rn->in.nid[off]);
@@ -314,8 +307,7 @@ static inline void clear_cold_data(struct page *page)
 
 static inline int is_node(struct page *page, int type)
 {
-       void *kaddr = page_address(page);
-       struct f2fs_node *rn = (struct f2fs_node *)kaddr;
+       struct f2fs_node *rn = F2FS_NODE(page);
        return le32_to_cpu(rn->footer.flag) & (1 << type);
 }
 
@@ -325,7 +317,7 @@ static inline int is_node(struct page *page, int type)
 
 static inline void set_cold_node(struct inode *inode, struct page *page)
 {
-       struct f2fs_node *rn = (struct f2fs_node *)page_address(page);
+       struct f2fs_node *rn = F2FS_NODE(page);
        unsigned int flag = le32_to_cpu(rn->footer.flag);
 
        if (S_ISDIR(inode->i_mode))
@@ -337,7 +329,7 @@ static inline void set_cold_node(struct inode *inode, struct page *page)
 
 static inline void set_mark(struct page *page, int mark, int type)
 {
-       struct f2fs_node *rn = (struct f2fs_node *)page_address(page);
+       struct f2fs_node *rn = F2FS_NODE(page);
        unsigned int flag = le32_to_cpu(rn->footer.flag);
        if (mark)
                flag |= (0x1 << type);
index d56d951c22537a14a9f103c679e93e64321d863f..639eb34652869101461db01f8f42ffd3bf2e8883 100644 (file)
@@ -40,8 +40,7 @@ static struct fsync_inode_entry *get_fsync_inode(struct list_head *head,
 
 static int recover_dentry(struct page *ipage, struct inode *inode)
 {
-       void *kaddr = page_address(ipage);
-       struct f2fs_node *raw_node = (struct f2fs_node *)kaddr;
+       struct f2fs_node *raw_node = F2FS_NODE(ipage);
        struct f2fs_inode *raw_inode = &(raw_node->i);
        nid_t pino = le32_to_cpu(raw_inode->i_pino);
        struct f2fs_dir_entry *de;
@@ -93,8 +92,7 @@ out:
 
 static int recover_inode(struct inode *inode, struct page *node_page)
 {
-       void *kaddr = page_address(node_page);
-       struct f2fs_node *raw_node = (struct f2fs_node *)kaddr;
+       struct f2fs_node *raw_node = F2FS_NODE(node_page);
        struct f2fs_inode *raw_inode = &(raw_node->i);
 
        if (!IS_INODE(node_page))
index a86d125a9885e274b11a421d4b117480a2744994..9b74ae2137d10a4bcad9a7d5ced77c6ce36ac2be 100644 (file)
@@ -611,18 +611,12 @@ static void f2fs_end_io_write(struct bio *bio, int err)
 struct bio *f2fs_bio_alloc(struct block_device *bdev, int npages)
 {
        struct bio *bio;
-       struct bio_private *priv;
-retry:
-       priv = kmalloc(sizeof(struct bio_private), GFP_NOFS);
-       if (!priv) {
-               cond_resched();
-               goto retry;
-       }
 
        /* No failure on bio allocation */
        bio = bio_alloc(GFP_NOIO, npages);
        bio->bi_bdev = bdev;
-       bio->bi_private = priv;
+       bio->bi_private = NULL;
+
        return bio;
 }
 
@@ -681,8 +675,17 @@ static void submit_write_page(struct f2fs_sb_info *sbi, struct page *page,
                do_submit_bio(sbi, type, false);
 alloc_new:
        if (sbi->bio[type] == NULL) {
+               struct bio_private *priv;
+retry:
+               priv = kmalloc(sizeof(struct bio_private), GFP_NOFS);
+               if (!priv) {
+                       cond_resched();
+                       goto retry;
+               }
+
                sbi->bio[type] = f2fs_bio_alloc(bdev, max_hw_blocks(sbi));
                sbi->bio[type]->bi_sector = SECTOR_FROM_BLOCK(sbi, blk_addr);
+               sbi->bio[type]->bi_private = priv;
                /*
                 * The end_io will be assigned at the sumbission phase.
                 * Until then, let bio_add_page() merge consecutive IOs as much
index 75c7dc363e9267378d5cdf39f811c16a7adc8692..70dbb313a7cad6ff357e803d4ee93c322ba45ee8 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/parser.h>
 #include <linux/mount.h>
 #include <linux/seq_file.h>
+#include <linux/proc_fs.h>
 #include <linux/random.h>
 #include <linux/exportfs.h>
 #include <linux/blkdev.h>
@@ -31,6 +32,7 @@
 #define CREATE_TRACE_POINTS
 #include <trace/events/f2fs.h>
 
+static struct proc_dir_entry *f2fs_proc_root;
 static struct kmem_cache *f2fs_inode_cachep;
 
 enum {
@@ -223,6 +225,11 @@ static void f2fs_put_super(struct super_block *sb)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(sb);
 
+       if (sbi->s_proc) {
+               remove_proc_entry("segment_info", sbi->s_proc);
+               remove_proc_entry(sb->s_id, f2fs_proc_root);
+       }
+
        f2fs_destroy_stats(sbi);
        stop_gc_thread(sbi);
 
@@ -340,6 +347,36 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
        return 0;
 }
 
+static int segment_info_seq_show(struct seq_file *seq, void *offset)
+{
+       struct super_block *sb = seq->private;
+       struct f2fs_sb_info *sbi = F2FS_SB(sb);
+       unsigned int total_segs = le32_to_cpu(sbi->raw_super->segment_count_main);
+       int i;
+
+       for (i = 0; i < total_segs; i++) {
+               seq_printf(seq, "%u", get_valid_blocks(sbi, i, 1));
+               if (i != 0 && (i % 10) == 0)
+                       seq_puts(seq, "\n");
+               else
+                       seq_puts(seq, " ");
+       }
+       return 0;
+}
+
+static int segment_info_open_fs(struct inode *inode, struct file *file)
+{
+       return single_open(file, segment_info_seq_show, PDE_DATA(inode));
+}
+
+static const struct file_operations f2fs_seq_segment_info_fops = {
+       .owner = THIS_MODULE,
+       .open = segment_info_open_fs,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
 static int f2fs_remount(struct super_block *sb, int *flags, char *data)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(sb);
@@ -766,6 +803,13 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
        if (err)
                goto fail;
 
+       if (f2fs_proc_root)
+               sbi->s_proc = proc_mkdir(sb->s_id, f2fs_proc_root);
+
+       if (sbi->s_proc)
+               proc_create_data("segment_info", S_IRUGO, sbi->s_proc,
+                                &f2fs_seq_segment_info_fops, sb);
+
        if (test_opt(sbi, DISCARD)) {
                struct request_queue *q = bdev_get_queue(sb->s_bdev);
                if (!blk_queue_discard(q))
@@ -852,12 +896,14 @@ static int __init init_f2fs_fs(void)
        if (err)
                goto fail;
        f2fs_create_root_stats();
+       f2fs_proc_root = proc_mkdir("fs/f2fs", NULL);
 fail:
        return err;
 }
 
 static void __exit exit_f2fs_fs(void)
 {
+       remove_proc_entry("fs/f2fs", NULL);
        f2fs_destroy_root_stats();
        unregister_filesystem(&f2fs_fs_type);
        destroy_checkpoint_caches();
index bbb2715171cd0c983770cf86b4b57ed69e04c98d..a01b8fd3a1c16c7b3363d5e6fac5ec54e5390119 100644 (file)
@@ -594,7 +594,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
                }
                gfs2_glock_dq_uninit(ghs);
                if (IS_ERR(d))
-                       return PTR_RET(d);
+                       return PTR_ERR(d);
                return error;
        } else if (error != -ENOENT) {
                goto fail_gunlock;
index 17c5b5d7dc88c4b73e00c5918f97473df15b354f..010b9fb9fec6e781cb80a6982d746896ba6cffdb 100644 (file)
@@ -579,6 +579,24 @@ static int buf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start,
        return error;
 }
 
+/**
+ * gfs2_meta_sync - Sync all buffers associated with a glock
+ * @gl: The glock
+ *
+ */
+
+static void gfs2_meta_sync(struct gfs2_glock *gl)
+{
+       struct address_space *mapping = gfs2_glock2aspace(gl);
+       int error;
+
+       filemap_fdatawrite(mapping);
+       error = filemap_fdatawait(mapping);
+
+       if (error)
+               gfs2_io_error(gl->gl_sbd);
+}
+
 static void buf_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass)
 {
        struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
index e04d0e09ee7b59d5959d69e5df872a5871e9ae64..7b0f5043cf24c253612451787588d638da5483ce 100644 (file)
@@ -155,7 +155,7 @@ static int __init init_gfs2_fs(void)
                goto fail_wq;
 
        gfs2_control_wq = alloc_workqueue("gfs2_control",
-                              WQ_NON_REENTRANT | WQ_UNBOUND | WQ_FREEZABLE, 0);
+                                         WQ_UNBOUND | WQ_FREEZABLE, 0);
        if (!gfs2_control_wq)
                goto fail_recovery;
 
index 0da390686c08f458e12aeb44df92d7301a96d788..932415050540e2a1bdefc6d957e68ef7a0d82d01 100644 (file)
@@ -97,24 +97,6 @@ const struct address_space_operations gfs2_meta_aops = {
        .releasepage = gfs2_releasepage,
 };
 
-/**
- * gfs2_meta_sync - Sync all buffers associated with a glock
- * @gl: The glock
- *
- */
-
-void gfs2_meta_sync(struct gfs2_glock *gl)
-{
-       struct address_space *mapping = gfs2_glock2aspace(gl);
-       int error;
-
-       filemap_fdatawrite(mapping);
-       error = filemap_fdatawait(mapping);
-
-       if (error)
-               gfs2_io_error(gl->gl_sbd);
-}
-
 /**
  * gfs2_getbuf - Get a buffer with a given address space
  * @gl: the glock
index 0d4c843b6f8e59aec3f143a80417d0e4e6de43e0..4823b934208a2be6012a71ded8f4e950fca753fb 100644 (file)
@@ -48,21 +48,17 @@ static inline struct gfs2_sbd *gfs2_mapping2sbd(struct address_space *mapping)
                return inode->i_sb->s_fs_info;
 }
 
-void gfs2_meta_sync(struct gfs2_glock *gl);
-
-struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, u64 blkno);
-int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno,
-                  int flags, struct buffer_head **bhp);
-int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh);
-struct buffer_head *gfs2_getbuf(struct gfs2_glock *gl, u64 blkno, int create);
-
-void gfs2_remove_from_journal(struct buffer_head *bh, struct gfs2_trans *tr,
-                             int meta);
-
-void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen);
-
-int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, u64 num,
-                             struct buffer_head **bhp);
+extern struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, u64 blkno);
+extern int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags,
+                         struct buffer_head **bhp);
+extern int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh);
+extern struct buffer_head *gfs2_getbuf(struct gfs2_glock *gl, u64 blkno,
+                                      int create);
+extern void gfs2_remove_from_journal(struct buffer_head *bh,
+                                    struct gfs2_trans *tr, int meta);
+extern void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen);
+extern int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, u64 num,
+                                    struct buffer_head **bhp);
 
 static inline int gfs2_meta_inode_buffer(struct gfs2_inode *ip,
                                         struct buffer_head **bhp)
index c348d6d886240cb0354dbc71faf88fef2395db67..e5d408a7ea4a27c88af2a1dcae32259eab1f7083 100644 (file)
@@ -117,8 +117,8 @@ static void destroy_inodecache(void)
 
 static int isofs_remount(struct super_block *sb, int *flags, char *data)
 {
-       /* we probably want a lot more here */
-       *flags |= MS_RDONLY;
+       if (!(*flags & MS_RDONLY))
+               return -EROFS;
        return 0;
 }
 
@@ -763,15 +763,6 @@ root_found:
         */
        s->s_maxbytes = 0x80000000000LL;
 
-       /*
-        * The CDROM is read-only, has no nodes (devices) on it, and since
-        * all of the files appear to be owned by root, we really do not want
-        * to allow suid.  (suid or devices will not show up unless we have
-        * Rock Ridge extensions)
-        */
-
-       s->s_flags |= MS_RDONLY /* | MS_NODEV | MS_NOSUID */;
-
        /* Set this for reference. Its not currently used except on write
           which we don't have .. */
 
@@ -1530,6 +1521,9 @@ struct inode *isofs_iget(struct super_block *sb,
 static struct dentry *isofs_mount(struct file_system_type *fs_type,
        int flags, const char *dev_name, void *data)
 {
+       /* We don't support read-write mounts */
+       if (!(flags & MS_RDONLY))
+               return ERR_PTR(-EACCES);
        return mount_bdev(fs_type, flags, dev_name, data, isofs_fill_super);
 }
 
index 9c501449450dc9be6891e5d9c1a035ca31b5687b..427bb73e298f197d4cfc73b17baeffdd1c848c5d 100644 (file)
@@ -245,8 +245,8 @@ static int logfs_mtd_can_write_buf(struct super_block *sb, u64 ofs)
                goto out;
        if (memchr_inv(buf, 0xff, super->s_writesize))
                err = -EIO;
-       kfree(buf);
 out:
+       kfree(buf);
        return err;
 }
 
index 54360293bcb5cd0680c3042e6f0b9b87e342c649..b256c0690e5b66f5b16a2b81be033cc3b345dec6 100644 (file)
@@ -287,14 +287,14 @@ static int logfs_make_writeable(struct super_block *sb)
        if (err)
                return err;
 
+       /* Do one GC pass before any data gets dirtied */
+       logfs_gc_pass(sb);
+
        /* Check areas for trailing unaccounted data */
        err = logfs_check_areas(sb);
        if (err)
                return err;
 
-       /* Do one GC pass before any data gets dirtied */
-       logfs_gc_pass(sb);
-
        /* after all initializations are done, replay the journal
         * for rw-mounts, if necessary */
        err = logfs_replay_journal(sb);
index cf11799297c42d50dc33aca126e6da11f033ce4b..0e64cccda0ac217ab7efc0a329422a0c76e2f701 100644 (file)
@@ -2940,10 +2940,10 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
        
        /* Deal with open(O_TRUNC) */
        if (sattr->ia_valid & ATTR_OPEN)
-               sattr->ia_valid &= ~(ATTR_MTIME|ATTR_CTIME|ATTR_OPEN);
+               sattr->ia_valid &= ~(ATTR_MTIME|ATTR_CTIME);
 
        /* Optimization: if the end result is no change, don't RPC */
-       if ((sattr->ia_valid & ~(ATTR_FILE)) == 0)
+       if ((sattr->ia_valid & ~(ATTR_FILE|ATTR_OPEN)) == 0)
                return 0;
 
        /* Search for an existing open(O_WRITE) file */
@@ -4662,10 +4662,14 @@ static unsigned int
 nfs4_init_uniform_client_string(const struct nfs_client *clp,
                                char *buf, size_t len)
 {
-       char *nodename = clp->cl_rpcclient->cl_nodename;
+       const char *nodename = clp->cl_rpcclient->cl_nodename;
 
        if (nfs4_client_id_uniquifier[0] != '\0')
-               nodename = nfs4_client_id_uniquifier;
+               return 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",
                                clp->rpc_ops->version, clp->cl_minorversion,
                                nodename);
@@ -6876,7 +6880,7 @@ int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp)
                .rpc_cred = lrp->cred,
        };
        struct rpc_task_setup task_setup_data = {
-               .rpc_client = lrp->clp->cl_rpcclient,
+               .rpc_client = NFS_SERVER(lrp->args.inode)->client,
                .rpc_message = &msg,
                .callback_ops = &nfs4_layoutreturn_call_ops,
                .callback_data = lrp,
index e22862f13564486ab535a437f4d46e6709a30ed9..ad1a7533ce6d8964a58cab193689245bc217b274 100644 (file)
@@ -2116,7 +2116,7 @@ static int nfs4_bind_conn_to_session(struct nfs_client *clp)
 }
 #else /* CONFIG_NFS_V4_1 */
 static int nfs4_reset_session(struct nfs_client *clp) { return 0; }
-static int nfs4_end_drain_session(struct nfs_client *clp) { return 0; }
+static void nfs4_end_drain_session(struct nfs_client *clp) { }
 
 static int nfs4_bind_conn_to_session(struct nfs_client *clp)
 {
index 3850b018815f2d07e4740fdd3ff8200523b9fe92..1a4a3bd415ed6c6b29e7cedf7809f9c1970288d4 100644 (file)
@@ -997,12 +997,10 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
        int owner_namelen = 0;
        int owner_grouplen = 0;
        __be32 *p;
-       __be32 *q;
-       int len;
-       uint32_t bmval_len = 2;
-       uint32_t bmval0 = 0;
-       uint32_t bmval1 = 0;
-       uint32_t bmval2 = 0;
+       unsigned i;
+       uint32_t len = 0;
+       uint32_t bmval_len;
+       uint32_t bmval[3] = { 0 };
 
        /*
         * We reserve enough space to write the entire attribute buffer at once.
@@ -1011,13 +1009,14 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
         * = 40 bytes, plus any contribution from variable-length fields
         *            such as owner/group.
         */
-       len = 8;
-
-       /* Sigh */
-       if (iap->ia_valid & ATTR_SIZE)
+       if (iap->ia_valid & ATTR_SIZE) {
+               bmval[0] |= FATTR4_WORD0_SIZE;
                len += 8;
-       if (iap->ia_valid & ATTR_MODE)
+       }
+       if (iap->ia_valid & ATTR_MODE) {
+               bmval[1] |= FATTR4_WORD1_MODE;
                len += 4;
+       }
        if (iap->ia_valid & ATTR_UID) {
                owner_namelen = nfs_map_uid_to_name(server, iap->ia_uid, owner_name, IDMAP_NAMESZ);
                if (owner_namelen < 0) {
@@ -1028,6 +1027,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
                        owner_namelen = sizeof("nobody") - 1;
                        /* goto out; */
                }
+               bmval[1] |= FATTR4_WORD1_OWNER;
                len += 4 + (XDR_QUADLEN(owner_namelen) << 2);
        }
        if (iap->ia_valid & ATTR_GID) {
@@ -1039,92 +1039,73 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
                        owner_grouplen = sizeof("nobody") - 1;
                        /* goto out; */
                }
+               bmval[1] |= FATTR4_WORD1_OWNER_GROUP;
                len += 4 + (XDR_QUADLEN(owner_grouplen) << 2);
        }
-       if (iap->ia_valid & ATTR_ATIME_SET)
+       if (iap->ia_valid & ATTR_ATIME_SET) {
+               bmval[1] |= FATTR4_WORD1_TIME_ACCESS_SET;
                len += 16;
-       else if (iap->ia_valid & ATTR_ATIME)
+       } else if (iap->ia_valid & ATTR_ATIME) {
+               bmval[1] |= FATTR4_WORD1_TIME_ACCESS_SET;
                len += 4;
-       if (iap->ia_valid & ATTR_MTIME_SET)
+       }
+       if (iap->ia_valid & ATTR_MTIME_SET) {
+               bmval[1] |= FATTR4_WORD1_TIME_MODIFY_SET;
                len += 16;
-       else if (iap->ia_valid & ATTR_MTIME)
+       } else if (iap->ia_valid & ATTR_MTIME) {
+               bmval[1] |= FATTR4_WORD1_TIME_MODIFY_SET;
                len += 4;
+       }
        if (label) {
                len += 4 + 4 + 4 + (XDR_QUADLEN(label->len) << 2);
-               bmval_len = 3;
+               bmval[2] |= FATTR4_WORD2_SECURITY_LABEL;
        }
 
-       len += bmval_len << 2;
-       p = reserve_space(xdr, len);
+       if (bmval[2] != 0)
+               bmval_len = 3;
+       else if (bmval[1] != 0)
+               bmval_len = 2;
+       else
+               bmval_len = 1;
+
+       p = reserve_space(xdr, 4 + (bmval_len << 2) + 4 + len);
 
-       /*
-        * We write the bitmap length now, but leave the bitmap and the attribute
-        * buffer length to be backfilled at the end of this routine.
-        */
        *p++ = cpu_to_be32(bmval_len);
-       q = p;
-       /* Skip bitmap entries + attrlen */
-       p += bmval_len + 1;
+       for (i = 0; i < bmval_len; i++)
+               *p++ = cpu_to_be32(bmval[i]);
+       *p++ = cpu_to_be32(len);
 
-       if (iap->ia_valid & ATTR_SIZE) {
-               bmval0 |= FATTR4_WORD0_SIZE;
+       if (bmval[0] & FATTR4_WORD0_SIZE)
                p = xdr_encode_hyper(p, iap->ia_size);
-       }
-       if (iap->ia_valid & ATTR_MODE) {
-               bmval1 |= FATTR4_WORD1_MODE;
+       if (bmval[1] & FATTR4_WORD1_MODE)
                *p++ = cpu_to_be32(iap->ia_mode & S_IALLUGO);
-       }
-       if (iap->ia_valid & ATTR_UID) {
-               bmval1 |= FATTR4_WORD1_OWNER;
+       if (bmval[1] & FATTR4_WORD1_OWNER)
                p = xdr_encode_opaque(p, owner_name, owner_namelen);
-       }
-       if (iap->ia_valid & ATTR_GID) {
-               bmval1 |= FATTR4_WORD1_OWNER_GROUP;
+       if (bmval[1] & FATTR4_WORD1_OWNER_GROUP)
                p = xdr_encode_opaque(p, owner_group, owner_grouplen);
+       if (bmval[1] & FATTR4_WORD1_TIME_ACCESS_SET) {
+               if (iap->ia_valid & ATTR_ATIME_SET) {
+                       *p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME);
+                       p = xdr_encode_hyper(p, (s64)iap->ia_atime.tv_sec);
+                       *p++ = cpu_to_be32(iap->ia_atime.tv_nsec);
+               } else
+                       *p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME);
        }
-       if (iap->ia_valid & ATTR_ATIME_SET) {
-               bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET;
-               *p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME);
-               p = xdr_encode_hyper(p, (s64)iap->ia_atime.tv_sec);
-               *p++ = cpu_to_be32(iap->ia_atime.tv_nsec);
-       }
-       else if (iap->ia_valid & ATTR_ATIME) {
-               bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET;
-               *p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME);
-       }
-       if (iap->ia_valid & ATTR_MTIME_SET) {
-               bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET;
-               *p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME);
-               p = xdr_encode_hyper(p, (s64)iap->ia_mtime.tv_sec);
-               *p++ = cpu_to_be32(iap->ia_mtime.tv_nsec);
-       }
-       else if (iap->ia_valid & ATTR_MTIME) {
-               bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET;
-               *p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME);
+       if (bmval[1] & FATTR4_WORD1_TIME_MODIFY_SET) {
+               if (iap->ia_valid & ATTR_MTIME_SET) {
+                       *p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME);
+                       p = xdr_encode_hyper(p, (s64)iap->ia_mtime.tv_sec);
+                       *p++ = cpu_to_be32(iap->ia_mtime.tv_nsec);
+               } else
+                       *p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME);
        }
-       if (label) {
-               bmval2 |= FATTR4_WORD2_SECURITY_LABEL;
+       if (bmval[2] & FATTR4_WORD2_SECURITY_LABEL) {
                *p++ = cpu_to_be32(label->lfs);
                *p++ = cpu_to_be32(label->pi);
                *p++ = cpu_to_be32(label->len);
                p = xdr_encode_opaque_fixed(p, label->label, label->len);
        }
 
-       /*
-        * Now we backfill the bitmap and the attribute buffer length.
-        */
-       if (len != ((char *)p - (char *)q) + 4) {
-               printk(KERN_ERR "NFS: Attr length error, %u != %Zu\n",
-                               len, ((char *)p - (char *)q) + 4);
-               BUG();
-       }
-       *q++ = htonl(bmval0);
-       *q++ = htonl(bmval1);
-       if (bmval_len == 3)
-               *q++ = htonl(bmval2);
-       len = (char *)p - (char *)(q + 1);
-       *q = htonl(len);
-
 /* out: */
 }
 
index 280acef6f0dc45e29365b197a8242f7d26bb22f7..1cb621131b00a786bb1632cd6e5965dd1acb0a9a 100644 (file)
@@ -282,19 +282,14 @@ static unsigned int file_hashval(struct inode *ino)
 
 static struct hlist_head file_hashtbl[FILE_HASH_SIZE];
 
-static void __nfs4_file_get_access(struct nfs4_file *fp, int oflag)
-{
-       WARN_ON_ONCE(!(fp->fi_fds[oflag] || fp->fi_fds[O_RDWR]));
-       atomic_inc(&fp->fi_access[oflag]);
-}
-
 static void nfs4_file_get_access(struct nfs4_file *fp, int oflag)
 {
+       WARN_ON_ONCE(!fp->fi_fds[oflag]);
        if (oflag == O_RDWR) {
-               __nfs4_file_get_access(fp, O_RDONLY);
-               __nfs4_file_get_access(fp, O_WRONLY);
+               atomic_inc(&fp->fi_access[O_RDONLY]);
+               atomic_inc(&fp->fi_access[O_WRONLY]);
        } else
-               __nfs4_file_get_access(fp, oflag);
+               atomic_inc(&fp->fi_access[oflag]);
 }
 
 static void nfs4_file_put_fd(struct nfs4_file *fp, int oflag)
index 5c1c864e81cc0dbcb0cd2f358f52f3c62ae6907d..5b62c95a6f5d21449a2691cbf2ac7277f9510242 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/time.h>
 #include <linux/debugfs.h>
 #include <linux/slab.h>
+#include <linux/bitmap.h>
 
 #include "heartbeat.h"
 #include "tcp.h"
@@ -282,15 +283,6 @@ struct o2hb_bio_wait_ctxt {
        int               wc_error;
 };
 
-static int o2hb_pop_count(void *map, int count)
-{
-       int i = -1, pop = 0;
-
-       while ((i = find_next_bit(map, count, i + 1)) < count)
-               pop++;
-       return pop;
-}
-
 static void o2hb_write_timeout(struct work_struct *work)
 {
        int failed, quorum;
@@ -307,9 +299,9 @@ static void o2hb_write_timeout(struct work_struct *work)
                spin_lock_irqsave(&o2hb_live_lock, flags);
                if (test_bit(reg->hr_region_num, o2hb_quorum_region_bitmap))
                        set_bit(reg->hr_region_num, o2hb_failed_region_bitmap);
-               failed = o2hb_pop_count(&o2hb_failed_region_bitmap,
+               failed = bitmap_weight(o2hb_failed_region_bitmap,
                                        O2NM_MAX_REGIONS);
-               quorum = o2hb_pop_count(&o2hb_quorum_region_bitmap,
+               quorum = bitmap_weight(o2hb_quorum_region_bitmap,
                                        O2NM_MAX_REGIONS);
                spin_unlock_irqrestore(&o2hb_live_lock, flags);
 
@@ -771,7 +763,7 @@ static void o2hb_set_quorum_device(struct o2hb_region *reg)
         * If global heartbeat active, unpin all regions if the
         * region count > CUT_OFF
         */
-       if (o2hb_pop_count(&o2hb_quorum_region_bitmap,
+       if (bitmap_weight(o2hb_quorum_region_bitmap,
                           O2NM_MAX_REGIONS) > O2HB_PIN_CUT_OFF)
                o2hb_region_unpin(NULL);
 unlock:
@@ -956,23 +948,9 @@ out:
        return changed;
 }
 
-/* This could be faster if we just implmented a find_last_bit, but I
- * don't think the circumstances warrant it. */
-static int o2hb_highest_node(unsigned long *nodes,
-                            int numbits)
+static int o2hb_highest_node(unsigned long *nodes, int numbits)
 {
-       int highest, node;
-
-       highest = numbits;
-       node = -1;
-       while ((node = find_next_bit(nodes, numbits, node + 1)) != -1) {
-               if (node >= numbits)
-                       break;
-
-               highest = node;
-       }
-
-       return highest;
+       return find_last_bit(nodes, numbits);
 }
 
 static int o2hb_do_disk_heartbeat(struct o2hb_region *reg)
@@ -1831,7 +1809,7 @@ static ssize_t o2hb_region_dev_write(struct o2hb_region *reg,
        live_threshold = O2HB_LIVE_THRESHOLD;
        if (o2hb_global_heartbeat_active()) {
                spin_lock(&o2hb_live_lock);
-               if (o2hb_pop_count(&o2hb_region_bitmap, O2NM_MAX_REGIONS) == 1)
+               if (bitmap_weight(o2hb_region_bitmap, O2NM_MAX_REGIONS) == 1)
                        live_threshold <<= 1;
                spin_unlock(&o2hb_live_lock);
        }
@@ -2182,7 +2160,7 @@ static void o2hb_heartbeat_group_drop_item(struct config_group *group,
        if (!o2hb_dependent_users)
                goto unlock;
 
-       if (o2hb_pop_count(&o2hb_quorum_region_bitmap,
+       if (bitmap_weight(o2hb_quorum_region_bitmap,
                           O2NM_MAX_REGIONS) <= O2HB_PIN_CUT_OFF)
                o2hb_region_pin(NULL);
 
@@ -2482,7 +2460,7 @@ static int o2hb_region_inc_user(const char *region_uuid)
        if (o2hb_dependent_users > 1)
                goto unlock;
 
-       if (o2hb_pop_count(&o2hb_quorum_region_bitmap,
+       if (bitmap_weight(o2hb_quorum_region_bitmap,
                           O2NM_MAX_REGIONS) <= O2HB_PIN_CUT_OFF)
                ret = o2hb_region_pin(NULL);
 
index baa2b9ef7eef90094dbd3ef8d76f6a6e1df64224..2260fb9e650831fef349ce2c6f6dcd878ffa45d2 100644 (file)
@@ -199,7 +199,8 @@ extern struct mlog_bits mlog_and_bits, mlog_not_bits;
 #define mlog_errno(st) do {                                            \
        int _st = (st);                                                 \
        if (_st != -ERESTARTSYS && _st != -EINTR &&                     \
-           _st != AOP_TRUNCATED_PAGE && _st != -ENOSPC)                \
+           _st != AOP_TRUNCATED_PAGE && _st != -ENOSPC &&              \
+           _st != -EDQUOT)                                             \
                mlog(ML_ERROR, "status = %lld\n", (long long)_st);      \
 } while (0)
 
index 33ecbe0e6734a7deaf0c8712934b9eb78fb44197..3d09a940c015d4e0304aaf2d3c98baeb3c0b80f8 100644 (file)
@@ -1888,8 +1888,10 @@ ok:
                         * up nodes that this node contacted */
                        while ((nn = find_next_bit (mle->response_map, O2NM_MAX_NODES,
                                                    nn+1)) < O2NM_MAX_NODES) {
-                               if (nn != dlm->node_num && nn != assert->node_idx)
+                               if (nn != dlm->node_num && nn != assert->node_idx) {
                                        master_request = 1;
+                                       break;
+                               }
                        }
                }
                mle->master = assert->node_idx;
@@ -2357,6 +2359,10 @@ static int dlm_is_lockres_migrateable(struct dlm_ctxt *dlm,
 
        assert_spin_locked(&res->spinlock);
 
+       /* delay migration when the lockres is in MIGRATING state */
+       if (res->state & DLM_LOCK_RES_MIGRATING)
+               return 0;
+
        if (res->owner != dlm->node_num)
                return 0;
 
index 773bd32bfd8c8bb56bcf5f7ee7880cd65bbe8f26..317c0d4024d823d383318170195c556d86cb5542 100644 (file)
@@ -1882,6 +1882,13 @@ static int dlm_process_recovery_data(struct dlm_ctxt *dlm,
 
                if (ml->type == LKM_NLMODE)
                        goto skip_lvb;
+               
+               /*
+                * If the lock is in the blocked list it can't have a valid lvb,
+                * so skip it
+                */
+               if (ml->list == DLM_BLOCKED_LIST)
+                       goto skip_lvb;
 
                if (!dlm_lvb_is_empty(mres->lvb)) {
                        if (lksb->flags & DLM_LKSB_PUT_LVB) {
index 998b17eda09d807b2b1d2ccc0b94cdc2a45974a1..9f6b96a09615bcc243b81ebc5cf3c9139c2deec3 100644 (file)
@@ -2965,6 +2965,11 @@ int ocfs2_duplicate_clusters_by_page(handle_t *handle,
                        to = map_end & (PAGE_CACHE_SIZE - 1);
 
                page = find_or_create_page(mapping, page_index, GFP_NOFS);
+               if (!page) {
+                       ret = -ENOMEM;
+                       mlog_errno(ret);
+                       break;
+               }
 
                /*
                 * In case PAGE_CACHE_SIZE <= CLUSTER_SIZE, This page
index 9ac4057a86c90f64a84ea2cee0b92e4f549ac01a..839a2bad7f45b693db4ed478598b997c42077712 100644 (file)
@@ -630,6 +630,12 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options)
        struct udf_sb_info *sbi = UDF_SB(sb);
        int error = 0;
 
+       if (sbi->s_lvid_bh) {
+               int write_rev = le16_to_cpu(udf_sb_lvidiu(sbi)->minUDFWriteRev);
+               if (write_rev > UDF_MAX_WRITE_VERSION && !(*flags & MS_RDONLY))
+                       return -EACCES;
+       }
+
        uopt.flags = sbi->s_flags;
        uopt.uid   = sbi->s_uid;
        uopt.gid   = sbi->s_gid;
@@ -649,12 +655,6 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options)
        sbi->s_dmode = uopt.dmode;
        write_unlock(&sbi->s_cred_lock);
 
-       if (sbi->s_lvid_bh) {
-               int write_rev = le16_to_cpu(udf_sb_lvidiu(sbi)->minUDFWriteRev);
-               if (write_rev > UDF_MAX_WRITE_VERSION)
-                       *flags |= MS_RDONLY;
-       }
-
        if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
                goto out_unlock;
 
@@ -843,27 +843,38 @@ static int udf_find_fileset(struct super_block *sb,
        return 1;
 }
 
+/*
+ * Load primary Volume Descriptor Sequence
+ *
+ * Return <0 on error, 0 on success. -EAGAIN is special meaning next sequence
+ * should be tried.
+ */
 static int udf_load_pvoldesc(struct super_block *sb, sector_t block)
 {
        struct primaryVolDesc *pvoldesc;
        struct ustr *instr, *outstr;
        struct buffer_head *bh;
        uint16_t ident;
-       int ret = 1;
+       int ret = -ENOMEM;
 
        instr = kmalloc(sizeof(struct ustr), GFP_NOFS);
        if (!instr)
-               return 1;
+               return -ENOMEM;
 
        outstr = kmalloc(sizeof(struct ustr), GFP_NOFS);
        if (!outstr)
                goto out1;
 
        bh = udf_read_tagged(sb, block, block, &ident);
-       if (!bh)
+       if (!bh) {
+               ret = -EAGAIN;
                goto out2;
+       }
 
-       BUG_ON(ident != TAG_IDENT_PVD);
+       if (ident != TAG_IDENT_PVD) {
+               ret = -EIO;
+               goto out_bh;
+       }
 
        pvoldesc = (struct primaryVolDesc *)bh->b_data;
 
@@ -889,8 +900,9 @@ static int udf_load_pvoldesc(struct super_block *sb, sector_t block)
                if (udf_CS0toUTF8(outstr, instr))
                        udf_debug("volSetIdent[] = '%s'\n", outstr->u_name);
 
-       brelse(bh);
        ret = 0;
+out_bh:
+       brelse(bh);
 out2:
        kfree(outstr);
 out1:
@@ -947,7 +959,7 @@ static int udf_load_metadata_files(struct super_block *sb, int partition)
 
                if (mdata->s_mirror_fe == NULL) {
                        udf_err(sb, "Both metadata and mirror metadata inode efe can not found\n");
-                       goto error_exit;
+                       return -EIO;
                }
        }
 
@@ -964,23 +976,18 @@ static int udf_load_metadata_files(struct super_block *sb, int partition)
                          addr.logicalBlockNum, addr.partitionReferenceNum);
 
                mdata->s_bitmap_fe = udf_iget(sb, &addr);
-
                if (mdata->s_bitmap_fe == NULL) {
                        if (sb->s_flags & MS_RDONLY)
                                udf_warn(sb, "bitmap inode efe not found but it's ok since the disc is mounted read-only\n");
                        else {
                                udf_err(sb, "bitmap inode efe not found and attempted read-write mount\n");
-                               goto error_exit;
+                               return -EIO;
                        }
                }
        }
 
        udf_debug("udf_load_metadata_files Ok\n");
-
        return 0;
-
-error_exit:
-       return 1;
 }
 
 static void udf_load_fileset(struct super_block *sb, struct buffer_head *bh,
@@ -1069,7 +1076,7 @@ static int udf_fill_partdesc_info(struct super_block *sb,
                if (!map->s_uspace.s_table) {
                        udf_debug("cannot load unallocSpaceTable (part %d)\n",
                                  p_index);
-                       return 1;
+                       return -EIO;
                }
                map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_TABLE;
                udf_debug("unallocSpaceTable (part %d) @ %ld\n",
@@ -1079,7 +1086,7 @@ static int udf_fill_partdesc_info(struct super_block *sb,
        if (phd->unallocSpaceBitmap.extLength) {
                struct udf_bitmap *bitmap = udf_sb_alloc_bitmap(sb, p_index);
                if (!bitmap)
-                       return 1;
+                       return -ENOMEM;
                map->s_uspace.s_bitmap = bitmap;
                bitmap->s_extPosition = le32_to_cpu(
                                phd->unallocSpaceBitmap.extPosition);
@@ -1102,7 +1109,7 @@ static int udf_fill_partdesc_info(struct super_block *sb,
                if (!map->s_fspace.s_table) {
                        udf_debug("cannot load freedSpaceTable (part %d)\n",
                                  p_index);
-                       return 1;
+                       return -EIO;
                }
 
                map->s_partition_flags |= UDF_PART_FLAG_FREED_TABLE;
@@ -1113,7 +1120,7 @@ static int udf_fill_partdesc_info(struct super_block *sb,
        if (phd->freedSpaceBitmap.extLength) {
                struct udf_bitmap *bitmap = udf_sb_alloc_bitmap(sb, p_index);
                if (!bitmap)
-                       return 1;
+                       return -ENOMEM;
                map->s_fspace.s_bitmap = bitmap;
                bitmap->s_extPosition = le32_to_cpu(
                                phd->freedSpaceBitmap.extPosition);
@@ -1165,7 +1172,7 @@ static int udf_load_vat(struct super_block *sb, int p_index, int type1_index)
                udf_find_vat_block(sb, p_index, type1_index, blocks - 1);
        }
        if (!sbi->s_vat_inode)
-               return 1;
+               return -EIO;
 
        if (map->s_partition_type == UDF_VIRTUAL_MAP15) {
                map->s_type_specific.s_virtual.s_start_offset = 0;
@@ -1177,7 +1184,7 @@ static int udf_load_vat(struct super_block *sb, int p_index, int type1_index)
                        pos = udf_block_map(sbi->s_vat_inode, 0);
                        bh = sb_bread(sb, pos);
                        if (!bh)
-                               return 1;
+                               return -EIO;
                        vat20 = (struct virtualAllocationTable20 *)bh->b_data;
                } else {
                        vat20 = (struct virtualAllocationTable20 *)
@@ -1195,6 +1202,12 @@ static int udf_load_vat(struct super_block *sb, int p_index, int type1_index)
        return 0;
 }
 
+/*
+ * Load partition descriptor block
+ *
+ * Returns <0 on error, 0 on success, -EAGAIN is special - try next descriptor
+ * sequence.
+ */
 static int udf_load_partdesc(struct super_block *sb, sector_t block)
 {
        struct buffer_head *bh;
@@ -1204,13 +1217,15 @@ static int udf_load_partdesc(struct super_block *sb, sector_t block)
        int i, type1_idx;
        uint16_t partitionNumber;
        uint16_t ident;
-       int ret = 0;
+       int ret;
 
        bh = udf_read_tagged(sb, block, block, &ident);
        if (!bh)
-               return 1;
-       if (ident != TAG_IDENT_PD)
+               return -EAGAIN;
+       if (ident != TAG_IDENT_PD) {
+               ret = 0;
                goto out_bh;
+       }
 
        p = (struct partitionDesc *)bh->b_data;
        partitionNumber = le16_to_cpu(p->partitionNumber);
@@ -1229,10 +1244,13 @@ static int udf_load_partdesc(struct super_block *sb, sector_t block)
        if (i >= sbi->s_partitions) {
                udf_debug("Partition (%d) not found in partition map\n",
                          partitionNumber);
+               ret = 0;
                goto out_bh;
        }
 
        ret = udf_fill_partdesc_info(sb, p, i);
+       if (ret < 0)
+               goto out_bh;
 
        /*
         * Now rescan for VIRTUAL or METADATA partitions when SPARABLE and
@@ -1249,32 +1267,37 @@ static int udf_load_partdesc(struct super_block *sb, sector_t block)
                        break;
        }
 
-       if (i >= sbi->s_partitions)
+       if (i >= sbi->s_partitions) {
+               ret = 0;
                goto out_bh;
+       }
 
        ret = udf_fill_partdesc_info(sb, p, i);
-       if (ret)
+       if (ret < 0)
                goto out_bh;
 
        if (map->s_partition_type == UDF_METADATA_MAP25) {
                ret = udf_load_metadata_files(sb, i);
-               if (ret) {
+               if (ret < 0) {
                        udf_err(sb, "error loading MetaData partition map %d\n",
                                i);
                        goto out_bh;
                }
        } else {
-               ret = udf_load_vat(sb, i, type1_idx);
-               if (ret)
-                       goto out_bh;
                /*
-                * Mark filesystem read-only if we have a partition with
-                * virtual map since we don't handle writing to it (we
-                * overwrite blocks instead of relocating them).
+                * If we have a partition with virtual map, we don't handle
+                * writing to it (we overwrite blocks instead of relocating
+                * them).
                 */
-               sb->s_flags |= MS_RDONLY;
-               pr_notice("Filesystem marked read-only because writing to pseudooverwrite partition is not implemented\n");
+               if (!(sb->s_flags & MS_RDONLY)) {
+                       ret = -EACCES;
+                       goto out_bh;
+               }
+               ret = udf_load_vat(sb, i, type1_idx);
+               if (ret < 0)
+                       goto out_bh;
        }
+       ret = 0;
 out_bh:
        /* In case loading failed, we handle cleanup in udf_fill_super */
        brelse(bh);
@@ -1340,11 +1363,11 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block,
        uint16_t ident;
        struct buffer_head *bh;
        unsigned int table_len;
-       int ret = 0;
+       int ret;
 
        bh = udf_read_tagged(sb, block, block, &ident);
        if (!bh)
-               return 1;
+               return -EAGAIN;
        BUG_ON(ident != TAG_IDENT_LVD);
        lvd = (struct logicalVolDesc *)bh->b_data;
        table_len = le32_to_cpu(lvd->mapTableLength);
@@ -1352,7 +1375,7 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block,
                udf_err(sb, "error loading logical volume descriptor: "
                        "Partition table too long (%u > %lu)\n", table_len,
                        sb->s_blocksize - sizeof(*lvd));
-               ret = 1;
+               ret = -EIO;
                goto out_bh;
        }
 
@@ -1396,11 +1419,10 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block,
                        } else if (!strncmp(upm2->partIdent.ident,
                                                UDF_ID_SPARABLE,
                                                strlen(UDF_ID_SPARABLE))) {
-                               if (udf_load_sparable_map(sb, map,
-                                   (struct sparablePartitionMap *)gpm) < 0) {
-                                       ret = 1;
+                               ret = udf_load_sparable_map(sb, map,
+                                       (struct sparablePartitionMap *)gpm);
+                               if (ret < 0)
                                        goto out_bh;
-                               }
                        } else if (!strncmp(upm2->partIdent.ident,
                                                UDF_ID_METADATA,
                                                strlen(UDF_ID_METADATA))) {
@@ -1465,7 +1487,7 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block,
        }
        if (lvd->integritySeqExt.extLength)
                udf_load_logicalvolint(sb, leea_to_cpu(lvd->integritySeqExt));
-
+       ret = 0;
 out_bh:
        brelse(bh);
        return ret;
@@ -1503,22 +1525,18 @@ static void udf_load_logicalvolint(struct super_block *sb, struct kernel_extent_
 }
 
 /*
- * udf_process_sequence
- *
- * PURPOSE
- *     Process a main/reserve volume descriptor sequence.
- *
- * PRE-CONDITIONS
- *     sb                      Pointer to _locked_ superblock.
- *     block                   First block of first extent of the sequence.
- *     lastblock               Lastblock of first extent of the sequence.
+ * Process a main/reserve volume descriptor sequence.
+ *   @block            First block of first extent of the sequence.
+ *   @lastblock                Lastblock of first extent of the sequence.
+ *   @fileset          There we store extent containing root fileset
  *
- * HISTORY
- *     July 1, 1997 - Andrew E. Mileski
- *     Written, tested, and released.
+ * Returns <0 on error, 0 on success. -EAGAIN is special - try next descriptor
+ * sequence
  */
-static noinline int udf_process_sequence(struct super_block *sb, long block,
-                               long lastblock, struct kernel_lb_addr *fileset)
+static noinline int udf_process_sequence(
+               struct super_block *sb,
+               sector_t block, sector_t lastblock,
+               struct kernel_lb_addr *fileset)
 {
        struct buffer_head *bh = NULL;
        struct udf_vds_record vds[VDS_POS_LENGTH];
@@ -1529,6 +1547,7 @@ static noinline int udf_process_sequence(struct super_block *sb, long block,
        uint32_t vdsn;
        uint16_t ident;
        long next_s = 0, next_e = 0;
+       int ret;
 
        memset(vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH);
 
@@ -1543,7 +1562,7 @@ static noinline int udf_process_sequence(struct super_block *sb, long block,
                        udf_err(sb,
                                "Block %llu of volume descriptor sequence is corrupted or we could not read it\n",
                                (unsigned long long)block);
-                       return 1;
+                       return -EAGAIN;
                }
 
                /* Process each descriptor (ISO 13346 3/8.3-8.4) */
@@ -1616,14 +1635,19 @@ static noinline int udf_process_sequence(struct super_block *sb, long block,
         */
        if (!vds[VDS_POS_PRIMARY_VOL_DESC].block) {
                udf_err(sb, "Primary Volume Descriptor not found!\n");
-               return 1;
+               return -EAGAIN;
+       }
+       ret = udf_load_pvoldesc(sb, vds[VDS_POS_PRIMARY_VOL_DESC].block);
+       if (ret < 0)
+               return ret;
+
+       if (vds[VDS_POS_LOGICAL_VOL_DESC].block) {
+               ret = udf_load_logicalvol(sb,
+                                         vds[VDS_POS_LOGICAL_VOL_DESC].block,
+                                         fileset);
+               if (ret < 0)
+                       return ret;
        }
-       if (udf_load_pvoldesc(sb, vds[VDS_POS_PRIMARY_VOL_DESC].block))
-               return 1;
-
-       if (vds[VDS_POS_LOGICAL_VOL_DESC].block && udf_load_logicalvol(sb,
-           vds[VDS_POS_LOGICAL_VOL_DESC].block, fileset))
-               return 1;
 
        if (vds[VDS_POS_PARTITION_DESC].block) {
                /*
@@ -1632,19 +1656,27 @@ static noinline int udf_process_sequence(struct super_block *sb, long block,
                 */
                for (block = vds[VDS_POS_PARTITION_DESC].block;
                     block < vds[VDS_POS_TERMINATING_DESC].block;
-                    block++)
-                       if (udf_load_partdesc(sb, block))
-                               return 1;
+                    block++) {
+                       ret = udf_load_partdesc(sb, block);
+                       if (ret < 0)
+                               return ret;
+               }
        }
 
        return 0;
 }
 
+/*
+ * Load Volume Descriptor Sequence described by anchor in bh
+ *
+ * Returns <0 on error, 0 on success
+ */
 static int udf_load_sequence(struct super_block *sb, struct buffer_head *bh,
                             struct kernel_lb_addr *fileset)
 {
        struct anchorVolDescPtr *anchor;
-       long main_s, main_e, reserve_s, reserve_e;
+       sector_t main_s, main_e, reserve_s, reserve_e;
+       int ret;
 
        anchor = (struct anchorVolDescPtr *)bh->b_data;
 
@@ -1662,18 +1694,26 @@ static int udf_load_sequence(struct super_block *sb, struct buffer_head *bh,
 
        /* Process the main & reserve sequences */
        /* responsible for finding the PartitionDesc(s) */
-       if (!udf_process_sequence(sb, main_s, main_e, fileset))
-               return 1;
-       udf_sb_free_partitions(sb);
-       if (!udf_process_sequence(sb, reserve_s, reserve_e, fileset))
-               return 1;
+       ret = udf_process_sequence(sb, main_s, main_e, fileset);
+       if (ret != -EAGAIN)
+               return ret;
        udf_sb_free_partitions(sb);
-       return 0;
+       ret = udf_process_sequence(sb, reserve_s, reserve_e, fileset);
+       if (ret < 0) {
+               udf_sb_free_partitions(sb);
+               /* No sequence was OK, return -EIO */
+               if (ret == -EAGAIN)
+                       ret = -EIO;
+       }
+       return ret;
 }
 
 /*
  * Check whether there is an anchor block in the given block and
  * load Volume Descriptor Sequence if so.
+ *
+ * Returns <0 on error, 0 on success, -EAGAIN is special - try next anchor
+ * block
  */
 static int udf_check_anchor_block(struct super_block *sb, sector_t block,
                                  struct kernel_lb_addr *fileset)
@@ -1685,33 +1725,40 @@ static int udf_check_anchor_block(struct super_block *sb, sector_t block,
        if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV) &&
            udf_fixed_to_variable(block) >=
            sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits)
-               return 0;
+               return -EAGAIN;
 
        bh = udf_read_tagged(sb, block, block, &ident);
        if (!bh)
-               return 0;
+               return -EAGAIN;
        if (ident != TAG_IDENT_AVDP) {
                brelse(bh);
-               return 0;
+               return -EAGAIN;
        }
        ret = udf_load_sequence(sb, bh, fileset);
        brelse(bh);
        return ret;
 }
 
-/* Search for an anchor volume descriptor pointer */
-static sector_t udf_scan_anchors(struct super_block *sb, sector_t lastblock,
-                                struct kernel_lb_addr *fileset)
+/*
+ * Search for an anchor volume descriptor pointer.
+ *
+ * Returns < 0 on error, 0 on success. -EAGAIN is special - try next set
+ * of anchors.
+ */
+static int udf_scan_anchors(struct super_block *sb, sector_t *lastblock,
+                           struct kernel_lb_addr *fileset)
 {
        sector_t last[6];
        int i;
        struct udf_sb_info *sbi = UDF_SB(sb);
        int last_count = 0;
+       int ret;
 
        /* First try user provided anchor */
        if (sbi->s_anchor) {
-               if (udf_check_anchor_block(sb, sbi->s_anchor, fileset))
-                       return lastblock;
+               ret = udf_check_anchor_block(sb, sbi->s_anchor, fileset);
+               if (ret != -EAGAIN)
+                       return ret;
        }
        /*
         * according to spec, anchor is in either:
@@ -1720,39 +1767,46 @@ static sector_t udf_scan_anchors(struct super_block *sb, sector_t lastblock,
         *     lastblock
         *  however, if the disc isn't closed, it could be 512.
         */
-       if (udf_check_anchor_block(sb, sbi->s_session + 256, fileset))
-               return lastblock;
+       ret = udf_check_anchor_block(sb, sbi->s_session + 256, fileset);
+       if (ret != -EAGAIN)
+               return ret;
        /*
         * The trouble is which block is the last one. Drives often misreport
         * this so we try various possibilities.
         */
-       last[last_count++] = lastblock;
-       if (lastblock >= 1)
-               last[last_count++] = lastblock - 1;
-       last[last_count++] = lastblock + 1;
-       if (lastblock >= 2)
-               last[last_count++] = lastblock - 2;
-       if (lastblock >= 150)
-               last[last_count++] = lastblock - 150;
-       if (lastblock >= 152)
-               last[last_count++] = lastblock - 152;
+       last[last_count++] = *lastblock;
+       if (*lastblock >= 1)
+               last[last_count++] = *lastblock - 1;
+       last[last_count++] = *lastblock + 1;
+       if (*lastblock >= 2)
+               last[last_count++] = *lastblock - 2;
+       if (*lastblock >= 150)
+               last[last_count++] = *lastblock - 150;
+       if (*lastblock >= 152)
+               last[last_count++] = *lastblock - 152;
 
        for (i = 0; i < last_count; i++) {
                if (last[i] >= sb->s_bdev->bd_inode->i_size >>
                                sb->s_blocksize_bits)
                        continue;
-               if (udf_check_anchor_block(sb, last[i], fileset))
-                       return last[i];
+               ret = udf_check_anchor_block(sb, last[i], fileset);
+               if (ret != -EAGAIN) {
+                       if (!ret)
+                               *lastblock = last[i];
+                       return ret;
+               }
                if (last[i] < 256)
                        continue;
-               if (udf_check_anchor_block(sb, last[i] - 256, fileset))
-                       return last[i];
+               ret = udf_check_anchor_block(sb, last[i] - 256, fileset);
+               if (ret != -EAGAIN) {
+                       if (!ret)
+                               *lastblock = last[i];
+                       return ret;
+               }
        }
 
        /* Finally try block 512 in case media is open */
-       if (udf_check_anchor_block(sb, sbi->s_session + 512, fileset))
-               return last[0];
-       return 0;
+       return udf_check_anchor_block(sb, sbi->s_session + 512, fileset);
 }
 
 /*
@@ -1760,54 +1814,59 @@ static sector_t udf_scan_anchors(struct super_block *sb, sector_t lastblock,
  * area specified by it. The function expects sbi->s_lastblock to be the last
  * block on the media.
  *
- * Return 1 if ok, 0 if not found.
- *
+ * Return <0 on error, 0 if anchor found. -EAGAIN is special meaning anchor
+ * was not found.
  */
 static int udf_find_anchor(struct super_block *sb,
                           struct kernel_lb_addr *fileset)
 {
-       sector_t lastblock;
        struct udf_sb_info *sbi = UDF_SB(sb);
+       sector_t lastblock = sbi->s_last_block;
+       int ret;
 
-       lastblock = udf_scan_anchors(sb, sbi->s_last_block, fileset);
-       if (lastblock)
+       ret = udf_scan_anchors(sb, &lastblock, fileset);
+       if (ret != -EAGAIN)
                goto out;
 
        /* No anchor found? Try VARCONV conversion of block numbers */
        UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
+       lastblock = udf_variable_to_fixed(sbi->s_last_block);
        /* Firstly, we try to not convert number of the last block */
-       lastblock = udf_scan_anchors(sb,
-                               udf_variable_to_fixed(sbi->s_last_block),
-                               fileset);
-       if (lastblock)
+       ret = udf_scan_anchors(sb, &lastblock, fileset);
+       if (ret != -EAGAIN)
                goto out;
 
+       lastblock = sbi->s_last_block;
        /* Secondly, we try with converted number of the last block */
-       lastblock = udf_scan_anchors(sb, sbi->s_last_block, fileset);
-       if (!lastblock) {
+       ret = udf_scan_anchors(sb, &lastblock, fileset);
+       if (ret < 0) {
                /* VARCONV didn't help. Clear it. */
                UDF_CLEAR_FLAG(sb, UDF_FLAG_VARCONV);
-               return 0;
        }
 out:
-       sbi->s_last_block = lastblock;
-       return 1;
+       if (ret == 0)
+               sbi->s_last_block = lastblock;
+       return ret;
 }
 
 /*
  * Check Volume Structure Descriptor, find Anchor block and load Volume
- * Descriptor Sequence
+ * Descriptor Sequence.
+ *
+ * Returns < 0 on error, 0 on success. -EAGAIN is special meaning anchor
+ * block was not found.
  */
 static int udf_load_vrs(struct super_block *sb, struct udf_options *uopt,
                        int silent, struct kernel_lb_addr *fileset)
 {
        struct udf_sb_info *sbi = UDF_SB(sb);
        loff_t nsr_off;
+       int ret;
 
        if (!sb_set_blocksize(sb, uopt->blocksize)) {
                if (!silent)
                        udf_warn(sb, "Bad block size\n");
-               return 0;
+               return -EINVAL;
        }
        sbi->s_last_block = uopt->lastblock;
        if (!uopt->novrs) {
@@ -1828,12 +1887,13 @@ static int udf_load_vrs(struct super_block *sb, struct udf_options *uopt,
 
        /* Look for anchor block and load Volume Descriptor Sequence */
        sbi->s_anchor = uopt->anchor;
-       if (!udf_find_anchor(sb, fileset)) {
-               if (!silent)
+       ret = udf_find_anchor(sb, fileset);
+       if (ret < 0) {
+               if (!silent && ret == -EAGAIN)
                        udf_warn(sb, "No anchor found\n");
-               return 0;
+               return ret;
        }
-       return 1;
+       return 0;
 }
 
 static void udf_open_lvid(struct super_block *sb)
@@ -1939,7 +1999,7 @@ u64 lvid_get_unique_id(struct super_block *sb)
 
 static int udf_fill_super(struct super_block *sb, void *options, int silent)
 {
-       int ret;
+       int ret = -EINVAL;
        struct inode *inode = NULL;
        struct udf_options uopt;
        struct kernel_lb_addr rootdir, fileset;
@@ -2011,7 +2071,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
        } else {
                uopt.blocksize = bdev_logical_block_size(sb->s_bdev);
                ret = udf_load_vrs(sb, &uopt, silent, &fileset);
-               if (!ret && uopt.blocksize != UDF_DEFAULT_BLOCKSIZE) {
+               if (ret == -EAGAIN && uopt.blocksize != UDF_DEFAULT_BLOCKSIZE) {
                        if (!silent)
                                pr_notice("Rescanning with blocksize %d\n",
                                          UDF_DEFAULT_BLOCKSIZE);
@@ -2021,8 +2081,11 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
                        ret = udf_load_vrs(sb, &uopt, silent, &fileset);
                }
        }
-       if (!ret) {
-               udf_warn(sb, "No partition found (1)\n");
+       if (ret < 0) {
+               if (ret == -EAGAIN) {
+                       udf_warn(sb, "No partition found (1)\n");
+                       ret = -EINVAL;
+               }
                goto error_out;
        }
 
@@ -2040,9 +2103,13 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
                        udf_err(sb, "minUDFReadRev=%x (max is %x)\n",
                                le16_to_cpu(lvidiu->minUDFReadRev),
                                UDF_MAX_READ_VERSION);
+                       ret = -EINVAL;
+                       goto error_out;
+               } else if (minUDFWriteRev > UDF_MAX_WRITE_VERSION &&
+                          !(sb->s_flags & MS_RDONLY)) {
+                       ret = -EACCES;
                        goto error_out;
-               } else if (minUDFWriteRev > UDF_MAX_WRITE_VERSION)
-                       sb->s_flags |= MS_RDONLY;
+               }
 
                sbi->s_udfrev = minUDFWriteRev;
 
@@ -2054,17 +2121,20 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
 
        if (!sbi->s_partitions) {
                udf_warn(sb, "No partition found (2)\n");
+               ret = -EINVAL;
                goto error_out;
        }
 
        if (sbi->s_partmaps[sbi->s_partition].s_partition_flags &
-                       UDF_PART_FLAG_READ_ONLY) {
-               pr_notice("Partition marked readonly; forcing readonly mount\n");
-               sb->s_flags |= MS_RDONLY;
+                       UDF_PART_FLAG_READ_ONLY &&
+           !(sb->s_flags & MS_RDONLY)) {
+               ret = -EACCES;
+               goto error_out;
        }
 
        if (udf_find_fileset(sb, &fileset, &rootdir)) {
                udf_warn(sb, "No fileset found\n");
+               ret = -EINVAL;
                goto error_out;
        }
 
@@ -2086,6 +2156,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
        if (!inode) {
                udf_err(sb, "Error in udf_iget, block=%d, partition=%d\n",
                       rootdir.logicalBlockNum, rootdir.partitionReferenceNum);
+               ret = -EIO;
                goto error_out;
        }
 
@@ -2093,6 +2164,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
        sb->s_root = d_make_root(inode);
        if (!sb->s_root) {
                udf_err(sb, "Couldn't allocate root dentry\n");
+               ret = -ENOMEM;
                goto error_out;
        }
        sb->s_maxbytes = MAX_LFS_FILESIZE;
@@ -2113,7 +2185,7 @@ error_out:
        kfree(sbi);
        sb->s_fs_info = NULL;
 
-       return -EINVAL;
+       return ret;
 }
 
 void _udf_err(struct super_block *sb, const char *function,
index 596ec71da00e8d4f005ab264142e927d03ac667d..79670869d436ccec578162fa9d7062b900dd93b0 100644 (file)
@@ -1516,13 +1516,26 @@ xfs_vm_write_failed(
        loff_t                  pos,
        unsigned                len)
 {
-       loff_t                  block_offset = pos & PAGE_MASK;
+       loff_t                  block_offset;
        loff_t                  block_start;
        loff_t                  block_end;
        loff_t                  from = pos & (PAGE_CACHE_SIZE - 1);
        loff_t                  to = from + len;
        struct buffer_head      *bh, *head;
 
+       /*
+        * The request pos offset might be 32 or 64 bit, this is all fine
+        * on 64-bit platform.  However, for 64-bit pos request on 32-bit
+        * platform, the high 32-bit will be masked off if we evaluate the
+        * block_offset via (pos & PAGE_MASK) because the PAGE_MASK is
+        * 0xfffff000 as an unsigned long, hence the result is incorrect
+        * which could cause the following ASSERT failed in most cases.
+        * In order to avoid this, we can evaluate the block_offset of the
+        * start of the page by using shifts rather than masks the mismatch
+        * problem.
+        */
+       block_offset = (pos >> PAGE_CACHE_SHIFT) << PAGE_CACHE_SHIFT;
+
        ASSERT(block_offset + from == pos);
 
        head = page_buffers(page);
index d852a2b3e1fdfae0c4fb5bf18452ec79fd03ab01..bf89eb97fefdcf24cf95a3fc3eb57c4b8ecb31cc 100644 (file)
@@ -1941,7 +1941,7 @@ xlog_print_tic_res(
 
        xfs_alert_tag(mp, XFS_PTAG_LOGRES,
                "xlog_write: reservation ran out. Need to up reservation");
-       xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
+       xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR);
 }
 
 /*
index 2b0ba358165619b87523315f1ca3940b4e2606c0..a0fa8021330d95bb9cf4a3374edccf2900f26213 100644 (file)
@@ -336,14 +336,6 @@ xfs_mount_validate_sb(
                return XFS_ERROR(EWRONGFS);
        }
 
-       if ((sbp->sb_qflags & (XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD)) &&
-                       (sbp->sb_qflags & (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD |
-                               XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD))) {
-               xfs_notice(mp,
-"Super block has XFS_OQUOTA bits along with XFS_PQUOTA and/or XFS_GQUOTA bits.\n");
-               return XFS_ERROR(EFSCORRUPTED);
-       }
-
        /*
         * Version 5 superblock feature mask validation. Reject combinations the
         * kernel cannot support up front before checking anything else. For
@@ -387,6 +379,19 @@ xfs_mount_validate_sb(
                }
        }
 
+       if (xfs_sb_version_has_pquotino(sbp)) {
+               if (sbp->sb_qflags & (XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD)) {
+                       xfs_notice(mp,
+                          "Version 5 of Super block has XFS_OQUOTA bits.\n");
+                       return XFS_ERROR(EFSCORRUPTED);
+               }
+       } else if (sbp->sb_qflags & (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD |
+                               XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD)) {
+                       xfs_notice(mp,
+"Superblock earlier than Version 5 has XFS_[PQ]UOTA_{ENFD|CHKD} bits.\n");
+                       return XFS_ERROR(EFSCORRUPTED);
+       }
+
        if (unlikely(
            sbp->sb_logstart == 0 && mp->m_logdev_targp == mp->m_ddev_targp)) {
                xfs_warn(mp,
@@ -572,6 +577,31 @@ out_unwind:
 static void
 xfs_sb_quota_from_disk(struct xfs_sb *sbp)
 {
+       /*
+        * older mkfs doesn't initialize quota inodes to NULLFSINO. This
+        * leads to in-core values having two different values for a quota
+        * inode to be invalid: 0 and NULLFSINO. Change it to a single value
+        * NULLFSINO.
+        *
+        * Note that this change affect only the in-core values. These
+        * values are not written back to disk unless any quota information
+        * is written to the disk. Even in that case, sb_pquotino field is
+        * not written to disk unless the superblock supports pquotino.
+        */
+       if (sbp->sb_uquotino == 0)
+               sbp->sb_uquotino = NULLFSINO;
+       if (sbp->sb_gquotino == 0)
+               sbp->sb_gquotino = NULLFSINO;
+       if (sbp->sb_pquotino == 0)
+               sbp->sb_pquotino = NULLFSINO;
+
+       /*
+        * We need to do these manipilations only if we are working
+        * with an older version of on-disk superblock.
+        */
+       if (xfs_sb_version_has_pquotino(sbp))
+               return;
+
        if (sbp->sb_qflags & XFS_OQUOTA_ENFD)
                sbp->sb_qflags |= (sbp->sb_qflags & XFS_PQUOTA_ACCT) ?
                                        XFS_PQUOTA_ENFD : XFS_GQUOTA_ENFD;
@@ -579,6 +609,18 @@ xfs_sb_quota_from_disk(struct xfs_sb *sbp)
                sbp->sb_qflags |= (sbp->sb_qflags & XFS_PQUOTA_ACCT) ?
                                        XFS_PQUOTA_CHKD : XFS_GQUOTA_CHKD;
        sbp->sb_qflags &= ~(XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD);
+
+       if (sbp->sb_qflags & XFS_PQUOTA_ACCT)  {
+               /*
+                * In older version of superblock, on-disk superblock only
+                * has sb_gquotino, and in-core superblock has both sb_gquotino
+                * and sb_pquotino. But, only one of them is supported at any
+                * point of time. So, if PQUOTA is set in disk superblock,
+                * copy over sb_gquotino to sb_pquotino.
+                */
+               sbp->sb_pquotino = sbp->sb_gquotino;
+               sbp->sb_gquotino = NULLFSINO;
+       }
 }
 
 void
@@ -650,6 +692,13 @@ xfs_sb_quota_to_disk(
 {
        __uint16_t      qflags = from->sb_qflags;
 
+       /*
+        * We need to do these manipilations only if we are working
+        * with an older version of on-disk superblock.
+        */
+       if (xfs_sb_version_has_pquotino(from))
+               return;
+
        if (*fields & XFS_SB_QFLAGS) {
                /*
                 * The in-core version of sb_qflags do not have
@@ -669,6 +718,21 @@ xfs_sb_quota_to_disk(
                to->sb_qflags = cpu_to_be16(qflags);
                *fields &= ~XFS_SB_QFLAGS;
        }
+
+       /*
+        * GQUOTINO and PQUOTINO cannot be used together in versions
+        * of superblock that do not have pquotino. from->sb_flags
+        * tells us which quota is active and should be copied to
+        * disk.
+        */
+       if ((*fields & XFS_SB_GQUOTINO) &&
+                               (from->sb_qflags & XFS_GQUOTA_ACCT))
+               to->sb_gquotino = cpu_to_be64(from->sb_gquotino);
+       else if ((*fields & XFS_SB_PQUOTINO) &&
+                               (from->sb_qflags & XFS_PQUOTA_ACCT))
+               to->sb_gquotino = cpu_to_be64(from->sb_pquotino);
+
+       *fields &= ~(XFS_SB_PQUOTINO | XFS_SB_GQUOTINO);
 }
 
 /*
index d320794d03ce233d93f7ccfcd0a6c2c3f186e9c2..1e2361d0294e31e31d5c9175b76575416f417628 100644 (file)
@@ -834,6 +834,36 @@ xfs_qm_qino_alloc(
        int             error;
        int             committed;
 
+       *ip = NULL;
+       /*
+        * With superblock that doesn't have separate pquotino, we
+        * share an inode between gquota and pquota. If the on-disk
+        * superblock has GQUOTA and the filesystem is now mounted
+        * with PQUOTA, just use sb_gquotino for sb_pquotino and
+        * vice-versa.
+        */
+       if (!xfs_sb_version_has_pquotino(&mp->m_sb) &&
+                       (flags & (XFS_QMOPT_PQUOTA|XFS_QMOPT_GQUOTA))) {
+               xfs_ino_t ino = NULLFSINO;
+
+               if ((flags & XFS_QMOPT_PQUOTA) &&
+                            (mp->m_sb.sb_gquotino != NULLFSINO)) {
+                       ino = mp->m_sb.sb_gquotino;
+                       ASSERT(mp->m_sb.sb_pquotino == NULLFSINO);
+               } else if ((flags & XFS_QMOPT_GQUOTA) &&
+                            (mp->m_sb.sb_pquotino != NULLFSINO)) {
+                       ino = mp->m_sb.sb_pquotino;
+                       ASSERT(mp->m_sb.sb_gquotino == NULLFSINO);
+               }
+               if (ino != NULLFSINO) {
+                       error = xfs_iget(mp, NULL, ino, 0, 0, ip);
+                       if (error)
+                               return error;
+                       mp->m_sb.sb_gquotino = NULLFSINO;
+                       mp->m_sb.sb_pquotino = NULLFSINO;
+               }
+       }
+
        tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QINOCREATE);
        if ((error = xfs_trans_reserve(tp,
                                      XFS_QM_QINOCREATE_SPACE_RES(mp),
@@ -844,11 +874,14 @@ xfs_qm_qino_alloc(
                return error;
        }
 
-       error = xfs_dir_ialloc(&tp, NULL, S_IFREG, 1, 0, 0, 1, ip, &committed);
-       if (error) {
-               xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES |
-                                XFS_TRANS_ABORT);
-               return error;
+       if (!*ip) {
+               error = xfs_dir_ialloc(&tp, NULL, S_IFREG, 1, 0, 0, 1, ip,
+                                                               &committed);
+               if (error) {
+                       xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES |
+                                        XFS_TRANS_ABORT);
+                       return error;
+               }
        }
 
        /*
@@ -860,21 +893,25 @@ xfs_qm_qino_alloc(
        if (flags & XFS_QMOPT_SBVERSION) {
                ASSERT(!xfs_sb_version_hasquota(&mp->m_sb));
                ASSERT((sbfields & (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
-                                  XFS_SB_GQUOTINO | XFS_SB_QFLAGS)) ==
-                      (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
-                       XFS_SB_GQUOTINO | XFS_SB_QFLAGS));
+                       XFS_SB_GQUOTINO | XFS_SB_PQUOTINO | XFS_SB_QFLAGS)) ==
+                               (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
+                                XFS_SB_GQUOTINO | XFS_SB_PQUOTINO |
+                                XFS_SB_QFLAGS));
 
                xfs_sb_version_addquota(&mp->m_sb);
                mp->m_sb.sb_uquotino = NULLFSINO;
                mp->m_sb.sb_gquotino = NULLFSINO;
+               mp->m_sb.sb_pquotino = NULLFSINO;
 
-               /* qflags will get updated _after_ quotacheck */
-               mp->m_sb.sb_qflags = 0;
+               /* qflags will get updated fully _after_ quotacheck */
+               mp->m_sb.sb_qflags = mp->m_qflags & XFS_ALL_QUOTA_ACCT;
        }
        if (flags & XFS_QMOPT_UQUOTA)
                mp->m_sb.sb_uquotino = (*ip)->i_ino;
-       else
+       else if (flags & XFS_QMOPT_GQUOTA)
                mp->m_sb.sb_gquotino = (*ip)->i_ino;
+       else
+               mp->m_sb.sb_pquotino = (*ip)->i_ino;
        spin_unlock(&mp->m_sb_lock);
        xfs_mod_sb(tp, sbfields);
 
@@ -1484,11 +1521,10 @@ xfs_qm_init_quotainos(
                        if (error)
                                goto error_rele;
                }
-               /* XXX: Use gquotino for now */
                if (XFS_IS_PQUOTA_ON(mp) &&
-                   mp->m_sb.sb_gquotino != NULLFSINO) {
-                       ASSERT(mp->m_sb.sb_gquotino > 0);
-                       error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
+                   mp->m_sb.sb_pquotino != NULLFSINO) {
+                       ASSERT(mp->m_sb.sb_pquotino > 0);
+                       error = xfs_iget(mp, NULL, mp->m_sb.sb_pquotino,
                                             0, 0, &pip);
                        if (error)
                                goto error_rele;
@@ -1496,7 +1532,8 @@ xfs_qm_init_quotainos(
        } else {
                flags |= XFS_QMOPT_SBVERSION;
                sbflags |= (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
-                           XFS_SB_GQUOTINO | XFS_SB_QFLAGS);
+                           XFS_SB_GQUOTINO | XFS_SB_PQUOTINO |
+                           XFS_SB_QFLAGS);
        }
 
        /*
@@ -1524,9 +1561,8 @@ xfs_qm_init_quotainos(
                flags &= ~XFS_QMOPT_SBVERSION;
        }
        if (XFS_IS_PQUOTA_ON(mp) && pip == NULL) {
-               /* XXX: Use XFS_SB_GQUOTINO for now */
                error = xfs_qm_qino_alloc(mp, &pip,
-                                         sbflags | XFS_SB_GQUOTINO,
+                                         sbflags | XFS_SB_PQUOTINO,
                                          flags | XFS_QMOPT_PQUOTA);
                if (error)
                        goto error_rele;
index e4f8b2d6f38ba1960beefe35cbd15b0066f530cf..8d9e4c78e1ab28b83aa90b579a69669a41d94dc9 100644 (file)
@@ -296,8 +296,10 @@ xfs_qm_scall_trunc_qfiles(
 
        if (flags & XFS_DQ_USER)
                error = xfs_qm_scall_trunc_qfile(mp, mp->m_sb.sb_uquotino);
-       if (flags & (XFS_DQ_GROUP|XFS_DQ_PROJ))
+       if (flags & XFS_DQ_GROUP)
                error2 = xfs_qm_scall_trunc_qfile(mp, mp->m_sb.sb_gquotino);
+       if (flags & XFS_DQ_PROJ)
+               error2 = xfs_qm_scall_trunc_qfile(mp, mp->m_sb.sb_pquotino);
 
        return error ? error : error2;
 }
@@ -413,8 +415,10 @@ xfs_qm_scall_getqstat(
        struct xfs_quotainfo    *q = mp->m_quotainfo;
        struct xfs_inode        *uip = NULL;
        struct xfs_inode        *gip = NULL;
+       struct xfs_inode        *pip = NULL;
        bool                    tempuqip = false;
        bool                    tempgqip = false;
+       bool                    temppqip = false;
 
        memset(out, 0, sizeof(fs_quota_stat_t));
 
@@ -424,16 +428,14 @@ xfs_qm_scall_getqstat(
                out->qs_gquota.qfs_ino = NULLFSINO;
                return (0);
        }
+
        out->qs_flags = (__uint16_t) xfs_qm_export_flags(mp->m_qflags &
                                                        (XFS_ALL_QUOTA_ACCT|
                                                         XFS_ALL_QUOTA_ENFD));
-       out->qs_pad = 0;
-       out->qs_uquota.qfs_ino = mp->m_sb.sb_uquotino;
-       out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino;
-
        if (q) {
                uip = q->qi_uquotaip;
                gip = q->qi_gquotaip;
+               pip = q->qi_pquotaip;
        }
        if (!uip && mp->m_sb.sb_uquotino != NULLFSINO) {
                if (xfs_iget(mp, NULL, mp->m_sb.sb_uquotino,
@@ -445,18 +447,41 @@ xfs_qm_scall_getqstat(
                                        0, 0, &gip) == 0)
                        tempgqip = true;
        }
+       /*
+        * Q_XGETQSTAT doesn't have room for both group and project quotas.
+        * So, allow the project quota values to be copied out only if
+        * there is no group quota information available.
+        */
+       if (!gip) {
+               if (!pip && mp->m_sb.sb_pquotino != NULLFSINO) {
+                       if (xfs_iget(mp, NULL, mp->m_sb.sb_pquotino,
+                                               0, 0, &pip) == 0)
+                               temppqip = true;
+               }
+       } else
+               pip = NULL;
        if (uip) {
+               out->qs_uquota.qfs_ino = mp->m_sb.sb_uquotino;
                out->qs_uquota.qfs_nblks = uip->i_d.di_nblocks;
                out->qs_uquota.qfs_nextents = uip->i_d.di_nextents;
                if (tempuqip)
                        IRELE(uip);
        }
+
        if (gip) {
+               out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino;
                out->qs_gquota.qfs_nblks = gip->i_d.di_nblocks;
                out->qs_gquota.qfs_nextents = gip->i_d.di_nextents;
                if (tempgqip)
                        IRELE(gip);
        }
+       if (pip) {
+               out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino;
+               out->qs_gquota.qfs_nblks = pip->i_d.di_nblocks;
+               out->qs_gquota.qfs_nextents = pip->i_d.di_nextents;
+               if (temppqip)
+                       IRELE(pip);
+       }
        if (q) {
                out->qs_incoredqs = q->qi_dquots;
                out->qs_btimelimit = q->qi_btimelimit;
index 78f9e70b80c7da8a64b92d528a9f7aa2ba49401e..a6ff9d6e72f651aa10b97b138b8d42a976d7f8db 100644 (file)
@@ -618,16 +618,23 @@ xfs_sb_has_incompat_log_feature(
        return (sbp->sb_features_log_incompat & feature) != 0;
 }
 
-static inline bool
-xfs_is_quota_inode(struct xfs_sb *sbp, xfs_ino_t ino)
+static inline int xfs_sb_version_has_pquotino(xfs_sb_t *sbp)
 {
-       return (ino == sbp->sb_uquotino || ino == sbp->sb_gquotino);
+       return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5;
 }
 
 /*
  * end of superblock version macros
  */
 
+static inline bool
+xfs_is_quota_inode(struct xfs_sb *sbp, xfs_ino_t ino)
+{
+       return (ino == sbp->sb_uquotino ||
+               ino == sbp->sb_gquotino ||
+               ino == sbp->sb_pquotino);
+}
+
 #define XFS_SB_DADDR           ((xfs_daddr_t)0) /* daddr in filesystem/ag */
 #define        XFS_SB_BLOCK(mp)        XFS_HDR_BLOCK(mp, XFS_SB_DADDR)
 #define XFS_BUF_TO_SBP(bp)     ((xfs_dsb_t *)((bp)->b_addr))
index 1d68ffcdeaa7f555ab77ee05f5c13571c6ee3b4d..19922ebeea2558bda9071339ba3d724e71901d10 100644 (file)
@@ -421,12 +421,6 @@ xfs_parseargs(
        }
 #endif
 
-       if ((mp->m_qflags & (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE)) &&
-           (mp->m_qflags & (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE))) {
-               xfs_warn(mp, "cannot mount with both project and group quota");
-               return EINVAL;
-       }
-
        if ((dsunit && !dswidth) || (!dsunit && dswidth)) {
                xfs_warn(mp, "sunit and swidth must be specified together");
                return EINVAL;
@@ -556,14 +550,13 @@ xfs_showargs(
        else if (mp->m_qflags & XFS_UQUOTA_ACCT)
                seq_puts(m, "," MNTOPT_UQUOTANOENF);
 
-       /* Either project or group quotas can be active, not both */
-
        if (mp->m_qflags & XFS_PQUOTA_ACCT) {
                if (mp->m_qflags & XFS_PQUOTA_ENFD)
                        seq_puts(m, "," MNTOPT_PRJQUOTA);
                else
                        seq_puts(m, "," MNTOPT_PQUOTANOENF);
-       } else if (mp->m_qflags & XFS_GQUOTA_ACCT) {
+       }
+       if (mp->m_qflags & XFS_GQUOTA_ACCT) {
                if (mp->m_qflags & XFS_GQUOTA_ENFD)
                        seq_puts(m, "," MNTOPT_GRPQUOTA);
                else
@@ -870,17 +863,17 @@ xfs_init_mount_workqueues(
                goto out_destroy_unwritten;
 
        mp->m_reclaim_workqueue = alloc_workqueue("xfs-reclaim/%s",
-                       WQ_NON_REENTRANT, 0, mp->m_fsname);
+                       0, 0, mp->m_fsname);
        if (!mp->m_reclaim_workqueue)
                goto out_destroy_cil;
 
        mp->m_log_workqueue = alloc_workqueue("xfs-log/%s",
-                       WQ_NON_REENTRANT, 0, mp->m_fsname);
+                       0, 0, mp->m_fsname);
        if (!mp->m_log_workqueue)
                goto out_destroy_reclaim;
 
        mp->m_eofblocks_workqueue = alloc_workqueue("xfs-eofblocks/%s",
-                       WQ_NON_REENTRANT, 0, mp->m_fsname);
+                       0, 0, mp->m_fsname);
        if (!mp->m_eofblocks_workqueue)
                goto out_destroy_log;
 
@@ -1396,6 +1389,14 @@ xfs_finish_flags(
                return XFS_ERROR(EROFS);
        }
 
+       if ((mp->m_qflags & (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE)) &&
+           (mp->m_qflags & (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE)) &&
+           !xfs_sb_version_has_pquotino(&mp->m_sb)) {
+               xfs_warn(mp,
+                 "Super block does not support project and group quota together");
+               return XFS_ERROR(EINVAL);
+       }
+
        return 0;
 }
 
index 56e6b68c8d2fcb36fae154ebe6bb687f9e74760d..79d9c6360260dca59a5e02fd581acd97df13535a 100644 (file)
@@ -56,6 +56,16 @@ acpi_evaluate_hotplug_ost(acpi_handle handle, u32 source_event,
 
 acpi_status
 acpi_get_physical_device_location(acpi_handle handle, struct acpi_pld_info **pld);
+
+bool acpi_has_method(acpi_handle handle, char *name);
+acpi_status acpi_execute_simple_method(acpi_handle handle, char *method,
+                                      u64 arg);
+acpi_status acpi_evaluate_ej0(acpi_handle handle);
+acpi_status acpi_evaluate_lck(acpi_handle handle, int lock);
+bool acpi_ata_match(acpi_handle handle);
+bool acpi_bay_match(acpi_handle handle);
+bool acpi_dock_match(acpi_handle handle);
+
 #ifdef CONFIG_ACPI
 
 #include <linux/proc_fs.h>
@@ -356,14 +366,11 @@ extern int acpi_notifier_call_chain(struct acpi_device *, u32, u32);
 extern int register_acpi_notifier(struct notifier_block *);
 extern int unregister_acpi_notifier(struct notifier_block *);
 
-extern int register_acpi_bus_notifier(struct notifier_block *nb);
-extern void unregister_acpi_bus_notifier(struct notifier_block *nb);
 /*
  * External Functions
  */
 
 int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device);
-void acpi_bus_data_handler(acpi_handle handle, void *context);
 acpi_status acpi_bus_get_status_handle(acpi_handle handle,
                                       unsigned long long *sta);
 int acpi_bus_get_status(struct acpi_device *device);
@@ -383,15 +390,6 @@ bool acpi_bus_can_wakeup(acpi_handle handle);
 static inline bool acpi_bus_can_wakeup(acpi_handle handle) { return false; }
 #endif
 
-#ifdef CONFIG_ACPI_PROC_EVENT
-int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data);
-int acpi_bus_generate_proc_event4(const char *class, const char *bid, u8 type, int data);
-int acpi_bus_receive_event(struct acpi_bus_event *event);
-#else
-static inline int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data)
-       { return 0; }
-#endif
-
 void acpi_scan_lock_acquire(void);
 void acpi_scan_lock_release(void);
 int acpi_scan_add_handler(struct acpi_scan_handler *handler);
@@ -478,7 +476,8 @@ static inline int acpi_pm_device_sleep_state(struct device *d, int *p, int m)
        if (p)
                *p = ACPI_STATE_D0;
 
-       return (m >= ACPI_STATE_D0 && m <= ACPI_STATE_D3) ? m : ACPI_STATE_D0;
+       return (m >= ACPI_STATE_D0 && m <= ACPI_STATE_D3_COLD) ?
+               m : ACPI_STATE_D0;
 }
 static inline void acpi_dev_pm_add_dependent(acpi_handle handle,
                                             struct device *depdev) {}
index b420939f5eb5608f2335e0b4ae4087176911022b..1cedfcb1bd8878ff7466e4ab6d9285e3a811a90a 100644 (file)
@@ -113,14 +113,13 @@ void pci_acpi_crs_quirks(void);
                                   Dock Station
   -------------------------------------------------------------------------- */
 struct acpi_dock_ops {
+       acpi_notify_handler fixup;
        acpi_notify_handler handler;
        acpi_notify_handler uevent;
 };
 
-#if defined(CONFIG_ACPI_DOCK) || defined(CONFIG_ACPI_DOCK_MODULE)
+#ifdef CONFIG_ACPI_DOCK
 extern int is_dock_device(acpi_handle handle);
-extern int register_dock_notifier(struct notifier_block *nb);
-extern void unregister_dock_notifier(struct notifier_block *nb);
 extern int register_hotplug_dock_device(acpi_handle handle,
                                        const struct acpi_dock_ops *ops,
                                        void *context,
@@ -132,13 +131,6 @@ static inline int is_dock_device(acpi_handle handle)
 {
        return 0;
 }
-static inline int register_dock_notifier(struct notifier_block *nb)
-{
-       return -ENODEV;
-}
-static inline void unregister_dock_notifier(struct notifier_block *nb)
-{
-}
 static inline int register_hotplug_dock_device(acpi_handle handle,
                                               const struct acpi_dock_ops *ops,
                                               void *context,
@@ -150,6 +142,6 @@ static inline int register_hotplug_dock_device(acpi_handle handle,
 static inline void unregister_hotplug_dock_device(acpi_handle handle)
 {
 }
-#endif
+#endif /* CONFIG_ACPI_DOCK */
 
 #endif /*__ACPI_DRIVERS_H__*/
index 22d497ee6ef95032977a5b4d533f5343d29c4fa5..0dd03f226a68169af82e237ff50e983dcdc5c895 100644 (file)
@@ -46,7 +46,7 @@
 
 /* Current ACPICA subsystem version in YYYYMMDD format */
 
-#define ACPI_CA_VERSION                 0x20130517
+#define ACPI_CA_VERSION                 0x20130626
 
 #include <acpi/acconfig.h>
 #include <acpi/actypes.h>
@@ -147,6 +147,8 @@ acpi_status acpi_install_interface(acpi_string interface_name);
 
 acpi_status acpi_remove_interface(acpi_string interface_name);
 
+acpi_status acpi_update_interfaces(u8 action);
+
 u32
 acpi_check_address_range(acpi_adr_space_type space_id,
                         acpi_physical_address address,
index 22b03c9286e94d0d4819d5e6610f96a850b4f713..eae55fb749050681998e6dd6223c15cf75587e9f 100644 (file)
@@ -668,13 +668,6 @@ typedef u32 acpi_event_status;
 #define ACPI_EVENT_FLAG_SET             (acpi_event_status) 0x04
 #define ACPI_EVENT_FLAG_HANDLE         (acpi_event_status) 0x08
 
-/*
- * General Purpose Events (GPE)
- */
-#define ACPI_GPE_INVALID                0xFF
-#define ACPI_GPE_MAX                    0xFF
-#define ACPI_NUM_GPE                    256
-
 /* Actions for acpi_set_gpe, acpi_gpe_wakeup, acpi_hw_low_set_gpe */
 
 #define ACPI_GPE_ENABLE                 0
@@ -1159,4 +1152,18 @@ struct acpi_memory_list {
 #define ACPI_OSI_WIN_7                  0x0B
 #define ACPI_OSI_WIN_8                  0x0C
 
+/* _OSI update actions */
+
+#define ACPI_VENDOR_STRINGS                 0x01
+#define ACPI_FEATURE_STRINGS                0x02
+#define ACPI_ENABLE_INTERFACES              0x00
+#define ACPI_DISABLE_INTERFACES             0x04
+
+#define ACPI_DISABLE_ALL_VENDOR_STRINGS     (ACPI_DISABLE_INTERFACES | ACPI_VENDOR_STRINGS)
+#define ACPI_DISABLE_ALL_FEATURE_STRINGS    (ACPI_DISABLE_INTERFACES | ACPI_FEATURE_STRINGS)
+#define ACPI_DISABLE_ALL_STRINGS            (ACPI_DISABLE_INTERFACES | ACPI_VENDOR_STRINGS | ACPI_FEATURE_STRINGS)
+#define ACPI_ENABLE_ALL_VENDOR_STRINGS      (ACPI_ENABLE_INTERFACES | ACPI_VENDOR_STRINGS)
+#define ACPI_ENABLE_ALL_FEATURE_STRINGS     (ACPI_ENABLE_INTERFACES | ACPI_FEATURE_STRINGS)
+#define ACPI_ENABLE_ALL_STRINGS             (ACPI_ENABLE_INTERFACES | ACPI_VENDOR_STRINGS | ACPI_FEATURE_STRINGS)
+
 #endif                         /* __ACTYPES_H__ */
index 12083dc862a9a6e03f12184a1fd1ff11d4e8ed04..4b518e05d293c80095868215728fa8067171581e 100644 (file)
@@ -71,6 +71,7 @@
 #include <asm/pgalloc.h>
 #include <drm/drm.h>
 #include <drm/drm_sarea.h>
+#include <drm/drm_vma_manager.h>
 
 #include <linux/idr.h>
 
@@ -587,7 +588,6 @@ struct drm_map_list {
        struct drm_local_map *map;      /**< mapping */
        uint64_t user_token;
        struct drm_master *master;
-       struct drm_mm_node *file_offset_node;   /**< fake offset */
 };
 
 /**
@@ -622,8 +622,7 @@ struct drm_ati_pcigart_info {
  * GEM specific mm private for tracking GEM objects
  */
 struct drm_gem_mm {
-       struct drm_mm offset_manager;   /**< Offset mgmt for buffer objects */
-       struct drm_open_hash offset_hash; /**< User token hash table for maps */
+       struct drm_vma_offset_manager vma_manager;
 };
 
 /**
@@ -644,7 +643,7 @@ struct drm_gem_object {
        struct file *filp;
 
        /* Mapping info for this object */
-       struct drm_map_list map_list;
+       struct drm_vma_offset_node vma_node;
 
        /**
         * Size of the object, in bytes.  Immutable over the object's
@@ -1131,12 +1130,7 @@ struct drm_device {
        /*@{ */
        int irq_enabled;                /**< True if irq handler is enabled */
        __volatile__ long context_flag; /**< Context swapping flag */
-       __volatile__ long interrupt_flag; /**< Interruption handler flag */
-       __volatile__ long dma_flag;     /**< DMA dispatch flag */
-       wait_queue_head_t context_wait; /**< Processes waiting on ctx switch */
-       int last_checked;               /**< Last context checked for DMA */
        int last_context;               /**< Last current context */
-       unsigned long last_switch;      /**< jiffies at last context switch */
        /*@} */
 
        struct work_struct work;
@@ -1174,12 +1168,8 @@ struct drm_device {
        spinlock_t event_lock;
 
        /*@} */
-       cycles_t ctx_start;
-       cycles_t lck_start;
 
        struct fasync_struct *buf_async;/**< Processes waiting for SIGIO */
-       wait_queue_head_t buf_readers;  /**< Processes waiting to read */
-       wait_queue_head_t buf_writers;  /**< Processes waiting to ctx switch */
 
        struct drm_agp_head *agp;       /**< AGP data */
 
@@ -1335,8 +1325,6 @@ extern int drm_resctx(struct drm_device *dev, void *data,
                      struct drm_file *file_priv);
 extern int drm_addctx(struct drm_device *dev, void *data,
                      struct drm_file *file_priv);
-extern int drm_modctx(struct drm_device *dev, void *data,
-                     struct drm_file *file_priv);
 extern int drm_getctx(struct drm_device *dev, void *data,
                      struct drm_file *file_priv);
 extern int drm_switchctx(struct drm_device *dev, void *data,
@@ -1405,7 +1393,6 @@ extern int drm_freebufs(struct drm_device *dev, void *data,
                        struct drm_file *file_priv);
 extern int drm_mapbufs(struct drm_device *dev, void *data,
                       struct drm_file *file_priv);
-extern int drm_order(unsigned long size);
 
                                /* DMA support (drm_dma.h) */
 extern int drm_dma_setup(struct drm_device *dev);
@@ -1577,9 +1564,8 @@ extern int drm_vma_info(struct seq_file *m, void *data);
 
                                /* Scatter Gather Support (drm_scatter.h) */
 extern void drm_sg_cleanup(struct drm_sg_mem * entry);
-extern int drm_sg_alloc_ioctl(struct drm_device *dev, void *data,
+extern int drm_sg_alloc(struct drm_device *dev, void *data,
                        struct drm_file *file_priv);
-extern int drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather * request);
 extern int drm_sg_free(struct drm_device *dev, void *data,
                       struct drm_file *file_priv);
 
@@ -1613,8 +1599,8 @@ struct drm_gem_object *drm_gem_object_alloc(struct drm_device *dev,
                                            size_t size);
 int drm_gem_object_init(struct drm_device *dev,
                        struct drm_gem_object *obj, size_t size);
-int drm_gem_private_object_init(struct drm_device *dev,
-                       struct drm_gem_object *obj, size_t size);
+void drm_gem_private_object_init(struct drm_device *dev,
+                                struct drm_gem_object *obj, size_t size);
 void drm_gem_object_handle_free(struct drm_gem_object *obj);
 void drm_gem_vm_open(struct vm_area_struct *vma);
 void drm_gem_vm_close(struct vm_area_struct *vma);
@@ -1660,24 +1646,6 @@ drm_gem_object_handle_reference(struct drm_gem_object *obj)
        atomic_inc(&obj->handle_count);
 }
 
-static inline void
-drm_gem_object_handle_unreference(struct drm_gem_object *obj)
-{
-       if (obj == NULL)
-               return;
-
-       if (atomic_read(&obj->handle_count) == 0)
-               return;
-       /*
-        * Must bump handle count first as this may be the last
-        * ref, in which case the object would disappear before we
-        * checked for a name
-        */
-       if (atomic_dec_and_test(&obj->handle_count))
-               drm_gem_object_handle_free(obj);
-       drm_gem_object_unreference(obj);
-}
-
 static inline void
 drm_gem_object_handle_unreference_unlocked(struct drm_gem_object *obj)
 {
index e8e1417af3d9c933073d2d36270ee3a15ffb5705..ae8dbfb1207c71a6cbe44dc166180988083c00e6 100644 (file)
@@ -342,13 +342,42 @@ u8 drm_dp_get_adjust_request_voltage(u8 link_status[DP_LINK_STATUS_SIZE],
 u8 drm_dp_get_adjust_request_pre_emphasis(u8 link_status[DP_LINK_STATUS_SIZE],
                                          int lane);
 
-#define DP_RECEIVER_CAP_SIZE   0xf
+#define DP_RECEIVER_CAP_SIZE           0xf
+#define EDP_PSR_RECEIVER_CAP_SIZE      2
+
 void drm_dp_link_train_clock_recovery_delay(u8 dpcd[DP_RECEIVER_CAP_SIZE]);
 void drm_dp_link_train_channel_eq_delay(u8 dpcd[DP_RECEIVER_CAP_SIZE]);
 
 u8 drm_dp_link_rate_to_bw_code(int link_rate);
 int drm_dp_bw_code_to_link_rate(u8 link_bw);
 
+struct edp_sdp_header {
+       u8 HB0; /* Secondary Data Packet ID */
+       u8 HB1; /* Secondary Data Packet Type */
+       u8 HB2; /* 7:5 reserved, 4:0 revision number */
+       u8 HB3; /* 7:5 reserved, 4:0 number of valid data bytes */
+} __packed;
+
+#define EDP_SDP_HEADER_REVISION_MASK           0x1F
+#define EDP_SDP_HEADER_VALID_PAYLOAD_BYTES     0x1F
+
+struct edp_vsc_psr {
+       struct edp_sdp_header sdp_header;
+       u8 DB0; /* Stereo Interface */
+       u8 DB1; /* 0 - PSR State; 1 - Update RFB; 2 - CRC Valid */
+       u8 DB2; /* CRC value bits 7:0 of the R or Cr component */
+       u8 DB3; /* CRC value bits 15:8 of the R or Cr component */
+       u8 DB4; /* CRC value bits 7:0 of the G or Y component */
+       u8 DB5; /* CRC value bits 15:8 of the G or Y component */
+       u8 DB6; /* CRC value bits 7:0 of the B or Cb component */
+       u8 DB7; /* CRC value bits 15:8 of the B or Cb component */
+       u8 DB8_31[24]; /* Reserved */
+} __packed;
+
+#define EDP_VSC_PSR_STATE_ACTIVE       (1<<0)
+#define EDP_VSC_PSR_UPDATE_RFB         (1<<1)
+#define EDP_VSC_PSR_CRC_VALUES_VALID   (1<<2)
+
 static inline int
 drm_dp_max_link_rate(u8 dpcd[DP_RECEIVER_CAP_SIZE])
 {
index f5e1168c76473d3c1180cbcac654eac67ee2373f..d639049a613dfdb264650f8ee938836e6ed28e10 100644 (file)
@@ -84,12 +84,12 @@ static inline int drm_fixp2int(int64_t a)
        return ((s64)a) >> DRM_FIXED_POINT;
 }
 
-static inline s64 drm_fixp_msbset(int64_t a)
+static inline unsigned drm_fixp_msbset(int64_t a)
 {
        unsigned shift, sign = (a >> 63) & 1;
 
        for (shift = 62; shift > 0; --shift)
-               if ((a >> shift) != sign)
+               if (((a >> shift) & 1) != sign)
                        return shift;
 
        return 0;
@@ -100,9 +100,9 @@ static inline s64 drm_fixp_mul(s64 a, s64 b)
        unsigned shift = drm_fixp_msbset(a) + drm_fixp_msbset(b);
        s64 result;
 
-       if (shift > 63) {
-               shift = shift - 63;
-               a >>= shift >> 1;
+       if (shift > 61) {
+               shift = shift - 61;
+               a >>= (shift >> 1) + (shift & 1);
                b >>= shift >> 1;
        } else
                shift = 0;
@@ -120,7 +120,7 @@ static inline s64 drm_fixp_mul(s64 a, s64 b)
 
 static inline s64 drm_fixp_div(s64 a, s64 b)
 {
-       unsigned shift = 63 - drm_fixp_msbset(a);
+       unsigned shift = 62 - drm_fixp_msbset(a);
        s64 result;
 
        a <<= shift;
@@ -154,7 +154,7 @@ static inline s64 drm_fixp_exp(s64 x)
        }
 
        if (x < 0)
-               sum = drm_fixp_div(1, sum);
+               sum = drm_fixp_div(DRM_FIXED_ONE, sum);
 
        return sum;
 }
index 4d06edb56d5fbb74480d0ffc4b24297870f8149e..98cb50ea6acb8dbce7e6135151728811c7be35d1 100644 (file)
 /*
  * Generic range manager structs
  */
+#include <linux/bug.h>
+#include <linux/kernel.h>
 #include <linux/list.h>
+#include <linux/spinlock.h>
 #ifdef CONFIG_DEBUG_FS
 #include <linux/seq_file.h>
 #endif
@@ -138,10 +141,7 @@ static inline unsigned long drm_mm_hole_node_end(struct drm_mm_node *hole_node)
 /*
  * Basic range manager support (drm_mm.c)
  */
-extern struct drm_mm_node *drm_mm_create_block(struct drm_mm *mm,
-                                              unsigned long start,
-                                              unsigned long size,
-                                              bool atomic);
+extern int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node);
 extern struct drm_mm_node *drm_mm_get_block_generic(struct drm_mm_node *node,
                                                    unsigned long size,
                                                    unsigned alignment,
@@ -155,6 +155,7 @@ extern struct drm_mm_node *drm_mm_get_block_range_generic(
                                                unsigned long start,
                                                unsigned long end,
                                                int atomic);
+
 static inline struct drm_mm_node *drm_mm_get_block(struct drm_mm_node *parent,
                                                   unsigned long size,
                                                   unsigned alignment)
diff --git a/include/drm/drm_vma_manager.h b/include/drm/drm_vma_manager.h
new file mode 100644 (file)
index 0000000..22eedac
--- /dev/null
@@ -0,0 +1,224 @@
+#ifndef __DRM_VMA_MANAGER_H__
+#define __DRM_VMA_MANAGER_H__
+
+/*
+ * Copyright (c) 2013 David Herrmann <dh.herrmann@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice 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.
+ */
+
+#include <drm/drm_mm.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/rbtree.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+struct drm_vma_offset_node {
+       struct drm_mm_node vm_node;
+       struct rb_node vm_rb;
+};
+
+struct drm_vma_offset_manager {
+       rwlock_t vm_lock;
+       struct rb_root vm_addr_space_rb;
+       struct drm_mm vm_addr_space_mm;
+};
+
+void drm_vma_offset_manager_init(struct drm_vma_offset_manager *mgr,
+                                unsigned long page_offset, unsigned long size);
+void drm_vma_offset_manager_destroy(struct drm_vma_offset_manager *mgr);
+
+struct drm_vma_offset_node *drm_vma_offset_lookup(struct drm_vma_offset_manager *mgr,
+                                                 unsigned long start,
+                                                 unsigned long pages);
+struct drm_vma_offset_node *drm_vma_offset_lookup_locked(struct drm_vma_offset_manager *mgr,
+                                                          unsigned long start,
+                                                          unsigned long pages);
+int drm_vma_offset_add(struct drm_vma_offset_manager *mgr,
+                      struct drm_vma_offset_node *node, unsigned long pages);
+void drm_vma_offset_remove(struct drm_vma_offset_manager *mgr,
+                          struct drm_vma_offset_node *node);
+
+/**
+ * drm_vma_offset_exact_lookup() - Look up node by exact address
+ * @mgr: Manager object
+ * @start: Start address (page-based, not byte-based)
+ * @pages: Size of object (page-based)
+ *
+ * Same as drm_vma_offset_lookup() but does not allow any offset into the node.
+ * It only returns the exact object with the given start address.
+ *
+ * RETURNS:
+ * Node at exact start address @start.
+ */
+static inline struct drm_vma_offset_node *
+drm_vma_offset_exact_lookup(struct drm_vma_offset_manager *mgr,
+                           unsigned long start,
+                           unsigned long pages)
+{
+       struct drm_vma_offset_node *node;
+
+       node = drm_vma_offset_lookup(mgr, start, pages);
+       return (node && node->vm_node.start == start) ? node : NULL;
+}
+
+/**
+ * drm_vma_offset_lock_lookup() - Lock lookup for extended private use
+ * @mgr: Manager object
+ *
+ * Lock VMA manager for extended lookups. Only *_locked() VMA function calls
+ * are allowed while holding this lock. All other contexts are blocked from VMA
+ * until the lock is released via drm_vma_offset_unlock_lookup().
+ *
+ * Use this if you need to take a reference to the objects returned by
+ * drm_vma_offset_lookup_locked() before releasing this lock again.
+ *
+ * This lock must not be used for anything else than extended lookups. You must
+ * not call any other VMA helpers while holding this lock.
+ *
+ * Note: You're in atomic-context while holding this lock!
+ *
+ * Example:
+ *   drm_vma_offset_lock_lookup(mgr);
+ *   node = drm_vma_offset_lookup_locked(mgr);
+ *   if (node)
+ *       kref_get_unless_zero(container_of(node, sth, entr));
+ *   drm_vma_offset_unlock_lookup(mgr);
+ */
+static inline void drm_vma_offset_lock_lookup(struct drm_vma_offset_manager *mgr)
+{
+       read_lock(&mgr->vm_lock);
+}
+
+/**
+ * drm_vma_offset_unlock_lookup() - Unlock lookup for extended private use
+ * @mgr: Manager object
+ *
+ * Release lookup-lock. See drm_vma_offset_lock_lookup() for more information.
+ */
+static inline void drm_vma_offset_unlock_lookup(struct drm_vma_offset_manager *mgr)
+{
+       read_unlock(&mgr->vm_lock);
+}
+
+/**
+ * drm_vma_node_reset() - Initialize or reset node object
+ * @node: Node to initialize or reset
+ *
+ * Reset a node to its initial state. This must be called if @node isn't
+ * already cleared (eg., via kzalloc) before using it with any VMA offset
+ * manager.
+ *
+ * This must not be called on an already allocated node, or you will leak
+ * memory.
+ */
+static inline void drm_vma_node_reset(struct drm_vma_offset_node *node)
+{
+       memset(node, 0, sizeof(*node));
+}
+
+/**
+ * drm_vma_node_start() - Return start address for page-based addressing
+ * @node: Node to inspect
+ *
+ * Return the start address of the given node. This can be used as offset into
+ * the linear VM space that is provided by the VMA offset manager. Note that
+ * this can only be used for page-based addressing. If you need a proper offset
+ * for user-space mappings, you must apply "<< PAGE_SHIFT" or use the
+ * drm_vma_node_offset_addr() helper instead.
+ *
+ * RETURNS:
+ * Start address of @node for page-based addressing. 0 if the node does not
+ * have an offset allocated.
+ */
+static inline unsigned long drm_vma_node_start(struct drm_vma_offset_node *node)
+{
+       return node->vm_node.start;
+}
+
+/**
+ * drm_vma_node_size() - Return size (page-based)
+ * @node: Node to inspect
+ *
+ * Return the size as number of pages for the given node. This is the same size
+ * that was passed to drm_vma_offset_add(). If no offset is allocated for the
+ * node, this is 0.
+ *
+ * RETURNS:
+ * Size of @node as number of pages. 0 if the node does not have an offset
+ * allocated.
+ */
+static inline unsigned long drm_vma_node_size(struct drm_vma_offset_node *node)
+{
+       return node->vm_node.size;
+}
+
+/**
+ * drm_vma_node_has_offset() - Check whether node is added to offset manager
+ * @node: Node to be checked
+ *
+ * RETURNS:
+ * true iff the node was previously allocated an offset and added to
+ * an vma offset manager.
+ */
+static inline bool drm_vma_node_has_offset(struct drm_vma_offset_node *node)
+{
+       return drm_mm_node_allocated(&node->vm_node);
+}
+
+/**
+ * drm_vma_node_offset_addr() - Return sanitized offset for user-space mmaps
+ * @node: Linked offset node
+ *
+ * Same as drm_vma_node_start() but returns the address as a valid offset that
+ * can be used for user-space mappings during mmap().
+ * This must not be called on unlinked nodes.
+ *
+ * RETURNS:
+ * Offset of @node for byte-based addressing. 0 if the node does not have an
+ * object allocated.
+ */
+static inline __u64 drm_vma_node_offset_addr(struct drm_vma_offset_node *node)
+{
+       return ((__u64)node->vm_node.start) << PAGE_SHIFT;
+}
+
+/**
+ * drm_vma_node_unmap() - Unmap offset node
+ * @node: Offset node
+ * @file_mapping: Address space to unmap @node from
+ *
+ * Unmap all userspace mappings for a given offset node. The mappings must be
+ * associated with the @file_mapping address-space. If no offset exists or
+ * the address-space is invalid, nothing is done.
+ *
+ * This call is unlocked. The caller must guarantee that drm_vma_offset_remove()
+ * is not called on this node concurrently.
+ */
+static inline void drm_vma_node_unmap(struct drm_vma_offset_node *node,
+                                     struct address_space *file_mapping)
+{
+       if (file_mapping && drm_vma_node_has_offset(node))
+               unmap_mapping_range(file_mapping,
+                                   drm_vma_node_offset_addr(node),
+                                   drm_vma_node_size(node) << PAGE_SHIFT, 1);
+}
+
+#endif /* __DRM_VMA_MANAGER_H__ */
index 8a6aa56ece52a53cad3734c756a6dbc19a5d7ac1..751eaffbf0d5fe5ef758254ceba1fe706af4423d 100644 (file)
 #define _TTM_BO_API_H_
 
 #include <drm/drm_hashtab.h>
+#include <drm/drm_vma_manager.h>
 #include <linux/kref.h>
 #include <linux/list.h>
 #include <linux/wait.h>
 #include <linux/mutex.h>
 #include <linux/mm.h>
-#include <linux/rbtree.h>
 #include <linux/bitmap.h>
 #include <linux/reservation.h>
 
@@ -145,7 +145,6 @@ struct ttm_tt;
  * @type: The bo type.
  * @destroy: Destruction function. If NULL, kfree is used.
  * @num_pages: Actual number of pages.
- * @addr_space_offset: Address space offset.
  * @acc_size: Accounted size for this object.
  * @kref: Reference count of this buffer object. When this refcount reaches
  * zero, the object is put on the delayed delete list.
@@ -166,8 +165,7 @@ struct ttm_tt;
  * @swap: List head for swap LRU list.
  * @sync_obj: Pointer to a synchronization object.
  * @priv_flags: Flags describing buffer object internal state.
- * @vm_rb: Rb node for the vm rb tree.
- * @vm_node: Address space manager node.
+ * @vma_node: Address space manager node.
  * @offset: The current GPU offset, which can have different meanings
  * depending on the memory type. For SYSTEM type memory, it should be 0.
  * @cur_placement: Hint of current placement.
@@ -194,7 +192,6 @@ struct ttm_buffer_object {
        enum ttm_bo_type type;
        void (*destroy) (struct ttm_buffer_object *);
        unsigned long num_pages;
-       uint64_t addr_space_offset;
        size_t acc_size;
 
        /**
@@ -238,13 +235,7 @@ struct ttm_buffer_object {
        void *sync_obj;
        unsigned long priv_flags;
 
-       /**
-        * Members protected by the bdev::vm_lock
-        */
-
-       struct rb_node vm_rb;
-       struct drm_mm_node *vm_node;
-
+       struct drm_vma_offset_node vma_node;
 
        /**
         * Special members that are protected by the reserve lock
index 984fc2d571a145860d6cfd2962d7ca20da7d0ee5..8639c85d61c400f4694e99ca7e1282df23f5ef66 100644 (file)
@@ -36,6 +36,7 @@
 #include <ttm/ttm_placement.h>
 #include <drm/drm_mm.h>
 #include <drm/drm_global.h>
+#include <drm/drm_vma_manager.h>
 #include <linux/workqueue.h>
 #include <linux/fs.h>
 #include <linux/spinlock.h>
@@ -519,7 +520,7 @@ struct ttm_bo_global {
  * @man: An array of mem_type_managers.
  * @fence_lock: Protects the synchronizing members on *all* bos belonging
  * to this device.
- * @addr_space_mm: Range manager for the device address space.
+ * @vma_manager: Address space manager
  * lru_lock: Spinlock that protects the buffer+device lru lists and
  * ddestroy lists.
  * @val_seq: Current validation sequence.
@@ -537,14 +538,13 @@ struct ttm_bo_device {
        struct list_head device_list;
        struct ttm_bo_global *glob;
        struct ttm_bo_driver *driver;
-       rwlock_t vm_lock;
        struct ttm_mem_type_manager man[TTM_NUM_MEM_TYPES];
        spinlock_t fence_lock;
+
        /*
-        * Protected by the vm lock.
+        * Protected by internal locks.
         */
-       struct rb_root addr_space_rb;
-       struct drm_mm addr_space_mm;
+       struct drm_vma_offset_manager vma_manager;
 
        /*
         * Protected by the global:lru lock.
index 353ba256f3681e4f6ddd8b18b9feba61b1d98cec..a5db4aeefa3642107e28b431c21a89c195569993 100644 (file)
@@ -481,6 +481,13 @@ void acpi_os_set_prepare_sleep(int (*func)(u8 sleep_state,
 
 acpi_status acpi_os_prepare_sleep(u8 sleep_state,
                                  u32 pm1a_control, u32 pm1b_control);
+
+void acpi_os_set_prepare_extended_sleep(int (*func)(u8 sleep_state,
+                                       u32 val_a,  u32 val_b));
+
+acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state,
+                                          u32 val_a, u32 val_b);
+
 #ifdef CONFIG_X86
 void arch_reserve_mem_area(acpi_physical_address addr, size_t size);
 #else
index ee0bd95240553576bf51672015c756aa0dea3b94..f63fb1afc5ccc8a6146dedeae449e4075d4f7653 100644 (file)
@@ -446,22 +446,6 @@ enum {
        SERR_TRANS_ST_ERROR     = (1 << 24), /* Transport state trans. error */
        SERR_UNRECOG_FIS        = (1 << 25), /* Unrecognized FIS */
        SERR_DEV_XCHG           = (1 << 26), /* device exchanged */
-
-       /* struct ata_taskfile flags */
-       ATA_TFLAG_LBA48         = (1 << 0), /* enable 48-bit LBA and "HOB" */
-       ATA_TFLAG_ISADDR        = (1 << 1), /* enable r/w to nsect/lba regs */
-       ATA_TFLAG_DEVICE        = (1 << 2), /* enable r/w to device reg */
-       ATA_TFLAG_WRITE         = (1 << 3), /* data dir: host->dev==1 (write) */
-       ATA_TFLAG_LBA           = (1 << 4), /* enable LBA */
-       ATA_TFLAG_FUA           = (1 << 5), /* enable FUA */
-       ATA_TFLAG_POLLING       = (1 << 6), /* set nIEN to 1 and use polling */
-
-       /* protocol flags */
-       ATA_PROT_FLAG_PIO       = (1 << 0), /* is PIO */
-       ATA_PROT_FLAG_DMA       = (1 << 1), /* is DMA */
-       ATA_PROT_FLAG_DATA      = ATA_PROT_FLAG_PIO | ATA_PROT_FLAG_DMA,
-       ATA_PROT_FLAG_NCQ       = (1 << 2), /* is NCQ */
-       ATA_PROT_FLAG_ATAPI     = (1 << 3), /* is ATAPI */
 };
 
 enum ata_tf_protocols {
@@ -488,83 +472,6 @@ struct ata_bmdma_prd {
        __le32                  flags_len;
 };
 
-struct ata_taskfile {
-       unsigned long           flags;          /* ATA_TFLAG_xxx */
-       u8                      protocol;       /* ATA_PROT_xxx */
-
-       u8                      ctl;            /* control reg */
-
-       u8                      hob_feature;    /* additional data */
-       u8                      hob_nsect;      /* to support LBA48 */
-       u8                      hob_lbal;
-       u8                      hob_lbam;
-       u8                      hob_lbah;
-
-       u8                      feature;
-       u8                      nsect;
-       u8                      lbal;
-       u8                      lbam;
-       u8                      lbah;
-
-       u8                      device;
-
-       u8                      command;        /* IO operation */
-};
-
-/*
- * protocol tests
- */
-static inline unsigned int ata_prot_flags(u8 prot)
-{
-       switch (prot) {
-       case ATA_PROT_NODATA:
-               return 0;
-       case ATA_PROT_PIO:
-               return ATA_PROT_FLAG_PIO;
-       case ATA_PROT_DMA:
-               return ATA_PROT_FLAG_DMA;
-       case ATA_PROT_NCQ:
-               return ATA_PROT_FLAG_DMA | ATA_PROT_FLAG_NCQ;
-       case ATAPI_PROT_NODATA:
-               return ATA_PROT_FLAG_ATAPI;
-       case ATAPI_PROT_PIO:
-               return ATA_PROT_FLAG_ATAPI | ATA_PROT_FLAG_PIO;
-       case ATAPI_PROT_DMA:
-               return ATA_PROT_FLAG_ATAPI | ATA_PROT_FLAG_DMA;
-       }
-       return 0;
-}
-
-static inline int ata_is_atapi(u8 prot)
-{
-       return ata_prot_flags(prot) & ATA_PROT_FLAG_ATAPI;
-}
-
-static inline int ata_is_nodata(u8 prot)
-{
-       return !(ata_prot_flags(prot) & ATA_PROT_FLAG_DATA);
-}
-
-static inline int ata_is_pio(u8 prot)
-{
-       return ata_prot_flags(prot) & ATA_PROT_FLAG_PIO;
-}
-
-static inline int ata_is_dma(u8 prot)
-{
-       return ata_prot_flags(prot) & ATA_PROT_FLAG_DMA;
-}
-
-static inline int ata_is_ncq(u8 prot)
-{
-       return ata_prot_flags(prot) & ATA_PROT_FLAG_NCQ;
-}
-
-static inline int ata_is_data(u8 prot)
-{
-       return ata_prot_flags(prot) & ATA_PROT_FLAG_DATA;
-}
-
 /*
  * id tests
  */
@@ -1060,15 +967,6 @@ static inline unsigned ata_set_lba_range_entries(void *_buffer,
        return used_bytes;
 }
 
-static inline int is_multi_taskfile(struct ata_taskfile *tf)
-{
-       return (tf->command == ATA_CMD_READ_MULTI) ||
-              (tf->command == ATA_CMD_WRITE_MULTI) ||
-              (tf->command == ATA_CMD_READ_MULTI_EXT) ||
-              (tf->command == ATA_CMD_WRITE_MULTI_EXT) ||
-              (tf->command == ATA_CMD_WRITE_MULTI_FUA_EXT);
-}
-
 static inline bool ata_ok(u8 status)
 {
        return ((status & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ | ATA_ERR))
index deb0ae58b99bb3724bee4376b0a376b563c29cff..66a0e5384edd6090ae3793082c8a4f56fb6ea74d 100644 (file)
@@ -11,7 +11,7 @@ struct atmel_ssc_platform_data {
 
 struct ssc_device {
        struct list_head        list;
-       resource_size_t         phybase;
+       dma_addr_t              phybase;
        void __iomem            *regs;
        struct platform_device  *pdev;
        struct atmel_ssc_platform_data *pdata;
index 622fc505d3e1cdfcfe8b2abc8f22800570c6f304..4d043c30216fc978f1d78bd1425177efef623186 100644 (file)
@@ -72,7 +72,19 @@ struct bcma_host_ops {
 /* Core-ID values. */
 #define BCMA_CORE_OOB_ROUTER           0x367   /* Out of band */
 #define BCMA_CORE_4706_CHIPCOMMON      0x500
+#define BCMA_CORE_PCIEG2               0x501
+#define BCMA_CORE_DMA                  0x502
+#define BCMA_CORE_SDIO3                        0x503
+#define BCMA_CORE_USB20                        0x504
+#define BCMA_CORE_USB30                        0x505
+#define BCMA_CORE_A9JTAG               0x506
+#define BCMA_CORE_DDR23                        0x507
+#define BCMA_CORE_ROM                  0x508
+#define BCMA_CORE_NAND                 0x509
+#define BCMA_CORE_QSPI                 0x50A
+#define BCMA_CORE_CHIPCOMMON_B         0x50B
 #define BCMA_CORE_4706_SOC_RAM         0x50E
+#define BCMA_CORE_ARMCA9               0x510
 #define BCMA_CORE_4706_MAC_GBIT                0x52D
 #define BCMA_CORE_AMEMC                        0x52E   /* DDR1/2 memory controller core */
 #define BCMA_CORE_ALTA                 0x534   /* I2S core */
@@ -177,6 +189,11 @@ struct bcma_host_ops {
 #define  BCMA_PKG_ID_BCM5357   11
 #define BCMA_CHIP_ID_BCM53572  53572
 #define  BCMA_PKG_ID_BCM47188  9
+#define BCMA_CHIP_ID_BCM4707   53010
+#define  BCMA_PKG_ID_BCM4707   1
+#define  BCMA_PKG_ID_BCM4708   2
+#define  BCMA_PKG_ID_BCM4709   0
+#define BCMA_CHIP_ID_BCM53018  53018
 
 /* Board types (on PCI usually equals to the subsystem dev id) */
 /* BCM4313 */
index 70cf138690e9184678b1dea1aa9a23dd1a10a487..2c2b7c74f22f6ab6102d9b62063f713d140ff8dc 100644 (file)
@@ -61,6 +61,7 @@ struct coredump_params {
        struct file *file;
        unsigned long limit;
        unsigned long mm_flags;
+       unsigned long written;
 };
 
 /*
index e9ac882868c0353f8f6bb7f2baba2a73c8602c41..44dd422d7e9bbcb7b699cfc7e49032bd53c50991 100644 (file)
@@ -161,7 +161,13 @@ struct cgroup_name {
 struct cgroup {
        unsigned long flags;            /* "unsigned long" so bitops work */
 
-       int id;                         /* ida allocated in-hierarchy ID */
+       /*
+        * idr allocated in-hierarchy ID.
+        *
+        * The ID of the root cgroup is always 0, and a new cgroup
+        * will be assigned with a smallest available ID.
+        */
+       int id;
 
        /*
         * We link our 'sibling' struct into our parent's 'children'.
@@ -322,7 +328,7 @@ struct cgroupfs_root {
        unsigned long flags;
 
        /* IDs for cgroups in this hierarchy */
-       struct ida cgroup_ida;
+       struct idr cgroup_idr;
 
        /* The path to use for release notifications. */
        char release_agent_path[PATH_MAX];
@@ -394,8 +400,8 @@ struct cgroup_map_cb {
 
 /* cftype->flags */
 enum {
-       CFTYPE_ONLY_ON_ROOT     = (1 << 0),     /* only create on root cg */
-       CFTYPE_NOT_ON_ROOT      = (1 << 1),     /* don't create on root cg */
+       CFTYPE_ONLY_ON_ROOT     = (1 << 0),     /* only create on root cgrp */
+       CFTYPE_NOT_ON_ROOT      = (1 << 1),     /* don't create on root cgrp */
        CFTYPE_INSANE           = (1 << 2),     /* don't create if sane_behavior */
 };
 
@@ -513,7 +519,7 @@ struct cftype_set {
 };
 
 struct cgroup_scanner {
-       struct cgroup *cg;
+       struct cgroup *cgrp;
        int (*test_task)(struct task_struct *p, struct cgroup_scanner *scan);
        void (*process_task)(struct task_struct *p,
                        struct cgroup_scanner *scan);
@@ -713,6 +719,24 @@ static inline struct cgroup* task_cgroup(struct task_struct *task,
        return task_subsys_state(task, subsys_id)->cgroup;
 }
 
+/**
+ * cgroup_from_id - lookup cgroup by id
+ * @ss: cgroup subsys to be looked into
+ * @id: the cgroup id
+ *
+ * Returns the cgroup if there's valid one with @id, otherwise returns NULL.
+ * Should be called under rcu_read_lock().
+ */
+static inline struct cgroup *cgroup_from_id(struct cgroup_subsys *ss, int id)
+{
+#ifdef CONFIG_PROVE_RCU
+       rcu_lockdep_assert(rcu_read_lock_held() ||
+                          lockdep_is_held(&cgroup_mutex),
+                          "cgroup_from_id() needs proper protection");
+#endif
+       return idr_find(&ss->root->cgroup_idr, id);
+}
+
 struct cgroup *cgroup_next_sibling(struct cgroup *pos);
 
 /**
index a98f1ca60407d574ee89980bde8029d8f1f73f78..c617580e24a4b073f7470b14b7fa0ad4e138e376 100644 (file)
@@ -10,8 +10,9 @@
  * These are the only things you should do on a core-file: use only these
  * functions to write out all the necessary info.
  */
-extern int dump_write(struct file *file, const void *addr, int nr);
-extern int dump_seek(struct file *file, loff_t off);
+extern bool dump_emit(struct coredump_params *cprm, const void *addr, size_t size);
+extern bool dump_skip(struct coredump_params *cprm, size_t size);
+extern bool dump_align(struct coredump_params *cprm, int align);
 #ifdef CONFIG_COREDUMP
 extern void do_coredump(siginfo_t *siginfo);
 #else
index 90d5a15120d592eedeff5de22cd33fe61fe98351..e1fd215e16c9603314152d0a43c8dad68f6fd183 100644 (file)
@@ -216,10 +216,6 @@ extern int cpufreq_driver_target(struct cpufreq_policy *policy,
 extern int __cpufreq_driver_target(struct cpufreq_policy *policy,
                                   unsigned int target_freq,
                                   unsigned int relation);
-
-extern int __cpufreq_driver_getavg(struct cpufreq_policy *policy,
-                                  unsigned int cpu);
-
 int cpufreq_register_governor(struct cpufreq_governor *governor);
 void cpufreq_unregister_governor(struct cpufreq_governor *governor);
 
@@ -258,8 +254,6 @@ struct cpufreq_driver {
        unsigned int    (*get)  (unsigned int cpu);
 
        /* optional */
-       unsigned int (*getavg)  (struct cpufreq_policy *policy,
-                                unsigned int cpu);
        int     (*bios_limit)   (int cpu, unsigned int *limit);
 
        int     (*exit)         (struct cpufreq_policy *policy);
index 0bc4b74668e95f561e6cad07d038f6822f86faa0..781addc66f03135e1fe033bd6aeb0476c0321fd2 100644 (file)
@@ -13,8 +13,6 @@
 
 #include <linux/percpu.h>
 #include <linux/list.h>
-#include <linux/kobject.h>
-#include <linux/completion.h>
 #include <linux/hrtimer.h>
 
 #define CPUIDLE_STATE_MAX      10
@@ -61,6 +59,10 @@ struct cpuidle_state {
 
 #define CPUIDLE_DRIVER_FLAGS_MASK (0xFFFF0000)
 
+struct cpuidle_device_kobj;
+struct cpuidle_state_kobj;
+struct cpuidle_driver_kobj;
+
 struct cpuidle_device {
        unsigned int            registered:1;
        unsigned int            enabled:1;
@@ -71,9 +73,8 @@ struct cpuidle_device {
        struct cpuidle_state_usage      states_usage[CPUIDLE_STATE_MAX];
        struct cpuidle_state_kobj *kobjs[CPUIDLE_STATE_MAX];
        struct cpuidle_driver_kobj *kobj_driver;
+       struct cpuidle_device_kobj *kobj_dev;
        struct list_head        device_list;
-       struct kobject          kobj;
-       struct completion       kobj_unregister;
 
 #ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED
        int                     safe_state_index;
index cb286b1acdb64f06131a4de019d5d5603c864b50..5692bc3afd3929ab96ed38b911b9b0b0576bfa35 100644 (file)
@@ -370,6 +370,33 @@ struct dma_slave_config {
        unsigned int slave_id;
 };
 
+/* struct dma_slave_caps - expose capabilities of a slave channel only
+ *
+ * @src_addr_widths: bit mask of src addr widths the channel supports
+ * @dstn_addr_widths: bit mask of dstn addr widths the channel supports
+ * @directions: bit mask of slave direction the channel supported
+ *     since the enum dma_transfer_direction is not defined as bits for each
+ *     type of direction, the dma controller should fill (1 << <TYPE>) and same
+ *     should be checked by controller as well
+ * @cmd_pause: true, if pause and thereby resume is supported
+ * @cmd_terminate: true, if terminate cmd is supported
+ *
+ * @max_sg_nr: maximum number of SG segments supported
+ *     0 for no maximum
+ * @max_sg_len: maximum length of a SG segment supported
+ *     0 for no maximum
+ */
+struct dma_slave_caps {
+       u32 src_addr_widths;
+       u32 dstn_addr_widths;
+       u32 directions;
+       bool cmd_pause;
+       bool cmd_terminate;
+
+       u32 max_sg_nr;
+       u32 max_sg_len;
+};
+
 static inline const char *dma_chan_name(struct dma_chan *chan)
 {
        return dev_name(&chan->dev->device);
@@ -532,6 +559,7 @@ struct dma_tx_state {
  *     struct with auxiliary transfer status information, otherwise the call
  *     will just return a simple status code
  * @device_issue_pending: push pending transactions to hardware
+ * @device_slave_caps: return the slave channel capabilities
  */
 struct dma_device {
 
@@ -597,6 +625,7 @@ struct dma_device {
                                            dma_cookie_t cookie,
                                            struct dma_tx_state *txstate);
        void (*device_issue_pending)(struct dma_chan *chan);
+       int (*device_slave_caps)(struct dma_chan *chan, struct dma_slave_caps *caps);
 };
 
 static inline int dmaengine_device_control(struct dma_chan *chan,
@@ -670,6 +699,21 @@ static inline struct dma_async_tx_descriptor *dmaengine_prep_interleaved_dma(
        return chan->device->device_prep_interleaved_dma(chan, xt, flags);
 }
 
+static inline int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps)
+{
+       if (!chan || !caps)
+               return -EINVAL;
+
+       /* check if the channel supports slave transactions */
+       if (!test_bit(DMA_SLAVE, chan->device->cap_mask.bits))
+               return -ENXIO;
+
+       if (chan->device->device_slave_caps)
+               return chan->device->device_slave_caps(chan, caps);
+
+       return -ENXIO;
+}
+
 static inline int dmaengine_terminate_all(struct dma_chan *chan)
 {
        return dmaengine_device_control(chan, DMA_TERMINATE_ALL, 0);
index 40a3c0e01b2be880a428d9662ee490d9a070e277..87fdf7a9377fd9d7f65992c3a533bc30231392c6 100644 (file)
@@ -39,13 +39,14 @@ extern Elf64_Dyn _DYNAMIC [];
 
 /* Optional callbacks to write extra ELF notes. */
 struct file;
+struct coredump_params;
 
 #ifndef ARCH_HAVE_EXTRA_ELF_NOTES
 static inline int elf_coredump_extra_notes_size(void) { return 0; }
-static inline int elf_coredump_extra_notes_write(struct file *file,
-                       loff_t *foffset) { return 0; }
+static inline int elf_coredump_extra_notes_write(struct coredump_params *cprm)
+                       { return 0; }
 #else
 extern int elf_coredump_extra_notes_size(void);
-extern int elf_coredump_extra_notes_write(struct file *file, loff_t *foffset);
+extern int elf_coredump_extra_notes_write(struct coredump_params *cprm);
 #endif
 #endif /* _LINUX_ELF_H */
index cdd3d13efce7c24da5e65fc3d651b1564c3a20e0..fea1a62557de52ea3217da9ba79487f79a1fa1bd 100644 (file)
@@ -63,10 +63,9 @@ static inline int elf_core_copy_task_xfpregs(struct task_struct *t, elf_fpxregse
  */
 extern Elf_Half elf_core_extra_phdrs(void);
 extern int
-elf_core_write_extra_phdrs(struct file *file, loff_t offset, size_t *size,
-                          unsigned long limit);
+elf_core_write_extra_phdrs(struct coredump_params *cprm, loff_t offset);
 extern int
-elf_core_write_extra_data(struct file *file, size_t *size, unsigned long limit);
+elf_core_write_extra_data(struct coredump_params *cprm);
 extern size_t elf_core_extra_data_size(void);
 
 #endif /* _LINUX_ELFCORE_H */
index 3b0e820375ab90c2e0f9a05ffaa94f7a36f76abd..5d7782e42b8f22f81df12652348ff9a21aebc7e4 100644 (file)
@@ -436,6 +436,7 @@ struct fw_iso_context {
        int type;
        int channel;
        int speed;
+       bool drop_overflow_headers;
        size_t header_size;
        union {
                fw_iso_callback_t sc;
index 0c48991b0402d0d93110b8a4fa9cd42d615279c2..5a4e789b9e978dcbb7065bdd167dc7ab64f2c38a 100644 (file)
@@ -456,6 +456,7 @@ struct hid_device {                                                 /* device report descriptor */
        enum hid_type type;                                             /* device type (mouse, kbd, ...) */
        unsigned country;                                               /* HID country */
        struct hid_report_enum report_enum[HID_REPORT_TYPES];
+       struct work_struct led_work;                                    /* delayed LED worker */
 
        struct semaphore driver_lock;                                   /* protects the current driver, except during input */
        struct semaphore driver_input_lock;                             /* protects the current driver */
@@ -744,6 +745,7 @@ struct hid_field *hidinput_get_led_field(struct hid_device *hid);
 unsigned int hidinput_count_leds(struct hid_device *hid);
 __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code);
 void hid_output_report(struct hid_report *report, __u8 *data);
+u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags);
 struct hid_device *hid_allocate_device(void);
 struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id);
 int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size);
@@ -989,7 +991,6 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
 u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct);
 int usbhid_quirks_init(char **quirks_param);
 void usbhid_quirks_exit(void);
-void usbhid_set_leds(struct hid_device *hid);
 
 #ifdef CONFIG_HID_PID
 int hid_pidff_init(struct hid_device *hid);
index 60e411d764d4d67bf69d52936baf8f844bc097e2..7aa901d920585949b2ecf6c546d65cb004daceea 100644 (file)
@@ -19,7 +19,8 @@
  * @hid_descriptor_address: i2c register where the HID descriptor is stored.
  *
  * Note that it is the responsibility of the platform driver (or the acpi 5.0
- * driver) to setup the irq related to the gpio in the struct i2c_board_info.
+ * driver, or the flattened device tree) to setup the irq related to the gpio in
+ * the struct i2c_board_info.
  * The platform driver should also setup the gpio according to the device:
  *
  * A typical example is the following:
index f6156f91eb1cb0fb06597e83b95a8bf74664cee6..a899dc24be152ab29525ee4cdcc4e8f2a7a6636f 100644 (file)
@@ -10,9 +10,9 @@
 #ifndef _LINUX_IF_TEAM_H_
 #define _LINUX_IF_TEAM_H_
 
-
 #include <linux/netpoll.h>
 #include <net/sch_generic.h>
+#include <linux/types.h>
 #include <uapi/linux/if_team.h>
 
 struct team_pcpu_stats {
@@ -194,6 +194,18 @@ struct team {
        bool user_carrier_enabled;
        bool queue_override_enabled;
        struct list_head *qom_lists; /* array of queue override mapping lists */
+       struct {
+               unsigned int count;
+               unsigned int interval; /* in ms */
+               atomic_t count_pending;
+               struct delayed_work dw;
+       } notify_peers;
+       struct {
+               unsigned int count;
+               unsigned int interval; /* in ms */
+               atomic_t count_pending;
+               struct delayed_work dw;
+       } mcast_rejoin;
        long mode_priv[TEAM_MODE_PRIV_LONGS];
 };
 
index e3362b5f13e8258857f50a64e73fe3e70f9039f3..f47550d75f85fddd53186c92f0e1383c8f693b90 100644 (file)
@@ -129,6 +129,5 @@ extern void ip_mc_unmap(struct in_device *);
 extern void ip_mc_remap(struct in_device *);
 extern void ip_mc_dec_group(struct in_device *in_dev, __be32 addr);
 extern void ip_mc_inc_group(struct in_device *in_dev, __be32 addr);
-extern void ip_mc_rejoin_groups(struct in_device *in_dev);
 
 #endif
index 8685d1be12c71a2d28d8be80b3bbe9ae507e1ee4..bc3e57d367fc798b2db09094fb24ae5cbd56b5a4 100644 (file)
@@ -77,7 +77,7 @@ static inline void *jbd_alloc(size_t size, gfp_t flags)
 static inline void jbd_free(void *ptr, size_t size)
 {
        free_pages((unsigned long)ptr, get_order(size));
-};
+}
 
 #define JFS_MIN_JOURNAL_BLOCKS 1024
 
index 4ea55bb45debf3a1e8ad6d8120e81b763069adc1..283d66bc603c3374454896e9013f2984cd18b450 100644 (file)
@@ -138,6 +138,22 @@ enum {
        ATA_SHT_THIS_ID         = -1,
        ATA_SHT_USE_CLUSTERING  = 1,
 
+       /* struct ata_taskfile flags */
+       ATA_TFLAG_LBA48         = (1 << 0), /* enable 48-bit LBA and "HOB" */
+       ATA_TFLAG_ISADDR        = (1 << 1), /* enable r/w to nsect/lba regs */
+       ATA_TFLAG_DEVICE        = (1 << 2), /* enable r/w to device reg */
+       ATA_TFLAG_WRITE         = (1 << 3), /* data dir: host->dev==1 (write) */
+       ATA_TFLAG_LBA           = (1 << 4), /* enable LBA */
+       ATA_TFLAG_FUA           = (1 << 5), /* enable FUA */
+       ATA_TFLAG_POLLING       = (1 << 6), /* set nIEN to 1 and use polling */
+
+       /* protocol flags */
+       ATA_PROT_FLAG_PIO       = (1 << 0), /* is PIO */
+       ATA_PROT_FLAG_DMA       = (1 << 1), /* is DMA */
+       ATA_PROT_FLAG_DATA      = ATA_PROT_FLAG_PIO | ATA_PROT_FLAG_DMA,
+       ATA_PROT_FLAG_NCQ       = (1 << 2), /* is NCQ */
+       ATA_PROT_FLAG_ATAPI     = (1 << 3), /* is ATAPI */
+
        /* struct ata_device stuff */
        ATA_DFLAG_LBA           = (1 << 0), /* device supports LBA */
        ATA_DFLAG_LBA48         = (1 << 1), /* device supports LBA48 */
@@ -518,6 +534,29 @@ enum sw_activity {
        BLINK_OFF,
 };
 
+struct ata_taskfile {
+       unsigned long           flags;          /* ATA_TFLAG_xxx */
+       u8                      protocol;       /* ATA_PROT_xxx */
+
+       u8                      ctl;            /* control reg */
+
+       u8                      hob_feature;    /* additional data */
+       u8                      hob_nsect;      /* to support LBA48 */
+       u8                      hob_lbal;
+       u8                      hob_lbam;
+       u8                      hob_lbah;
+
+       u8                      feature;
+       u8                      nsect;
+       u8                      lbal;
+       u8                      lbam;
+       u8                      lbah;
+
+       u8                      device;
+
+       u8                      command;        /* IO operation */
+};
+
 #ifdef CONFIG_ATA_SFF
 struct ata_ioports {
        void __iomem            *cmd_addr;
@@ -959,6 +998,69 @@ extern const unsigned long sata_deb_timing_long[];
 extern struct ata_port_operations ata_dummy_port_ops;
 extern const struct ata_port_info ata_dummy_port_info;
 
+/*
+ * protocol tests
+ */
+static inline unsigned int ata_prot_flags(u8 prot)
+{
+       switch (prot) {
+       case ATA_PROT_NODATA:
+               return 0;
+       case ATA_PROT_PIO:
+               return ATA_PROT_FLAG_PIO;
+       case ATA_PROT_DMA:
+               return ATA_PROT_FLAG_DMA;
+       case ATA_PROT_NCQ:
+               return ATA_PROT_FLAG_DMA | ATA_PROT_FLAG_NCQ;
+       case ATAPI_PROT_NODATA:
+               return ATA_PROT_FLAG_ATAPI;
+       case ATAPI_PROT_PIO:
+               return ATA_PROT_FLAG_ATAPI | ATA_PROT_FLAG_PIO;
+       case ATAPI_PROT_DMA:
+               return ATA_PROT_FLAG_ATAPI | ATA_PROT_FLAG_DMA;
+       }
+       return 0;
+}
+
+static inline int ata_is_atapi(u8 prot)
+{
+       return ata_prot_flags(prot) & ATA_PROT_FLAG_ATAPI;
+}
+
+static inline int ata_is_nodata(u8 prot)
+{
+       return !(ata_prot_flags(prot) & ATA_PROT_FLAG_DATA);
+}
+
+static inline int ata_is_pio(u8 prot)
+{
+       return ata_prot_flags(prot) & ATA_PROT_FLAG_PIO;
+}
+
+static inline int ata_is_dma(u8 prot)
+{
+       return ata_prot_flags(prot) & ATA_PROT_FLAG_DMA;
+}
+
+static inline int ata_is_ncq(u8 prot)
+{
+       return ata_prot_flags(prot) & ATA_PROT_FLAG_NCQ;
+}
+
+static inline int ata_is_data(u8 prot)
+{
+       return ata_prot_flags(prot) & ATA_PROT_FLAG_DATA;
+}
+
+static inline int is_multi_taskfile(struct ata_taskfile *tf)
+{
+       return (tf->command == ATA_CMD_READ_MULTI) ||
+              (tf->command == ATA_CMD_WRITE_MULTI) ||
+              (tf->command == ATA_CMD_READ_MULTI_EXT) ||
+              (tf->command == ATA_CMD_WRITE_MULTI_EXT) ||
+              (tf->command == ATA_CMD_WRITE_MULTI_FUA_EXT);
+}
+
 static inline const unsigned long *
 sata_ehc_deb_timing(struct ata_eh_context *ehc)
 {
diff --git a/include/linux/mfd/arizona/gpio.h b/include/linux/mfd/arizona/gpio.h
new file mode 100644 (file)
index 0000000..d2146bb
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * GPIO configuration for Arizona devices
+ *
+ * Copyright 2013 Wolfson Microelectronics. PLC.
+ *
+ * Author: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _ARIZONA_GPIO_H
+#define _ARIZONA_GPIO_H
+
+#define ARIZONA_GP_FN_TXLRCLK                    0x00
+#define ARIZONA_GP_FN_GPIO                       0x01
+#define ARIZONA_GP_FN_IRQ1                       0x02
+#define ARIZONA_GP_FN_IRQ2                       0x03
+#define ARIZONA_GP_FN_OPCLK                      0x04
+#define ARIZONA_GP_FN_FLL1_OUT                   0x05
+#define ARIZONA_GP_FN_FLL2_OUT                   0x06
+#define ARIZONA_GP_FN_PWM1                       0x08
+#define ARIZONA_GP_FN_PWM2                       0x09
+#define ARIZONA_GP_FN_SYSCLK_UNDERCLOCKED        0x0A
+#define ARIZONA_GP_FN_ASYNCCLK_UNDERCLOCKED      0x0B
+#define ARIZONA_GP_FN_FLL1_LOCK                  0x0C
+#define ARIZONA_GP_FN_FLL2_LOCK                  0x0D
+#define ARIZONA_GP_FN_FLL1_CLOCK_OK              0x0F
+#define ARIZONA_GP_FN_FLL2_CLOCK_OK              0x10
+#define ARIZONA_GP_FN_HEADPHONE_DET              0x12
+#define ARIZONA_GP_FN_MIC_DET                    0x13
+#define ARIZONA_GP_FN_WSEQ_STATUS                0x15
+#define ARIZONA_GP_FN_CIF_ADDRESS_ERROR          0x16
+#define ARIZONA_GP_FN_ASRC1_LOCK                 0x1A
+#define ARIZONA_GP_FN_ASRC2_LOCK                 0x1B
+#define ARIZONA_GP_FN_ASRC_CONFIG_ERROR          0x1C
+#define ARIZONA_GP_FN_DRC1_SIGNAL_DETECT         0x1D
+#define ARIZONA_GP_FN_DRC1_ANTICLIP              0x1E
+#define ARIZONA_GP_FN_DRC1_DECAY                 0x1F
+#define ARIZONA_GP_FN_DRC1_NOISE                 0x20
+#define ARIZONA_GP_FN_DRC1_QUICK_RELEASE         0x21
+#define ARIZONA_GP_FN_DRC2_SIGNAL_DETECT         0x22
+#define ARIZONA_GP_FN_DRC2_ANTICLIP              0x23
+#define ARIZONA_GP_FN_DRC2_DECAY                 0x24
+#define ARIZONA_GP_FN_DRC2_NOISE                 0x25
+#define ARIZONA_GP_FN_DRC2_QUICK_RELEASE         0x26
+#define ARIZONA_GP_FN_MIXER_DROPPED_SAMPLE       0x27
+#define ARIZONA_GP_FN_AIF1_CONFIG_ERROR          0x28
+#define ARIZONA_GP_FN_AIF2_CONFIG_ERROR          0x29
+#define ARIZONA_GP_FN_AIF3_CONFIG_ERROR          0x2A
+#define ARIZONA_GP_FN_SPK_TEMP_SHUTDOWN          0x2B
+#define ARIZONA_GP_FN_SPK_TEMP_WARNING           0x2C
+#define ARIZONA_GP_FN_UNDERCLOCKED               0x2D
+#define ARIZONA_GP_FN_OVERCLOCKED                0x2E
+#define ARIZONA_GP_FN_DSP_IRQ1                   0x35
+#define ARIZONA_GP_FN_DSP_IRQ2                   0x36
+#define ARIZONA_GP_FN_ASYNC_OPCLK                0x3D
+#define ARIZONA_GP_FN_BOOT_DONE                  0x44
+#define ARIZONA_GP_FN_DSP1_RAM_READY             0x45
+#define ARIZONA_GP_FN_SYSCLK_ENA_STATUS          0x4B
+#define ARIZONA_GP_FN_ASYNCCLK_ENA_STATUS        0x4C
+
+#define ARIZONA_GPN_DIR                          0x8000  /* GPN_DIR */
+#define ARIZONA_GPN_DIR_MASK                     0x8000  /* GPN_DIR */
+#define ARIZONA_GPN_DIR_SHIFT                        15  /* GPN_DIR */
+#define ARIZONA_GPN_DIR_WIDTH                         1  /* GPN_DIR */
+#define ARIZONA_GPN_PU                           0x4000  /* GPN_PU */
+#define ARIZONA_GPN_PU_MASK                      0x4000  /* GPN_PU */
+#define ARIZONA_GPN_PU_SHIFT                         14  /* GPN_PU */
+#define ARIZONA_GPN_PU_WIDTH                          1  /* GPN_PU */
+#define ARIZONA_GPN_PD                           0x2000  /* GPN_PD */
+#define ARIZONA_GPN_PD_MASK                      0x2000  /* GPN_PD */
+#define ARIZONA_GPN_PD_SHIFT                         13  /* GPN_PD */
+#define ARIZONA_GPN_PD_WIDTH                          1  /* GPN_PD */
+#define ARIZONA_GPN_LVL                          0x0800  /* GPN_LVL */
+#define ARIZONA_GPN_LVL_MASK                     0x0800  /* GPN_LVL */
+#define ARIZONA_GPN_LVL_SHIFT                        11  /* GPN_LVL */
+#define ARIZONA_GPN_LVL_WIDTH                         1  /* GPN_LVL */
+#define ARIZONA_GPN_POL                          0x0400  /* GPN_POL */
+#define ARIZONA_GPN_POL_MASK                     0x0400  /* GPN_POL */
+#define ARIZONA_GPN_POL_SHIFT                        10  /* GPN_POL */
+#define ARIZONA_GPN_POL_WIDTH                         1  /* GPN_POL */
+#define ARIZONA_GPN_OP_CFG                       0x0200  /* GPN_OP_CFG */
+#define ARIZONA_GPN_OP_CFG_MASK                  0x0200  /* GPN_OP_CFG */
+#define ARIZONA_GPN_OP_CFG_SHIFT                      9  /* GPN_OP_CFG */
+#define ARIZONA_GPN_OP_CFG_WIDTH                      1  /* GPN_OP_CFG */
+#define ARIZONA_GPN_DB                           0x0100  /* GPN_DB */
+#define ARIZONA_GPN_DB_MASK                      0x0100  /* GPN_DB */
+#define ARIZONA_GPN_DB_SHIFT                          8  /* GPN_DB */
+#define ARIZONA_GPN_DB_WIDTH                          1  /* GPN_DB */
+#define ARIZONA_GPN_FN_MASK                      0x007F  /* GPN_DB */
+#define ARIZONA_GPN_FN_SHIFT                          0  /* GPN_DB */
+#define ARIZONA_GPN_FN_WIDTH                          7  /* GPN_DB */
+
+#endif
index bb1c8096a7eb28a5b9c9c24f37dd4603dc727b98..cd1fdf75103b7bd26350490cffc7de8e054bc366 100644 (file)
@@ -69,6 +69,7 @@ enum {
        MLX4_CMD_SET_ICM_SIZE    = 0xffd,
        /*master notify fw on finish for slave's flr*/
        MLX4_CMD_INFORM_FLR_DONE = 0x5b,
+       MLX4_CMD_GET_OP_REQ      = 0x59,
 
        /* TPT commands */
        MLX4_CMD_SW2HW_MPT       = 0xd,
index 52c23a892bab3cec77af9e8f662fe2ea3d47adfb..6aebdfe0ed8be7e88d6fd02cfe562c5a0680c9c6 100644 (file)
@@ -207,6 +207,7 @@ enum mlx4_event {
        MLX4_EVENT_TYPE_CMD                = 0x0a,
        MLX4_EVENT_TYPE_VEP_UPDATE         = 0x19,
        MLX4_EVENT_TYPE_COMM_CHANNEL       = 0x18,
+       MLX4_EVENT_TYPE_OP_REQUIRED        = 0x1a,
        MLX4_EVENT_TYPE_FATAL_WARNING      = 0x1b,
        MLX4_EVENT_TYPE_FLR_EVENT          = 0x1c,
        MLX4_EVENT_TYPE_PORT_MNG_CHG_EVENT = 0x1d,
index 8de8d8f22384b9abcd83ce0f76898c7afdf7ded9..737685e9e852e91fd93ccf142500c33773f42e71 100644 (file)
@@ -690,6 +690,26 @@ struct mlx5_query_cq_mbox_out {
        __be64                  pas[0];
 };
 
+struct mlx5_enable_hca_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       u8                      rsvd[8];
+};
+
+struct mlx5_enable_hca_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       u8                      rsvd[8];
+};
+
+struct mlx5_disable_hca_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       u8                      rsvd[8];
+};
+
+struct mlx5_disable_hca_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       u8                      rsvd[8];
+};
+
 struct mlx5_eq_context {
        u8                      status;
        u8                      ec_oi;
index f22e4419839b372b9cf6b6535b27cacf721ba9fc..2aa258b0ced1449b8281f6728d6f243d0c72d15f 100644 (file)
@@ -101,6 +101,8 @@ enum {
        MLX5_CMD_OP_QUERY_ADAPTER               = 0x101,
        MLX5_CMD_OP_INIT_HCA                    = 0x102,
        MLX5_CMD_OP_TEARDOWN_HCA                = 0x103,
+       MLX5_CMD_OP_ENABLE_HCA                  = 0x104,
+       MLX5_CMD_OP_DISABLE_HCA                 = 0x105,
        MLX5_CMD_OP_QUERY_PAGES                 = 0x107,
        MLX5_CMD_OP_MANAGE_PAGES                = 0x108,
        MLX5_CMD_OP_SET_HCA_CAP                 = 0x109,
@@ -690,7 +692,7 @@ int mlx5_pagealloc_start(struct mlx5_core_dev *dev);
 void mlx5_pagealloc_stop(struct mlx5_core_dev *dev);
 void mlx5_core_req_pages_handler(struct mlx5_core_dev *dev, u16 func_id,
                                 s16 npages);
-int mlx5_satisfy_startup_pages(struct mlx5_core_dev *dev);
+int mlx5_satisfy_startup_pages(struct mlx5_core_dev *dev, int boot);
 int mlx5_reclaim_startup_pages(struct mlx5_core_dev *dev);
 void mlx5_register_debugfs(void);
 void mlx5_unregister_debugfs(void);
index b62d4af6c667c27bbbd3620fde9813c9d6b529b8..45e921401b067b68c9912f82af1c19a1a8c6d048 100644 (file)
@@ -361,7 +361,8 @@ struct ssb_device_id {
        __u16   vendor;
        __u16   coreid;
        __u8    revision;
-};
+       __u8    __pad;
+} __attribute__((packed, aligned(2)));
 #define SSB_DEVICE(_vendor, _coreid, _revision)  \
        { .vendor = _vendor, .coreid = _coreid, .revision = _revision, }
 #define SSB_DEVTABLE_END  \
@@ -377,7 +378,7 @@ struct bcma_device_id {
        __u16   id;
        __u8    rev;
        __u8    class;
-};
+} __attribute__((packed,aligned(2)));
 #define BCMA_CORE(_manuf, _id, _rev, _class)  \
        { .manuf = _manuf, .id = _id, .rev = _rev, .class = _class, }
 #define BCMA_CORETABLE_END  \
index 46f1ea01e6f62161db550b13be8a2ed85246219a..504035f3ece151662eab6f5928140f3e159bb83a 100644 (file)
@@ -97,6 +97,11 @@ extern const struct gtype##_id __mod_##gtype##_table         \
 /* For userspace: you can also call me... */
 #define MODULE_ALIAS(_alias) MODULE_INFO(alias, _alias)
 
+/* Soft module dependencies. See man modprobe.d for details.
+ * Example: MODULE_SOFTDEP("pre: module-foo module-bar post: module-baz")
+ */
+#define MODULE_SOFTDEP(_softdep) MODULE_INFO(softdep, _softdep)
+
 /*
  * The following license idents are currently accepted as indicating free
  * software modules
index d6ed61ef451df403377f77e010a52711dac8e5a9..c8be32e9fc49507702d187a33893f8f3870a38ef 100644 (file)
@@ -137,6 +137,7 @@ enum access_mode {
 
 /**
  * fsmc_nand_platform_data - platform specific NAND controller config
+ * @nand_timings: timing setup for the physical NAND interface
  * @partitions: partition table for the platform, use a default fallback
  * if this is NULL
  * @nr_partitions: the number of partitions in the previous entry
index ab6363443ce81f033b641b014102a2dfdf8921be..0745a42f1acd0774acdbc3eb411061ca7648c900 100644 (file)
@@ -56,7 +56,7 @@ extern int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
  * is supported now. If you add a chip with bigger oobsize/page
  * adjust this accordingly.
  */
-#define NAND_MAX_OOBSIZE       640
+#define NAND_MAX_OOBSIZE       744
 #define NAND_MAX_PAGESIZE      8192
 
 /*
@@ -217,6 +217,9 @@ struct nand_chip;
 /* ONFI subfeature parameters length */
 #define ONFI_SUBFEATURE_PARAM_LEN      4
 
+/* ONFI optional commands SET/GET FEATURES supported? */
+#define ONFI_OPT_CMD_SET_GET_FEATURES  (1 << 2)
+
 struct nand_onfi_params {
        /* rev info and features block */
        /* 'O' 'N' 'F' 'I'  */
@@ -390,8 +393,8 @@ struct nand_buffers {
  * @write_buf:         [REPLACEABLE] write data from the buffer to the chip
  * @read_buf:          [REPLACEABLE] read data from the chip into the buffer
  * @select_chip:       [REPLACEABLE] select chip nr
- * @block_bad:         [REPLACEABLE] check, if the block is bad
- * @block_markbad:     [REPLACEABLE] mark the block bad
+ * @block_bad:         [REPLACEABLE] check if a block is bad, using OOB markers
+ * @block_markbad:     [REPLACEABLE] mark a block bad
  * @cmd_ctrl:          [BOARDSPECIFIC] hardwarespecific function for controlling
  *                     ALE/CLE/nCE. Also used to write command and address
  * @init_size:         [BOARDSPECIFIC] hardwarespecific function for setting
index 0741a1e919a542c53e50003560d01ed06322e658..077363dcd860702b67003c1721badf92d187e020 100644 (file)
@@ -728,6 +728,16 @@ struct netdev_fcoe_hbainfo {
 };
 #endif
 
+#define MAX_PHYS_PORT_ID_LEN 32
+
+/* This structure holds a unique identifier to identify the
+ * physical port used by a netdevice.
+ */
+struct netdev_phys_port_id {
+       unsigned char id[MAX_PHYS_PORT_ID_LEN];
+       unsigned char id_len;
+};
+
 /*
  * This structure defines the management hooks for network devices.
  * The following hooks can be defined; unless noted otherwise, they are
@@ -932,6 +942,12 @@ struct netdev_fcoe_hbainfo {
  *     that determine carrier state from physical hardware properties (eg
  *     network cables) or protocol-dependent mechanisms (eg
  *     USB_CDC_NOTIFY_NETWORK_CONNECTION) should NOT implement this function.
+ *
+ * int (*ndo_get_phys_port_id)(struct net_device *dev,
+ *                            struct netdev_phys_port_id *ppid);
+ *     Called to get ID of physical port of this device. If driver does
+ *     not implement this, it is assumed that the hw is not able to have
+ *     multiple net devices on single physical port.
  */
 struct net_device_ops {
        int                     (*ndo_init)(struct net_device *dev);
@@ -973,7 +989,7 @@ struct net_device_ops {
                                                     gfp_t gfp);
        void                    (*ndo_netpoll_cleanup)(struct net_device *dev);
 #endif
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        int                     (*ndo_busy_poll)(struct napi_struct *dev);
 #endif
        int                     (*ndo_set_vf_mac)(struct net_device *dev,
@@ -1060,6 +1076,8 @@ struct net_device_ops {
                                                      struct nlmsghdr *nlh);
        int                     (*ndo_change_carrier)(struct net_device *dev,
                                                      bool new_carrier);
+       int                     (*ndo_get_phys_port_id)(struct net_device *dev,
+                                                       struct netdev_phys_port_id *ppid);
 };
 
 /*
@@ -1633,6 +1651,7 @@ struct packet_offload {
 #define NETDEV_NOTIFY_PEERS    0x0013
 #define NETDEV_JOIN            0x0014
 #define NETDEV_CHANGEUPPER     0x0015
+#define NETDEV_RESEND_IGMP     0x0016
 
 extern int register_netdevice_notifier(struct notifier_block *nb);
 extern int unregister_netdevice_notifier(struct notifier_block *nb);
@@ -1665,9 +1684,6 @@ extern int call_netdevice_notifiers(unsigned long val, struct net_device *dev);
 
 extern rwlock_t                                dev_base_lock;          /* Device list lock */
 
-extern seqcount_t      devnet_rename_seq;      /* Device rename seq */
-
-
 #define for_each_netdev(net, d)                \
                list_for_each_entry(d, &(net)->dev_base_head, dev_list)
 #define for_each_netdev_reverse(net, d)        \
@@ -2317,6 +2333,8 @@ extern int                dev_set_mac_address(struct net_device *,
                                            struct sockaddr *);
 extern int             dev_change_carrier(struct net_device *,
                                           bool new_carrier);
+extern int             dev_get_phys_port_id(struct net_device *dev,
+                                            struct netdev_phys_port_id *ppid);
 extern int             dev_hard_start_xmit(struct sk_buff *skb,
                                            struct net_device *dev,
                                            struct netdev_queue *txq);
index 1704479772787b28950c9768a9e73c35c88dcd9a..d006f0ca60f46e92705fb8b3fd315ebacc5242b2 100644 (file)
@@ -47,24 +47,22 @@ void acpi_pci_remove_bus(struct pci_bus *bus);
 
 #ifdef CONFIG_ACPI_PCI_SLOT
 void acpi_pci_slot_init(void);
-void acpi_pci_slot_enumerate(struct pci_bus *bus, acpi_handle handle);
+void acpi_pci_slot_enumerate(struct pci_bus *bus);
 void acpi_pci_slot_remove(struct pci_bus *bus);
 #else
 static inline void acpi_pci_slot_init(void) { }
-static inline void acpi_pci_slot_enumerate(struct pci_bus *bus,
-                                          acpi_handle handle) { }
+static inline void acpi_pci_slot_enumerate(struct pci_bus *bus) { }
 static inline void acpi_pci_slot_remove(struct pci_bus *bus) { }
 #endif
 
 #ifdef CONFIG_HOTPLUG_PCI_ACPI
 void acpiphp_init(void);
-void acpiphp_enumerate_slots(struct pci_bus *bus, acpi_handle handle);
+void acpiphp_enumerate_slots(struct pci_bus *bus);
 void acpiphp_remove_slots(struct pci_bus *bus);
 void acpiphp_check_host_bridge(acpi_handle handle);
 #else
 static inline void acpiphp_init(void) { }
-static inline void acpiphp_enumerate_slots(struct pci_bus *bus,
-                                          acpi_handle handle) { }
+static inline void acpiphp_enumerate_slots(struct pci_bus *bus) { }
 static inline void acpiphp_remove_slots(struct pci_bus *bus) { }
 static inline void acpiphp_check_host_bridge(acpi_handle handle) { }
 #endif
index 0fd1f1582fa1cdf359b33f3cddeaa60026f492ac..2edbee64aeba5aeaecd5012f33202be4d929b166 100644 (file)
@@ -183,6 +183,19 @@ enum pci_bus_flags {
        PCI_BUS_FLAGS_NO_MMRBC = (__force pci_bus_flags_t) 2,
 };
 
+/* These values come from the PCI Express Spec */
+enum pcie_link_width {
+       PCIE_LNK_WIDTH_RESRV    = 0x00,
+       PCIE_LNK_X1             = 0x01,
+       PCIE_LNK_X2             = 0x02,
+       PCIE_LNK_X4             = 0x04,
+       PCIE_LNK_X8             = 0x08,
+       PCIE_LNK_X12            = 0x0C,
+       PCIE_LNK_X16            = 0x10,
+       PCIE_LNK_X32            = 0x20,
+       PCIE_LNK_WIDTH_UNKNOWN  = 0xFF,
+};
+
 /* Based on the PCI Hotplug Spec, but some values are made up by us */
 enum pci_bus_speed {
        PCI_SPEED_33MHz                 = 0x00,
@@ -921,6 +934,8 @@ int pcie_get_readrq(struct pci_dev *dev);
 int pcie_set_readrq(struct pci_dev *dev, int rq);
 int pcie_get_mps(struct pci_dev *dev);
 int pcie_set_mps(struct pci_dev *dev, int mps);
+int pcie_get_minimum_link(struct pci_dev *dev, enum pci_bus_speed *speed,
+                         enum pcie_link_width *width);
 int __pci_reset_function(struct pci_dev *dev);
 int __pci_reset_function_locked(struct pci_dev *dev);
 int pci_reset_function(struct pci_dev *dev);
index 8db71dcd633740a8a7290aff4a99f6a23ee8e366..64e61e05d9a03452c217e27f79573dea4d4afd48 100644 (file)
 #ifndef _PCI_HOTPLUG_H
 #define _PCI_HOTPLUG_H
 
-/* These values come from the PCI Express Spec */
-enum pcie_link_width {
-       PCIE_LNK_WIDTH_RESRV    = 0x00,
-       PCIE_LNK_X1             = 0x01,
-       PCIE_LNK_X2             = 0x02,
-       PCIE_LNK_X4             = 0x04,
-       PCIE_LNK_X8             = 0x08,
-       PCIE_LNK_X12            = 0x0C,
-       PCIE_LNK_X16            = 0x10,
-       PCIE_LNK_X32            = 0x20,
-       PCIE_LNK_WIDTH_UNKNOWN  = 0xFF,
-};
-
 /**
  * struct hotplug_slot_ops -the callbacks that the hotplug pci core can use
  * @owner: The module owner of this structure
index 6a293b7fff3bf9d4cb260d3d6c6d639427f38275..cea9f70133c521f1d5fb2a0d459f3e30ca3f9576 100644 (file)
@@ -71,6 +71,10 @@ struct atmel_nand_data {
        u8              on_flash_bbt;           /* bbt on flash */
        struct mtd_partition *parts;
        unsigned int    num_parts;
+       bool            has_dma;                /* support dma transfer */
+
+       /* default is false, only for at32ap7000 chip is true */
+       bool            need_reset_workaround;
 };
 
  /* Serial */
index bf0a83b7ed9d3e0538cc09c57f7d498065931501..5e36e4205043239073fe5dcec4a73da465611ff3 100644 (file)
@@ -23,6 +23,10 @@ enum bch_ecc {
        BCH8_ECC,
 };
 
+#define ECC_TYPE_BCH4                (0x0 << 0)
+#define ECC_TYPE_BCH8                (0x1 << 0)
+#define ECC_TYPE_BCH16               (0x2 << 0)
+
 /* ELM support 8 error syndrome process */
 #define ERROR_VECTOR_MAX               8
 
diff --git a/include/linux/platform_data/omap-abe-twl6040.h b/include/linux/platform_data/omap-abe-twl6040.h
deleted file mode 100644 (file)
index 5d298ac..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- * omap-abe-twl6040.h - ASoC machine driver OMAP4+ devices, header.
- *
- * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com
- * All rights reserved.
- *
- * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- */
-
-#ifndef _OMAP_ABE_TWL6040_H_
-#define _OMAP_ABE_TWL6040_H_
-
-/* To select if only one channel is connected in a stereo port */
-#define ABE_TWL6040_LEFT       (1 << 0)
-#define ABE_TWL6040_RIGHT      (1 << 1)
-
-struct omap_abe_twl6040_data {
-       char *card_name;
-       /* Feature flags for connected audio pins */
-       u8      has_hs;
-       u8      has_hf;
-       bool    has_ep;
-       u8      has_aux;
-       u8      has_vibra;
-       bool    has_dmic;
-       bool    has_hsmic;
-       bool    has_mainmic;
-       bool    has_submic;
-       u8      has_afm;
-       /* Other features */
-       bool    jack_detection; /* board can detect jack events */
-       int     mclk_freq;      /* MCLK frequency speed for twl6040 */
-};
-
-#endif /* _OMAP_ABE_TWL6040_H_ */
index 8dfaa2ce2e956e0037c469daed8586cb9a94bc68..0f424698064f5ee2c0a0da036189843c2e8cead4 100644 (file)
@@ -114,6 +114,11 @@ extern const struct raid6_recov_calls raid6_recov_intx1;
 extern const struct raid6_recov_calls raid6_recov_ssse3;
 extern const struct raid6_recov_calls raid6_recov_avx2;
 
+extern const struct raid6_calls raid6_neonx1;
+extern const struct raid6_calls raid6_neonx2;
+extern const struct raid6_calls raid6_neonx4;
+extern const struct raid6_calls raid6_neonx8;
+
 /* Algorithm list */
 extern const struct raid6_calls * const raid6_algos[];
 extern const struct raid6_recov_calls *const raid6_recov_algos[];
index 50d04b92cedaf900532f72d1acef35d04d7ecb69..d722490da030c5906d991b7c76f8dc178edadee8 100644 (file)
@@ -1628,6 +1628,7 @@ extern void thread_group_cputime_adjusted(struct task_struct *p, cputime_t *ut,
 #define PF_MEMPOLICY   0x10000000      /* Non-default NUMA mempolicy */
 #define PF_MUTEX_TESTER        0x20000000      /* Thread belongs to the rt mutex tester */
 #define PF_FREEZER_SKIP        0x40000000      /* Freezer should not count it as freezable */
+#define PF_SUSPEND_TASK 0x80000000      /* this thread called freeze_processes and should not be frozen */
 
 /*
  * Only the _current_ task can read/write to tsk->flags, but other
index d34049712a4d7cee24958816840ca1c843e0541f..dca3c08d414112cfb56dbe011db8263c6b81343f 100644 (file)
 #define SCIx_NOT_SUPPORTED     (-1)
 
 enum {
+       SCBRR_ALGO_INVALID,
+
        SCBRR_ALGO_1,           /* ((clk + 16 * bps) / (16 * bps) - 1) */
        SCBRR_ALGO_2,           /* ((clk + 16 * bps) / (32 * bps) - 1) */
        SCBRR_ALGO_3,           /* (((clk * 2) + 16 * bps) / (16 * bps) - 1) */
        SCBRR_ALGO_4,           /* (((clk * 2) + 16 * bps) / (32 * bps) - 1) */
        SCBRR_ALGO_5,           /* (((clk * 1000 / 32) / bps) - 1) */
        SCBRR_ALGO_6,           /* HSCIF variable sample rate algorithm */
+
+       SCBRR_NR_ALGOS,
 };
 
 #define SCSCR_TIE      (1 << 7)
index 5afefa01a13c892e1fe9eb7ce6fc3f047e5880ba..ae46475d45684fe73718a489d287cd2f5fd6b1f9 100644 (file)
@@ -501,7 +501,7 @@ struct sk_buff {
        /* 7/9 bit hole (depending on ndisc_nodetype presence) */
        kmemcheck_bitfield_end(flags2);
 
-#if defined CONFIG_NET_DMA || defined CONFIG_NET_LL_RX_POLL
+#if defined CONFIG_NET_DMA || defined CONFIG_NET_RX_BUSY_POLL
        union {
                unsigned int    napi_id;
                dma_cookie_t    dma_cookie;
@@ -1805,10 +1805,13 @@ static inline void pskb_trim_unique(struct sk_buff *skb, unsigned int len)
  */
 static inline void skb_orphan(struct sk_buff *skb)
 {
-       if (skb->destructor)
+       if (skb->destructor) {
                skb->destructor(skb);
-       skb->destructor = NULL;
-       skb->sk         = NULL;
+               skb->destructor = NULL;
+               skb->sk         = NULL;
+       } else {
+               BUG_ON(skb->sk);
+       }
 }
 
 /**
index 472120b4fac57584f30998d1be87c672607eb643..d68633452d9b070ce12056e5a17dc40f1f148c4d 100644 (file)
@@ -107,7 +107,6 @@ static inline void tcp_clear_options(struct tcp_options_received *rx_opt)
  * only four options will fit in a standard TCP header */
 #define TCP_NUM_SACKS 4
 
-struct tcp_cookie_values;
 struct tcp_request_sock_ops;
 
 struct tcp_request_sock {
@@ -238,6 +237,7 @@ struct tcp_sock {
 
        u32     rcv_wnd;        /* Current receiver window              */
        u32     write_seq;      /* Tail(+1) of data held in tcp send buffer */
+       u32     notsent_lowat;  /* TCP_NOTSENT_LOWAT */
        u32     pushed_seq;     /* Last pushed seq, required to talk to windows */
        u32     lost_out;       /* Lost packets                 */
        u32     sacked_out;     /* SACK'd packets                       */
index 9180f4b85e6deedd827fa071add91940c3ac48e5..62bd8b72873c0bed1702d41a2a8982831d01564b 100644 (file)
@@ -174,10 +174,4 @@ static inline void tick_nohz_task_switch(struct task_struct *tsk) { }
 #endif
 
 
-# ifdef CONFIG_CPU_IDLE_GOV_MENU
-extern void menu_hrtimer_cancel(void);
-# else
-static inline void menu_hrtimer_cancel(void) {}
-# endif /* CONFIG_CPU_IDLE_GOV_MENU */
-
 #endif
index f18d64129f99982f966f3c2fe733cd85260dc625..8fbc008e183e33704ddbc0f8cc63c3cd69b5f753 100644 (file)
@@ -34,6 +34,7 @@ struct usbnet {
        struct mutex            phy_mutex;
        unsigned char           suspend_count;
        unsigned char           pkt_cnt, pkt_err;
+       unsigned short          rx_qlen, tx_qlen;
 
        /* i/o info: pipes etc */
        unsigned                in, out;
@@ -253,4 +254,6 @@ extern void usbnet_link_change(struct usbnet *, bool, bool);
 extern int usbnet_status_start(struct usbnet *dev, gfp_t mem_flags);
 extern void usbnet_status_stop(struct usbnet *dev);
 
+extern void usbnet_update_max_qlen(struct usbnet *dev);
+
 #endif /* __LINUX_USB_USBNET_H */
index 76be077340ea5c7c4d96f1299bea48b9aa40a98d..7dc17e2456de141ef3241a73af02fbec9b9c1ee5 100644 (file)
@@ -12,7 +12,7 @@ struct vmpressure {
        unsigned long scanned;
        unsigned long reclaimed;
        /* The lock is used to keep the scanned/reclaimed above in sync. */
-       struct mutex sr_lock;
+       struct spinlock sr_lock;
 
        /* The list of vmpressure_event structs. */
        struct list_head events;
@@ -30,6 +30,7 @@ extern void vmpressure(gfp_t gfp, struct mem_cgroup *memcg,
 extern void vmpressure_prio(gfp_t gfp, struct mem_cgroup *memcg, int prio);
 
 extern void vmpressure_init(struct vmpressure *vmpr);
+extern void vmpressure_cleanup(struct vmpressure *vmpr);
 extern struct vmpressure *memcg_to_vmpressure(struct mem_cgroup *memcg);
 extern struct cgroup_subsys_state *vmpressure_to_css(struct vmpressure *vmpr);
 extern struct vmpressure *css_to_vmpressure(struct cgroup_subsys_state *css);
index 944757be49bbf7ef4005202d2f20e71b1fc3fc44..e4142b1ef8cdae0aa99320405d2cd21196058869 100644 (file)
  * @pll_control: PLL and oversampling control. This control allows internal
  *              PLL 1 circuit to be powered down and the oversampling to be
  *              switched off.
- * @dac_1: power on/off DAC 1.
- * @dac_2: power on/off DAC 2.
- * @dac_3: power on/off DAC 3.
- * @dac_4: power on/off DAC 4.
- * @dac_5: power on/off DAC 5.
- * @dac_6: power on/off DAC 6.
+ * @dac: array to configure power on/off DAC's 1..6
  *
  * Power mode register (Register 0x0), for more info refer REGISTER MAP ACCESS
  * section of datasheet[1], table 17 page no 30.
 struct adv7343_power_mode {
        bool sleep_mode;
        bool pll_control;
-       bool dac_1;
-       bool dac_2;
-       bool dac_3;
-       bool dac_4;
-       bool dac_5;
-       bool dac_6;
+       u32 dac[6];
 };
 
 /**
  * struct adv7343_sd_config - SD Only Output Configuration.
- * @sd_dac_out1: Configure SD DAC Output 1.
- * @sd_dac_out2: Configure SD DAC Output 2.
+ * @sd_dac_out: array configuring SD DAC Outputs 1 and 2
  */
 struct adv7343_sd_config {
        /* SD only Output Configuration */
-       bool sd_dac_out1;
-       bool sd_dac_out2;
+       u32 sd_dac_out[2];
 };
 
 /**
index 3882e0675ccfd45e718dbd8dc38bedd51af02120..3cb1704a0650d2020f3bb67cc055bc4bd695c0d0 100644 (file)
@@ -59,6 +59,8 @@ struct vpif_display_config {
        int subdev_count;
        struct vpif_display_chan_config chan_config[VPIF_DISPLAY_MAX_CHANNELS];
        const char *card_name;
+       struct v4l2_async_subdev **asd; /* Flat array, arranged in groups */
+       int *asd_sizes;         /* 0-terminated array of asd group sizes */
 };
 
 struct vpif_input {
@@ -81,5 +83,7 @@ struct vpif_capture_config {
        struct vpif_subdev_info *subdev_info;
        int subdev_count;
        const char *card_name;
+       struct v4l2_async_subdev **asd; /* Flat array, arranged in groups */
+       int *asd_sizes;         /* 0-terminated array of asd group sizes */
 };
 #endif /* _VPIF_TYPES_H */
index 168dd0b1bae236ea3859e1fb384b6cc79766a1da..78f0637ca68d91d1fc45639141bb6f9d39acd82e 100644 (file)
@@ -139,6 +139,7 @@ struct lirc_driver {
        struct lirc_buffer *rbuf;
        int (*set_use_inc) (void *data);
        void (*set_use_dec) (void *data);
+       struct rc_dev *rdev;
        const struct file_operations *fops;
        struct device *dev;
        struct module *owner;
index 06a75deff553c4a2fac3396c48b3954dda422432..2f6f1f78d958c5238e3f0a145c0c33c0a38b45f0 100644 (file)
@@ -101,6 +101,7 @@ struct rc_dev {
        bool                            idle;
        u64                             allowed_protos;
        u64                             enabled_protocols;
+       u32                             users;
        u32                             scanmask;
        void                            *priv;
        spinlock_t                      keylock;
@@ -142,6 +143,9 @@ void rc_free_device(struct rc_dev *dev);
 int rc_register_device(struct rc_dev *dev);
 void rc_unregister_device(struct rc_dev *dev);
 
+int rc_open(struct rc_dev *rdev);
+void rc_close(struct rc_dev *rdev);
+
 void rc_repeat(struct rc_dev *dev);
 void rc_keydown(struct rc_dev *dev, int scancode, u8 toggle);
 void rc_keydown_notimeout(struct rc_dev *dev, int scancode, u8 toggle);
index c3ec6ac75f7e9837f9d686ab87f3b69f455945f7..768356917bea005886a5c897f3af9c740d07ad6e 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/mutex.h>
 
 struct device;
+struct device_node;
 struct v4l2_device;
 struct v4l2_subdev;
 struct v4l2_async_notifier;
@@ -22,10 +23,11 @@ struct v4l2_async_notifier;
 /* A random max subdevice number, used to allocate an array on stack */
 #define V4L2_MAX_SUBDEVS 128U
 
-enum v4l2_async_bus_type {
-       V4L2_ASYNC_BUS_CUSTOM,
-       V4L2_ASYNC_BUS_PLATFORM,
-       V4L2_ASYNC_BUS_I2C,
+enum v4l2_async_match_type {
+       V4L2_ASYNC_MATCH_CUSTOM,
+       V4L2_ASYNC_MATCH_DEVNAME,
+       V4L2_ASYNC_MATCH_I2C,
+       V4L2_ASYNC_MATCH_OF,
 };
 
 /**
@@ -36,11 +38,14 @@ enum v4l2_async_bus_type {
  *             probed, to a notifier->waiting list
  */
 struct v4l2_async_subdev {
-       enum v4l2_async_bus_type bus_type;
+       enum v4l2_async_match_type match_type;
        union {
+               struct {
+                       const struct device_node *node;
+               } of;
                struct {
                        const char *name;
-               } platform;
+               } device_name;
                struct {
                        int adapter_id;
                        unsigned short address;
@@ -56,26 +61,13 @@ struct v4l2_async_subdev {
        struct list_head list;
 };
 
-/**
- * v4l2_async_subdev_list - provided by subdevices
- * @list:      links struct v4l2_async_subdev_list objects to a global list
- *             before probing, and onto notifier->done after probing
- * @asd:       pointer to respective struct v4l2_async_subdev
- * @notifier:  pointer to managing notifier
- */
-struct v4l2_async_subdev_list {
-       struct list_head list;
-       struct v4l2_async_subdev *asd;
-       struct v4l2_async_notifier *notifier;
-};
-
 /**
  * v4l2_async_notifier - v4l2_device notifier data
  * @num_subdevs:number of subdevices
- * @subdev   array of pointers to subdevice descriptors
+ * @subdevs:   array of pointers to subdevice descriptors
  * @v4l2_dev:  pointer to struct v4l2_device
  * @waiting:   list of struct v4l2_async_subdev, waiting for their drivers
- * @done:      list of struct v4l2_async_subdev_list, already probed
+ * @done:      list of struct v4l2_subdev, already probed
  * @list:      member in a global list of notifiers
  * @bound:     a subdevice driver has successfully probed one of subdevices
  * @complete:  all subdevices have been probed successfully
@@ -83,7 +75,7 @@ struct v4l2_async_subdev_list {
  */
 struct v4l2_async_notifier {
        unsigned int num_subdevs;
-       struct v4l2_async_subdev **subdev;
+       struct v4l2_async_subdev **subdevs;
        struct v4l2_device *v4l2_dev;
        struct list_head waiting;
        struct list_head done;
index 7343a27fe81966372c3ee8dc72241f2822891543..47ada23345a195973c3942681566244d50c7f34d 100644 (file)
@@ -22,6 +22,7 @@
 #define _V4L2_CTRLS_H
 
 #include <linux/list.h>
+#include <linux/mutex.h>
 #include <linux/videodev2.h>
 
 /* forward references */
index 0f4555b2a31bdfc4a499df23f3b77de6a95769a2..44542a20ab8126cdcd851a3d369f2b2b956c96ac 100644 (file)
@@ -60,6 +60,7 @@ struct v4l2_m2m_queue_ctx {
        struct list_head        rdy_queue;
        spinlock_t              rdy_spinlock;
        u8                      num_rdy;
+       bool                    buffered;
 };
 
 struct v4l2_m2m_ctx {
@@ -134,6 +135,18 @@ struct v4l2_m2m_ctx *v4l2_m2m_ctx_init(struct v4l2_m2m_dev *m2m_dev,
                void *drv_priv,
                int (*queue_init)(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq));
 
+static inline void v4l2_m2m_set_src_buffered(struct v4l2_m2m_ctx *m2m_ctx,
+                                            bool buffered)
+{
+       m2m_ctx->out_q_ctx.buffered = buffered;
+}
+
+static inline void v4l2_m2m_set_dst_buffered(struct v4l2_m2m_ctx *m2m_ctx,
+                                            bool buffered)
+{
+       m2m_ctx->cap_q_ctx.buffered = buffered;
+}
+
 void v4l2_m2m_ctx_release(struct v4l2_m2m_ctx *m2m_ctx);
 
 void v4l2_m2m_buf_queue(struct v4l2_m2m_ctx *m2m_ctx, struct vb2_buffer *vb);
index 3250cc5e79259febddfb7a9472114281a8f4b1f1..bfda0fe9aeb05fc494a167cc246d9b500a508be2 100644 (file)
@@ -586,15 +586,14 @@ struct v4l2_subdev {
        struct video_device *devnode;
        /* pointer to the physical device, if any */
        struct device *dev;
-       struct v4l2_async_subdev_list asdl;
+       /* Links this subdev to a global subdev_list or @notifier->done list. */
+       struct list_head async_list;
+       /* Pointer to respective struct v4l2_async_subdev. */
+       struct v4l2_async_subdev *asd;
+       /* Pointer to the managing notifier. */
+       struct v4l2_async_notifier *notifier;
 };
 
-static inline struct v4l2_subdev *v4l2_async_to_subdev(
-                       struct v4l2_async_subdev_list *asdl)
-{
-       return container_of(asdl, struct v4l2_subdev, asdl);
-}
-
 #define media_entity_to_v4l2_subdev(ent) \
        container_of(ent, struct v4l2_subdev, entity)
 #define vdev_to_v4l2_subdev(vdev) \
index d9fa68f26c41c34c33db5f743a4142faf7886792..9a36d929711482da1f4090fb9e51c4ab9a261ffd 100644 (file)
@@ -40,8 +40,6 @@
  * @close: member function to discard a connection on this transport
  * @request: member function to issue a request to the transport
  * @cancel: member function to cancel a request (if it hasn't been sent)
- * @cancelled: member function to notify that a cancelled request will not
- *             not receive a reply
  *
  * This is the basic API for a transport module which is registered by the
  * transport module with the 9P core network module and used by the client
@@ -60,7 +58,6 @@ struct p9_trans_module {
        void (*close) (struct p9_client *);
        int (*request) (struct p9_client *, struct p9_req_t *req);
        int (*cancel) (struct p9_client *, struct p9_req_t *req);
-       int (*cancelled)(struct p9_client *, struct p9_req_t *req);
        int (*zc_request)(struct p9_client *, struct p9_req_t *,
                          char *, char *, int , int, int, int);
 };
index b8ffac7b6bab755f5adb4d648b5d34bd57eb028f..9e90fdff470d5a8b358b35c8aa3bc660728ffc05 100644 (file)
@@ -82,36 +82,36 @@ struct tc_action_ops {
        int     (*walk)(struct sk_buff *, struct netlink_callback *, int, struct tc_action *);
 };
 
-extern struct tcf_common *tcf_hash_lookup(u32 index,
-                                         struct tcf_hashinfo *hinfo);
-extern void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo);
-extern int tcf_hash_release(struct tcf_common *p, int bind,
-                           struct tcf_hashinfo *hinfo);
-extern int tcf_generic_walker(struct sk_buff *skb, struct netlink_callback *cb,
-                             int type, struct tc_action *a);
-extern u32 tcf_hash_new_index(u32 *idx_gen, struct tcf_hashinfo *hinfo);
-extern int tcf_hash_search(struct tc_action *a, u32 index);
-extern struct tcf_common *tcf_hash_check(u32 index, struct tc_action *a,
-                                        int bind, struct tcf_hashinfo *hinfo);
-extern struct tcf_common *tcf_hash_create(u32 index, struct nlattr *est,
-                                         struct tc_action *a, int size,
-                                         int bind, u32 *idx_gen,
-                                         struct tcf_hashinfo *hinfo);
-extern void tcf_hash_insert(struct tcf_common *p, struct tcf_hashinfo *hinfo);
+struct tcf_common *tcf_hash_lookup(u32 index, struct tcf_hashinfo *hinfo);
+void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo);
+int tcf_hash_release(struct tcf_common *p, int bind,
+                    struct tcf_hashinfo *hinfo);
+int tcf_generic_walker(struct sk_buff *skb, struct netlink_callback *cb,
+                      int type, struct tc_action *a);
+u32 tcf_hash_new_index(u32 *idx_gen, struct tcf_hashinfo *hinfo);
+int tcf_hash_search(struct tc_action *a, u32 index);
+struct tcf_common *tcf_hash_check(u32 index, struct tc_action *a,
+                                 int bind, struct tcf_hashinfo *hinfo);
+struct tcf_common *tcf_hash_create(u32 index, struct nlattr *est,
+                                  struct tc_action *a, int size,
+                                  int bind, u32 *idx_gen,
+                                  struct tcf_hashinfo *hinfo);
+void tcf_hash_insert(struct tcf_common *p, struct tcf_hashinfo *hinfo);
 
-extern int tcf_register_action(struct tc_action_ops *a);
-extern int tcf_unregister_action(struct tc_action_ops *a);
-extern void tcf_action_destroy(struct tc_action *a, int bind);
-extern int tcf_action_exec(struct sk_buff *skb, const struct tc_action *a, struct tcf_result *res);
-extern struct tc_action *tcf_action_init(struct net *net, struct nlattr *nla,
-                                        struct nlattr *est, char *n, int ovr,
-                                        int bind);
-extern struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla,
-                                          struct nlattr *est, char *n, int ovr,
-                                          int bind);
-extern int tcf_action_dump(struct sk_buff *skb, struct tc_action *a, int, int);
-extern int tcf_action_dump_old(struct sk_buff *skb, struct tc_action *a, int, int);
-extern int tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int, int);
-extern int tcf_action_copy_stats (struct sk_buff *,struct tc_action *, int);
+int tcf_register_action(struct tc_action_ops *a);
+int tcf_unregister_action(struct tc_action_ops *a);
+void tcf_action_destroy(struct tc_action *a, int bind);
+int tcf_action_exec(struct sk_buff *skb, const struct tc_action *a,
+                   struct tcf_result *res);
+struct tc_action *tcf_action_init(struct net *net, struct nlattr *nla,
+                                 struct nlattr *est, char *n, int ovr,
+                                 int bind);
+struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla,
+                                   struct nlattr *est, char *n, int ovr,
+                                   int bind);
+int tcf_action_dump(struct sk_buff *skb, struct tc_action *a, int, int);
+int tcf_action_dump_old(struct sk_buff *skb, struct tc_action *a, int, int);
+int tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int, int);
+int tcf_action_copy_stats(struct sk_buff *, struct tc_action *, int);
 #endif /* CONFIG_NET_CLS_ACT */
 #endif
index c7b181cb47a6a9ae4b4e30ca2d94ce74f5f9ef40..43fa31a610b81e9d7ae8677d58d34b431cd47576 100644 (file)
@@ -53,51 +53,36 @@ struct prefix_info {
 #define IN6_ADDR_HSIZE_SHIFT   4
 #define IN6_ADDR_HSIZE         (1 << IN6_ADDR_HSIZE_SHIFT)
 
-extern int                     addrconf_init(void);
-extern void                    addrconf_cleanup(void);
+int addrconf_init(void);
+void addrconf_cleanup(void);
 
-extern int                     addrconf_add_ifaddr(struct net *net,
-                                                   void __user *arg);
-extern int                     addrconf_del_ifaddr(struct net *net,
-                                                   void __user *arg);
-extern int                     addrconf_set_dstaddr(struct net *net,
-                                                    void __user *arg);
+int addrconf_add_ifaddr(struct net *net, void __user *arg);
+int addrconf_del_ifaddr(struct net *net, void __user *arg);
+int addrconf_set_dstaddr(struct net *net, void __user *arg);
 
-extern int                     ipv6_chk_addr(struct net *net,
-                                             const struct in6_addr *addr,
-                                             const struct net_device *dev,
-                                             int strict);
+int ipv6_chk_addr(struct net *net, const struct in6_addr *addr,
+                 const struct net_device *dev, int strict);
 
 #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
-extern int                     ipv6_chk_home_addr(struct net *net,
-                                                  const struct in6_addr *addr);
+int ipv6_chk_home_addr(struct net *net, const struct in6_addr *addr);
 #endif
 
-extern int                     ipv6_chk_prefix(const struct in6_addr *addr,
-                                               struct net_device *dev);
-
-extern struct inet6_ifaddr      *ipv6_get_ifaddr(struct net *net,
-                                                const struct in6_addr *addr,
-                                                struct net_device *dev,
-                                                int strict);
-
-extern int                     ipv6_dev_get_saddr(struct net *net,
-                                              const struct net_device *dev,
-                                              const struct in6_addr *daddr,
-                                              unsigned int srcprefs,
-                                              struct in6_addr *saddr);
-extern int                     __ipv6_get_lladdr(struct inet6_dev *idev,
-                                                 struct in6_addr *addr,
-                                                 unsigned char banned_flags);
-extern int                     ipv6_get_lladdr(struct net_device *dev,
-                                               struct in6_addr *addr,
-                                               unsigned char banned_flags);
-extern int                     ipv6_rcv_saddr_equal(const struct sock *sk,
-                                                   const struct sock *sk2);
-extern void                    addrconf_join_solict(struct net_device *dev,
-                                       const struct in6_addr *addr);
-extern void                    addrconf_leave_solict(struct inet6_dev *idev,
-                                       const struct in6_addr *addr);
+int ipv6_chk_prefix(const struct in6_addr *addr, struct net_device *dev);
+
+struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net,
+                                    const struct in6_addr *addr,
+                                    struct net_device *dev, int strict);
+
+int ipv6_dev_get_saddr(struct net *net, const struct net_device *dev,
+                      const struct in6_addr *daddr, unsigned int srcprefs,
+                      struct in6_addr *saddr);
+int __ipv6_get_lladdr(struct inet6_dev *idev, struct in6_addr *addr,
+                     unsigned char banned_flags);
+int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr,
+                   unsigned char banned_flags);
+int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2);
+void addrconf_join_solict(struct net_device *dev, const struct in6_addr *addr);
+void addrconf_leave_solict(struct inet6_dev *idev, const struct in6_addr *addr);
 
 static inline unsigned long addrconf_timeout_fixup(u32 timeout,
                                                   unsigned int unit)
@@ -124,41 +109,38 @@ static inline int addrconf_finite_timeout(unsigned long timeout)
 /*
  *     IPv6 Address Label subsystem (addrlabel.c)
  */
-extern int                     ipv6_addr_label_init(void);
-extern void                    ipv6_addr_label_cleanup(void);
-extern void                    ipv6_addr_label_rtnl_register(void);
-extern u32                     ipv6_addr_label(struct net *net,
-                                               const struct in6_addr *addr,
-                                               int type, int ifindex);
+int ipv6_addr_label_init(void);
+void ipv6_addr_label_cleanup(void);
+void ipv6_addr_label_rtnl_register(void);
+u32 ipv6_addr_label(struct net *net, const struct in6_addr *addr,
+                   int type, int ifindex);
 
 /*
  *     multicast prototypes (mcast.c)
  */
-extern int ipv6_sock_mc_join(struct sock *sk, int ifindex,
-                            const struct in6_addr *addr);
-extern int ipv6_sock_mc_drop(struct sock *sk, int ifindex,
-                            const struct in6_addr *addr);
-extern void ipv6_sock_mc_close(struct sock *sk);
-extern bool inet6_mc_check(struct sock *sk,
-                          const struct in6_addr *mc_addr,
-                          const struct in6_addr *src_addr);
-
-extern int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr);
-extern int __ipv6_dev_mc_dec(struct inet6_dev *idev, const struct in6_addr *addr);
-extern int ipv6_dev_mc_dec(struct net_device *dev, const struct in6_addr *addr);
-extern void ipv6_mc_up(struct inet6_dev *idev);
-extern void ipv6_mc_down(struct inet6_dev *idev);
-extern void ipv6_mc_unmap(struct inet6_dev *idev);
-extern void ipv6_mc_remap(struct inet6_dev *idev);
-extern void ipv6_mc_init_dev(struct inet6_dev *idev);
-extern void ipv6_mc_destroy_dev(struct inet6_dev *idev);
-extern void addrconf_dad_failure(struct inet6_ifaddr *ifp);
-
-extern bool ipv6_chk_mcast_addr(struct net_device *dev,
-                               const struct in6_addr *group,
-                               const struct in6_addr *src_addr);
-
-extern void ipv6_mc_dad_complete(struct inet6_dev *idev);
+int ipv6_sock_mc_join(struct sock *sk, int ifindex,
+                     const struct in6_addr *addr);
+int ipv6_sock_mc_drop(struct sock *sk, int ifindex,
+                     const struct in6_addr *addr);
+void ipv6_sock_mc_close(struct sock *sk);
+bool inet6_mc_check(struct sock *sk, const struct in6_addr *mc_addr,
+                   const struct in6_addr *src_addr);
+
+int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr);
+int __ipv6_dev_mc_dec(struct inet6_dev *idev, const struct in6_addr *addr);
+int ipv6_dev_mc_dec(struct net_device *dev, const struct in6_addr *addr);
+void ipv6_mc_up(struct inet6_dev *idev);
+void ipv6_mc_down(struct inet6_dev *idev);
+void ipv6_mc_unmap(struct inet6_dev *idev);
+void ipv6_mc_remap(struct inet6_dev *idev);
+void ipv6_mc_init_dev(struct inet6_dev *idev);
+void ipv6_mc_destroy_dev(struct inet6_dev *idev);
+void addrconf_dad_failure(struct inet6_ifaddr *ifp);
+
+bool ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group,
+                        const struct in6_addr *src_addr);
+
+void ipv6_mc_dad_complete(struct inet6_dev *idev);
 /*
  * identify MLD packets for MLD filter exceptions
  */
@@ -184,29 +166,31 @@ static inline bool ipv6_is_mld(struct sk_buff *skb, int nexthdr, int offset)
        return false;
 }
 
-extern void addrconf_prefix_rcv(struct net_device *dev,
-                               u8 *opt, int len, bool sllao);
+void addrconf_prefix_rcv(struct net_device *dev,
+                        u8 *opt, int len, bool sllao);
 
 /*
  *     anycast prototypes (anycast.c)
  */
-extern int ipv6_sock_ac_join(struct sock *sk,int ifindex, const struct in6_addr *addr);
-extern int ipv6_sock_ac_drop(struct sock *sk,int ifindex, const struct in6_addr *addr);
-extern void ipv6_sock_ac_close(struct sock *sk);
-
-extern int ipv6_dev_ac_inc(struct net_device *dev, const struct in6_addr *addr);
-extern int __ipv6_dev_ac_dec(struct inet6_dev *idev, const struct in6_addr *addr);
-extern bool ipv6_chk_acast_addr(struct net *net, struct net_device *dev,
+int ipv6_sock_ac_join(struct sock *sk, int ifindex,
+                     const struct in6_addr *addr);
+int ipv6_sock_ac_drop(struct sock *sk, int ifindex,
+                     const struct in6_addr *addr);
+void ipv6_sock_ac_close(struct sock *sk);
+
+int ipv6_dev_ac_inc(struct net_device *dev, const struct in6_addr *addr);
+int __ipv6_dev_ac_dec(struct inet6_dev *idev, const struct in6_addr *addr);
+bool ipv6_chk_acast_addr(struct net *net, struct net_device *dev,
                                const struct in6_addr *addr);
 
 
 /* Device notifier */
-extern int register_inet6addr_notifier(struct notifier_block *nb);
-extern int unregister_inet6addr_notifier(struct notifier_block *nb);
-extern int inet6addr_notifier_call_chain(unsigned long val, void *v);
+int register_inet6addr_notifier(struct notifier_block *nb);
+int unregister_inet6addr_notifier(struct notifier_block *nb);
+int inet6addr_notifier_call_chain(unsigned long val, void *v);
 
-extern void inet6_netconf_notify_devconf(struct net *net, int type, int ifindex,
-                                        struct ipv6_devconf *devconf);
+void inet6_netconf_notify_devconf(struct net *net, int type, int ifindex,
+                                 struct ipv6_devconf *devconf);
 
 /**
  * __in6_dev_get - get inet6_dev pointer from netdevice
@@ -240,7 +224,7 @@ static inline struct inet6_dev *in6_dev_get(const struct net_device *dev)
        return idev;
 }
 
-extern void in6_dev_finish_destroy(struct inet6_dev *idev);
+void in6_dev_finish_destroy(struct inet6_dev *idev);
 
 static inline void in6_dev_put(struct inet6_dev *idev)
 {
@@ -258,7 +242,7 @@ static inline void in6_dev_hold(struct inet6_dev *idev)
        atomic_inc(&idev->refcnt);
 }
 
-extern void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp);
+void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp);
 
 static inline void in6_ifa_put(struct inet6_ifaddr *ifp)
 {
@@ -340,8 +324,8 @@ static inline bool ipv6_addr_is_solict_mult(const struct in6_addr *addr)
 }
 
 #ifdef CONFIG_PROC_FS
-extern int if6_proc_init(void);
-extern void if6_proc_exit(void);
+int if6_proc_init(void);
+void if6_proc_exit(void);
 #endif
 
 #endif
index 03e6e94536231559b95b67bd1d9f99f313556459..e797d45a5ae62697361e1ca827a7638542cc4f41 100644 (file)
@@ -31,24 +31,21 @@ enum {
 
 typedef void (*rxrpc_interceptor_t)(struct sock *, unsigned long,
                                    struct sk_buff *);
-extern void rxrpc_kernel_intercept_rx_messages(struct socket *,
-                                              rxrpc_interceptor_t);
-extern struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *,
-                                                 struct sockaddr_rxrpc *,
-                                                 struct key *,
-                                                 unsigned long,
-                                                 gfp_t);
-extern int rxrpc_kernel_send_data(struct rxrpc_call *, struct msghdr *,
-                                 size_t);
-extern void rxrpc_kernel_abort_call(struct rxrpc_call *, u32);
-extern void rxrpc_kernel_end_call(struct rxrpc_call *);
-extern bool rxrpc_kernel_is_data_last(struct sk_buff *);
-extern u32 rxrpc_kernel_get_abort_code(struct sk_buff *);
-extern int rxrpc_kernel_get_error_number(struct sk_buff *);
-extern void rxrpc_kernel_data_delivered(struct sk_buff *);
-extern void rxrpc_kernel_free_skb(struct sk_buff *);
-extern struct rxrpc_call *rxrpc_kernel_accept_call(struct socket *,
-                                                  unsigned long);
-extern int rxrpc_kernel_reject_call(struct socket *);
+void rxrpc_kernel_intercept_rx_messages(struct socket *, rxrpc_interceptor_t);
+struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *,
+                                          struct sockaddr_rxrpc *,
+                                          struct key *,
+                                          unsigned long,
+                                          gfp_t);
+int rxrpc_kernel_send_data(struct rxrpc_call *, struct msghdr *, size_t);
+void rxrpc_kernel_abort_call(struct rxrpc_call *, u32);
+void rxrpc_kernel_end_call(struct rxrpc_call *);
+bool rxrpc_kernel_is_data_last(struct sk_buff *);
+u32 rxrpc_kernel_get_abort_code(struct sk_buff *);
+int rxrpc_kernel_get_error_number(struct sk_buff *);
+void rxrpc_kernel_data_delivered(struct sk_buff *);
+void rxrpc_kernel_free_skb(struct sk_buff *);
+struct rxrpc_call *rxrpc_kernel_accept_call(struct socket *, unsigned long);
+int rxrpc_kernel_reject_call(struct socket *);
 
 #endif /* _NET_RXRPC_H */
index dbdfd2b0f3b3dbe0a4470d83e19052db4ba3aa04..05442df4ca8937124759b2d028a066a812bfdb5e 100644 (file)
@@ -6,12 +6,12 @@
 #include <linux/mutex.h>
 #include <net/sock.h>
 
-extern void unix_inflight(struct file *fp);
-extern void unix_notinflight(struct file *fp);
-extern void unix_gc(void);
-extern void wait_for_unix_gc(void);
-extern struct sock *unix_get_socket(struct file *filp);
-extern struct sock *unix_peer_get(struct sock *);
+void unix_inflight(struct file *fp);
+void unix_notinflight(struct file *fp);
+void unix_gc(void);
+void wait_for_unix_gc(void);
+struct sock *unix_get_socket(struct file *filp);
+struct sock *unix_peer_get(struct sock *);
 
 #define UNIX_HASH_SIZE 256
 #define UNIX_HASH_BITS 8
@@ -71,8 +71,8 @@ long unix_inq_len(struct sock *sk);
 long unix_outq_len(struct sock *sk);
 
 #ifdef CONFIG_SYSCTL
-extern int unix_sysctl_register(struct net *net);
-extern void unix_sysctl_unregister(struct net *net);
+int unix_sysctl_register(struct net *net);
+void unix_sysctl_unregister(struct net *net);
 #else
 static inline int unix_sysctl_register(struct net *net) { return 0; }
 static inline void unix_sysctl_unregister(struct net *net) {}
index b630dae03411ae69694e842d75108a254c0584aa..7509d9da4e3631ee9f00fba4d27922ace90cb9ae 100644 (file)
@@ -46,22 +46,22 @@ static inline struct neighbour *__ipv4_neigh_lookup(struct net_device *dev, u32
        return n;
 }
 
-extern void    arp_init(void);
-extern int     arp_find(unsigned char *haddr, struct sk_buff *skb);
-extern int     arp_ioctl(struct net *net, unsigned int cmd, void __user *arg);
-extern void     arp_send(int type, int ptype, __be32 dest_ip,
-                        struct net_device *dev, __be32 src_ip,
-                        const unsigned char *dest_hw,
-                        const unsigned char *src_hw, const unsigned char *th);
-extern int     arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir);
-extern void    arp_ifdown(struct net_device *dev);
+void arp_init(void);
+int arp_find(unsigned char *haddr, struct sk_buff *skb);
+int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg);
+void arp_send(int type, int ptype, __be32 dest_ip,
+             struct net_device *dev, __be32 src_ip,
+             const unsigned char *dest_hw,
+             const unsigned char *src_hw, const unsigned char *th);
+int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir);
+void arp_ifdown(struct net_device *dev);
 
-extern struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip,
-                                 struct net_device *dev, __be32 src_ip,
-                                 const unsigned char *dest_hw,
-                                 const unsigned char *src_hw,
-                                 const unsigned char *target_hw);
-extern void arp_xmit(struct sk_buff *skb);
+struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip,
+                          struct net_device *dev, __be32 src_ip,
+                          const unsigned char *dest_hw,
+                          const unsigned char *src_hw,
+                          const unsigned char *target_hw);
+void arp_xmit(struct sk_buff *skb);
 int arp_invalidate(struct net_device *dev, __be32 ip);
 
 #endif /* _ARP_H */
index 89ed9ac5701fcc3c309890bb3403eef85c97a63e..bf0396e9a5d3f3c946b30a64c030c9f5c4f17ca0 100644 (file)
@@ -195,7 +195,7 @@ static inline void ax25_hold_route(ax25_route *ax25_rt)
        atomic_inc(&ax25_rt->refcount);
 }
 
-extern void __ax25_put_route(ax25_route *ax25_rt);
+void __ax25_put_route(ax25_route *ax25_rt);
 
 static inline void ax25_put_route(ax25_route *ax25_rt)
 {
@@ -272,30 +272,31 @@ static inline __be16 ax25_type_trans(struct sk_buff *skb, struct net_device *dev
 /* af_ax25.c */
 extern struct hlist_head ax25_list;
 extern spinlock_t ax25_list_lock;
-extern void ax25_cb_add(ax25_cb *);
+void ax25_cb_add(ax25_cb *);
 struct sock *ax25_find_listener(ax25_address *, int, struct net_device *, int);
 struct sock *ax25_get_socket(ax25_address *, ax25_address *, int);
-extern ax25_cb *ax25_find_cb(ax25_address *, ax25_address *, ax25_digi *, struct net_device *);
-extern void ax25_send_to_raw(ax25_address *, struct sk_buff *, int);
-extern void ax25_destroy_socket(ax25_cb *);
-extern ax25_cb * __must_check ax25_create_cb(void);
-extern void ax25_fillin_cb(ax25_cb *, ax25_dev *);
-extern struct sock *ax25_make_new(struct sock *, struct ax25_dev *);
+ax25_cb *ax25_find_cb(ax25_address *, ax25_address *, ax25_digi *,
+                     struct net_device *);
+void ax25_send_to_raw(ax25_address *, struct sk_buff *, int);
+void ax25_destroy_socket(ax25_cb *);
+ax25_cb * __must_check ax25_create_cb(void);
+void ax25_fillin_cb(ax25_cb *, ax25_dev *);
+struct sock *ax25_make_new(struct sock *, struct ax25_dev *);
 
 /* ax25_addr.c */
 extern const ax25_address ax25_bcast;
 extern const ax25_address ax25_defaddr;
 extern const ax25_address null_ax25_address;
-extern char *ax2asc(char *buf, const ax25_address *);
-extern void asc2ax(ax25_address *addr, const char *callsign);
-extern int ax25cmp(const ax25_address *, const ax25_address *);
-extern int ax25digicmp(const ax25_digi *, const ax25_digi *);
-extern const unsigned char *ax25_addr_parse(const unsigned char *, int,
+char *ax2asc(char *buf, const ax25_address *);
+void asc2ax(ax25_address *addr, const char *callsign);
+int ax25cmp(const ax25_address *, const ax25_address *);
+int ax25digicmp(const ax25_digi *, const ax25_digi *);
+const unsigned char *ax25_addr_parse(const unsigned char *, int,
        ax25_address *, ax25_address *, ax25_digi *, int *, int *);
-extern int  ax25_addr_build(unsigned char *, const ax25_address *,
-       const ax25_address *, const ax25_digi *, int, int);
-extern int  ax25_addr_size(const ax25_digi *);
-extern void ax25_digi_invert(const ax25_digi *, ax25_digi *);
+int ax25_addr_build(unsigned char *, const ax25_address *,
+                   const ax25_address *, const ax25_digi *, int, int);
+int ax25_addr_size(const ax25_digi *);
+void ax25_digi_invert(const ax25_digi *, ax25_digi *);
 
 /* ax25_dev.c */
 extern ax25_dev *ax25_dev_list;
@@ -306,33 +307,33 @@ static inline ax25_dev *ax25_dev_ax25dev(struct net_device *dev)
        return dev->ax25_ptr;
 }
 
-extern ax25_dev *ax25_addr_ax25dev(ax25_address *);
-extern void ax25_dev_device_up(struct net_device *);
-extern void ax25_dev_device_down(struct net_device *);
-extern int  ax25_fwd_ioctl(unsigned int, struct ax25_fwd_struct *);
-extern struct net_device *ax25_fwd_dev(struct net_device *);
-extern void ax25_dev_free(void);
+ax25_dev *ax25_addr_ax25dev(ax25_address *);
+void ax25_dev_device_up(struct net_device *);
+void ax25_dev_device_down(struct net_device *);
+int ax25_fwd_ioctl(unsigned int, struct ax25_fwd_struct *);
+struct net_device *ax25_fwd_dev(struct net_device *);
+void ax25_dev_free(void);
 
 /* ax25_ds_in.c */
-extern int  ax25_ds_frame_in(ax25_cb *, struct sk_buff *, int);
+int ax25_ds_frame_in(ax25_cb *, struct sk_buff *, int);
 
 /* ax25_ds_subr.c */
-extern void ax25_ds_nr_error_recovery(ax25_cb *);
-extern void ax25_ds_enquiry_response(ax25_cb *);
-extern void ax25_ds_establish_data_link(ax25_cb *);
-extern void ax25_dev_dama_off(ax25_dev *);
-extern void ax25_dama_on(ax25_cb *);
-extern void ax25_dama_off(ax25_cb *);
+void ax25_ds_nr_error_recovery(ax25_cb *);
+void ax25_ds_enquiry_response(ax25_cb *);
+void ax25_ds_establish_data_link(ax25_cb *);
+void ax25_dev_dama_off(ax25_dev *);
+void ax25_dama_on(ax25_cb *);
+void ax25_dama_off(ax25_cb *);
 
 /* ax25_ds_timer.c */
-extern void ax25_ds_setup_timer(ax25_dev *);
-extern void ax25_ds_set_timer(ax25_dev *);
-extern void ax25_ds_del_timer(ax25_dev *);
-extern void ax25_ds_timer(ax25_cb *);
-extern void ax25_ds_t1_timeout(ax25_cb *);
-extern void ax25_ds_heartbeat_expiry(ax25_cb *);
-extern void ax25_ds_t3timer_expiry(ax25_cb *);
-extern void ax25_ds_idletimer_expiry(ax25_cb *);
+void ax25_ds_setup_timer(ax25_dev *);
+void ax25_ds_set_timer(ax25_dev *);
+void ax25_ds_del_timer(ax25_dev *);
+void ax25_ds_timer(ax25_cb *);
+void ax25_ds_t1_timeout(ax25_cb *);
+void ax25_ds_heartbeat_expiry(ax25_cb *);
+void ax25_ds_t3timer_expiry(ax25_cb *);
+void ax25_ds_idletimer_expiry(ax25_cb *);
 
 /* ax25_iface.c */
 
@@ -342,107 +343,109 @@ struct ax25_protocol {
        int (*func)(struct sk_buff *, ax25_cb *);
 };
 
-extern void ax25_register_pid(struct ax25_protocol *ap);
-extern void ax25_protocol_release(unsigned int);
+void ax25_register_pid(struct ax25_protocol *ap);
+void ax25_protocol_release(unsigned int);
 
 struct ax25_linkfail {
        struct hlist_node lf_node;
        void (*func)(ax25_cb *, int);
 };
 
-extern void ax25_linkfail_register(struct ax25_linkfail *lf);
-extern void ax25_linkfail_release(struct ax25_linkfail *lf);
-extern int __must_check ax25_listen_register(ax25_address *,
-       struct net_device *);
-extern void ax25_listen_release(ax25_address *, struct net_device *);
-extern int  (*ax25_protocol_function(unsigned int))(struct sk_buff *, ax25_cb *);
-extern int  ax25_listen_mine(ax25_address *, struct net_device *);
-extern void ax25_link_failed(ax25_cb *, int);
-extern int  ax25_protocol_is_registered(unsigned int);
+void ax25_linkfail_register(struct ax25_linkfail *lf);
+void ax25_linkfail_release(struct ax25_linkfail *lf);
+int __must_check ax25_listen_register(ax25_address *, struct net_device *);
+void ax25_listen_release(ax25_address *, struct net_device *);
+int(*ax25_protocol_function(unsigned int))(struct sk_buff *, ax25_cb *);
+int ax25_listen_mine(ax25_address *, struct net_device *);
+void ax25_link_failed(ax25_cb *, int);
+int ax25_protocol_is_registered(unsigned int);
 
 /* ax25_in.c */
-extern int  ax25_rx_iframe(ax25_cb *, struct sk_buff *);
-extern int  ax25_kiss_rcv(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *);
+int ax25_rx_iframe(ax25_cb *, struct sk_buff *);
+int ax25_kiss_rcv(struct sk_buff *, struct net_device *, struct packet_type *,
+                 struct net_device *);
 
 /* ax25_ip.c */
-extern int ax25_hard_header(struct sk_buff *, struct net_device *,
-                           unsigned short, const void *,
-                           const void *, unsigned int);
-extern int  ax25_rebuild_header(struct sk_buff *);
+int ax25_hard_header(struct sk_buff *, struct net_device *, unsigned short,
+                    const void *, const void *, unsigned int);
+int ax25_rebuild_header(struct sk_buff *);
 extern const struct header_ops ax25_header_ops;
 
 /* ax25_out.c */
-extern ax25_cb *ax25_send_frame(struct sk_buff *, int, ax25_address *, ax25_address *, ax25_digi *, struct net_device *);
-extern void ax25_output(ax25_cb *, int, struct sk_buff *);
-extern void ax25_kick(ax25_cb *);
-extern void ax25_transmit_buffer(ax25_cb *, struct sk_buff *, int);
-extern void ax25_queue_xmit(struct sk_buff *skb, struct net_device *dev);
-extern int  ax25_check_iframes_acked(ax25_cb *, unsigned short);
+ax25_cb *ax25_send_frame(struct sk_buff *, int, ax25_address *, ax25_address *,
+                        ax25_digi *, struct net_device *);
+void ax25_output(ax25_cb *, int, struct sk_buff *);
+void ax25_kick(ax25_cb *);
+void ax25_transmit_buffer(ax25_cb *, struct sk_buff *, int);
+void ax25_queue_xmit(struct sk_buff *skb, struct net_device *dev);
+int ax25_check_iframes_acked(ax25_cb *, unsigned short);
 
 /* ax25_route.c */
-extern void ax25_rt_device_down(struct net_device *);
-extern int  ax25_rt_ioctl(unsigned int, void __user *);
+void ax25_rt_device_down(struct net_device *);
+int ax25_rt_ioctl(unsigned int, void __user *);
 extern const struct file_operations ax25_route_fops;
-extern ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev);
-extern int  ax25_rt_autobind(ax25_cb *, ax25_address *);
-extern struct sk_buff *ax25_rt_build_path(struct sk_buff *, ax25_address *, ax25_address *, ax25_digi *);
-extern void ax25_rt_free(void);
+ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev);
+int ax25_rt_autobind(ax25_cb *, ax25_address *);
+struct sk_buff *ax25_rt_build_path(struct sk_buff *, ax25_address *,
+                                  ax25_address *, ax25_digi *);
+void ax25_rt_free(void);
 
 /* ax25_std_in.c */
-extern int  ax25_std_frame_in(ax25_cb *, struct sk_buff *, int);
+int ax25_std_frame_in(ax25_cb *, struct sk_buff *, int);
 
 /* ax25_std_subr.c */
-extern void ax25_std_nr_error_recovery(ax25_cb *);
-extern void ax25_std_establish_data_link(ax25_cb *);
-extern void ax25_std_transmit_enquiry(ax25_cb *);
-extern void ax25_std_enquiry_response(ax25_cb *);
-extern void ax25_std_timeout_response(ax25_cb *);
+void ax25_std_nr_error_recovery(ax25_cb *);
+void ax25_std_establish_data_link(ax25_cb *);
+void ax25_std_transmit_enquiry(ax25_cb *);
+void ax25_std_enquiry_response(ax25_cb *);
+void ax25_std_timeout_response(ax25_cb *);
 
 /* ax25_std_timer.c */
-extern void ax25_std_heartbeat_expiry(ax25_cb *);
-extern void ax25_std_t1timer_expiry(ax25_cb *);
-extern void ax25_std_t2timer_expiry(ax25_cb *);
-extern void ax25_std_t3timer_expiry(ax25_cb *);
-extern void ax25_std_idletimer_expiry(ax25_cb *);
+void ax25_std_heartbeat_expiry(ax25_cb *);
+void ax25_std_t1timer_expiry(ax25_cb *);
+void ax25_std_t2timer_expiry(ax25_cb *);
+void ax25_std_t3timer_expiry(ax25_cb *);
+void ax25_std_idletimer_expiry(ax25_cb *);
 
 /* ax25_subr.c */
-extern void ax25_clear_queues(ax25_cb *);
-extern void ax25_frames_acked(ax25_cb *, unsigned short);
-extern void ax25_requeue_frames(ax25_cb *);
-extern int  ax25_validate_nr(ax25_cb *, unsigned short);
-extern int  ax25_decode(ax25_cb *, struct sk_buff *, int *, int *, int *);
-extern void ax25_send_control(ax25_cb *, int, int, int);
-extern void ax25_return_dm(struct net_device *, ax25_address *, ax25_address *, ax25_digi *);
-extern void ax25_calculate_t1(ax25_cb *);
-extern void ax25_calculate_rtt(ax25_cb *);
-extern void ax25_disconnect(ax25_cb *, int);
+void ax25_clear_queues(ax25_cb *);
+void ax25_frames_acked(ax25_cb *, unsigned short);
+void ax25_requeue_frames(ax25_cb *);
+int ax25_validate_nr(ax25_cb *, unsigned short);
+int ax25_decode(ax25_cb *, struct sk_buff *, int *, int *, int *);
+void ax25_send_control(ax25_cb *, int, int, int);
+void ax25_return_dm(struct net_device *, ax25_address *, ax25_address *,
+                   ax25_digi *);
+void ax25_calculate_t1(ax25_cb *);
+void ax25_calculate_rtt(ax25_cb *);
+void ax25_disconnect(ax25_cb *, int);
 
 /* ax25_timer.c */
-extern void ax25_setup_timers(ax25_cb *);
-extern void ax25_start_heartbeat(ax25_cb *);
-extern void ax25_start_t1timer(ax25_cb *);
-extern void ax25_start_t2timer(ax25_cb *);
-extern void ax25_start_t3timer(ax25_cb *);
-extern void ax25_start_idletimer(ax25_cb *);
-extern void ax25_stop_heartbeat(ax25_cb *);
-extern void ax25_stop_t1timer(ax25_cb *);
-extern void ax25_stop_t2timer(ax25_cb *);
-extern void ax25_stop_t3timer(ax25_cb *);
-extern void ax25_stop_idletimer(ax25_cb *);
-extern int  ax25_t1timer_running(ax25_cb *);
-extern unsigned long ax25_display_timer(struct timer_list *);
+void ax25_setup_timers(ax25_cb *);
+void ax25_start_heartbeat(ax25_cb *);
+void ax25_start_t1timer(ax25_cb *);
+void ax25_start_t2timer(ax25_cb *);
+void ax25_start_t3timer(ax25_cb *);
+void ax25_start_idletimer(ax25_cb *);
+void ax25_stop_heartbeat(ax25_cb *);
+void ax25_stop_t1timer(ax25_cb *);
+void ax25_stop_t2timer(ax25_cb *);
+void ax25_stop_t3timer(ax25_cb *);
+void ax25_stop_idletimer(ax25_cb *);
+int ax25_t1timer_running(ax25_cb *);
+unsigned long ax25_display_timer(struct timer_list *);
 
 /* ax25_uid.c */
 extern int  ax25_uid_policy;
-extern ax25_uid_assoc *ax25_findbyuid(kuid_t);
-extern int __must_check ax25_uid_ioctl(int, struct sockaddr_ax25 *);
+ax25_uid_assoc *ax25_findbyuid(kuid_t);
+int __must_check ax25_uid_ioctl(int, struct sockaddr_ax25 *);
 extern const struct file_operations ax25_uid_fops;
-extern void ax25_uid_free(void);
+void ax25_uid_free(void);
 
 /* sysctl_net_ax25.c */
 #ifdef CONFIG_SYSCTL
-extern int ax25_register_dev_sysctl(ax25_dev *ax25_dev);
-extern void ax25_unregister_dev_sysctl(ax25_dev *ax25_dev);
+int ax25_register_dev_sysctl(ax25_dev *ax25_dev);
+void ax25_unregister_dev_sysctl(ax25_dev *ax25_dev);
 #else
 static inline int ax25_register_dev_sysctl(ax25_dev *ax25_dev) { return 0; }
 static inline void ax25_unregister_dev_sysctl(ax25_dev *ax25_dev) {}
index 3c592cf473dae89f5fb529bcfdeb445612604622..a01fbb4a04992f14cd5357413f4018aa4f8313ec 100644 (file)
@@ -296,6 +296,12 @@ enum {
 #define HCI_AT_GENERAL_BONDING         0x04
 #define HCI_AT_GENERAL_BONDING_MITM    0x05
 
+/* I/O capabilities */
+#define HCI_IO_DISPLAY_ONLY    0x00
+#define HCI_IO_DISPLAY_YESNO   0x01
+#define HCI_IO_KEYBOARD_ONLY   0x02
+#define HCI_IO_NO_INPUT_OUTPUT 0x03
+
 /* Link Key types */
 #define HCI_LK_COMBINATION             0x00
 #define HCI_LK_LOCAL_UNIT              0x01
index a14339c2985ff0f24e259861fa39dcf335f601b5..f18b91966d3de718528ae3d44887e937514718fc 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/netdevice.h>
 #include <net/ip.h>
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
 
 struct napi_struct;
 extern unsigned int sysctl_net_busy_read __read_mostly;
@@ -146,7 +146,7 @@ static inline void sk_mark_napi_id(struct sock *sk, struct sk_buff *skb)
        sk->sk_napi_id = skb->napi_id;
 }
 
-#else /* CONFIG_NET_LL_RX_POLL */
+#else /* CONFIG_NET_RX_BUSY_POLL */
 static inline unsigned long net_busy_loop_on(void)
 {
        return 0;
@@ -181,5 +181,10 @@ static inline bool busy_loop_timeout(unsigned long end_time)
        return true;
 }
 
-#endif /* CONFIG_NET_LL_RX_POLL */
+static inline bool sk_busy_loop(struct sock *sk, int nonblock)
+{
+       return false;
+}
+
+#endif /* CONFIG_NET_RX_BUSY_POLL */
 #endif /* _LINUX_NET_BUSY_POLL_H */
index 7b0730aeb892621abc6419ec9c345b141e184b71..2cb06a6c059fa6ac2f22028c04ebba4eea6ef9a8 100644 (file)
@@ -460,6 +460,33 @@ ieee80211_chandef_rate_flags(struct cfg80211_chan_def *chandef)
        return 0;
 }
 
+/**
+ * ieee80211_chandef_max_power - maximum transmission power for the chandef
+ *
+ * In some regulations, the transmit power may depend on the configured channel
+ * bandwidth which may be defined as dBm/MHz. This function returns the actual
+ * max_power for non-standard (20 MHz) channels.
+ *
+ * @chandef: channel definition for the channel
+ *
+ * Returns: maximum allowed transmission power in dBm for the chandef
+ */
+static inline int
+ieee80211_chandef_max_power(struct cfg80211_chan_def *chandef)
+{
+       switch (chandef->width) {
+       case NL80211_CHAN_WIDTH_5:
+               return min(chandef->chan->max_reg_power - 6,
+                          chandef->chan->max_power);
+       case NL80211_CHAN_WIDTH_10:
+               return min(chandef->chan->max_reg_power - 3,
+                          chandef->chan->max_power);
+       default:
+               break;
+       }
+       return chandef->chan->max_power;
+}
+
 /**
  * enum survey_info_flags - survey information flags
  *
@@ -490,7 +517,7 @@ enum survey_info_flags {
  * @channel: the channel this survey record reports, mandatory
  * @filled: bitflag of flags from &enum survey_info_flags
  * @noise: channel noise in dBm. This and all following fields are
- *     optional
+ *     optional
  * @channel_time: amount of time in ms the radio spent on the channel
  * @channel_time_busy: amount of time the primary channel was sensed busy
  * @channel_time_ext_busy: amount of time the extension channel was sensed busy
@@ -546,9 +573,9 @@ struct cfg80211_crypto_settings {
 /**
  * struct cfg80211_beacon_data - beacon data
  * @head: head portion of beacon (before TIM IE)
- *     or %NULL if not changed
+ *     or %NULL if not changed
  * @tail: tail portion of beacon (after TIM IE)
- *     or %NULL if not changed
+ *     or %NULL if not changed
  * @head_len: length of @head
  * @tail_len: length of @tail
  * @beacon_ies: extra information element(s) to add into Beacon frames or %NULL
@@ -764,7 +791,7 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
  * @STATION_INFO_PLINK_STATE: @plink_state filled
  * @STATION_INFO_SIGNAL: @signal filled
  * @STATION_INFO_TX_BITRATE: @txrate fields are filled
- *  (tx_bitrate, tx_bitrate_flags and tx_bitrate_mcs)
+ *     (tx_bitrate, tx_bitrate_flags and tx_bitrate_mcs)
  * @STATION_INFO_RX_PACKETS: @rx_packets filled with 32-bit value
  * @STATION_INFO_TX_PACKETS: @tx_packets filled with 32-bit value
  * @STATION_INFO_TX_RETRIES: @tx_retries filled
@@ -1285,6 +1312,7 @@ struct cfg80211_ssid {
  * @n_ssids: number of SSIDs
  * @channels: channels to scan on.
  * @n_channels: total number of channels to scan
+ * @scan_width: channel width for scanning
  * @ie: optional information element(s) to add into Probe Request or %NULL
  * @ie_len: length of ie in octets
  * @flags: bit field of flags controlling operation
@@ -1300,6 +1328,7 @@ struct cfg80211_scan_request {
        struct cfg80211_ssid *ssids;
        int n_ssids;
        u32 n_channels;
+       enum nl80211_bss_scan_width scan_width;
        const u8 *ie;
        size_t ie_len;
        u32 flags;
@@ -1333,6 +1362,7 @@ struct cfg80211_match_set {
  * @ssids: SSIDs to scan for (passed in the probe_reqs in active scans)
  * @n_ssids: number of SSIDs
  * @n_channels: total number of channels to scan
+ * @scan_width: channel width for scanning
  * @interval: interval between each scheduled scan cycle
  * @ie: optional information element(s) to add into Probe Request or %NULL
  * @ie_len: length of ie in octets
@@ -1352,6 +1382,7 @@ struct cfg80211_sched_scan_request {
        struct cfg80211_ssid *ssids;
        int n_ssids;
        u32 n_channels;
+       enum nl80211_bss_scan_width scan_width;
        u32 interval;
        const u8 *ie;
        size_t ie_len;
@@ -1403,6 +1434,7 @@ struct cfg80211_bss_ies {
  * for use in scan results and similar.
  *
  * @channel: channel this BSS is on
+ * @scan_width: width of the control channel
  * @bssid: BSSID of the BSS
  * @beacon_interval: the beacon interval as from the frame
  * @capability: the capability field in host byte order
@@ -1424,6 +1456,7 @@ struct cfg80211_bss_ies {
  */
 struct cfg80211_bss {
        struct ieee80211_channel *channel;
+       enum nl80211_bss_scan_width scan_width;
 
        const struct cfg80211_bss_ies __rcu *ies;
        const struct cfg80211_bss_ies __rcu *beacon_ies;
@@ -1509,7 +1542,7 @@ enum cfg80211_assoc_req_flags {
  * @prev_bssid: previous BSSID, if not %NULL use reassociate frame
  * @flags:  See &enum cfg80211_assoc_req_flags
  * @ht_capa:  HT Capabilities over-rides.  Values set in ht_capa_mask
- *   will be used in ht_capa.  Un-supported values will be ignored.
+ *     will be used in ht_capa.  Un-supported values will be ignored.
  * @ht_capa_mask:  The bits of ht_capa which are to be used.
  * @vht_capa: VHT capability override
  * @vht_capa_mask: VHT capability mask indicating which fields to use
@@ -1592,6 +1625,9 @@ struct cfg80211_disassoc_request {
  *     user space. Otherwise, port is marked authorized by default.
  * @basic_rates: bitmap of basic rates to use when creating the IBSS
  * @mcast_rate: per-band multicast rate index + 1 (0: disabled)
+ * @ht_capa:  HT Capabilities over-rides.  Values set in ht_capa_mask
+ *     will be used in ht_capa.  Un-supported values will be ignored.
+ * @ht_capa_mask:  The bits of ht_capa which are to be used.
  */
 struct cfg80211_ibss_params {
        u8 *ssid;
@@ -1605,6 +1641,8 @@ struct cfg80211_ibss_params {
        bool privacy;
        bool control_port;
        int mcast_rate[IEEE80211_NUM_BANDS];
+       struct ieee80211_ht_cap ht_capa;
+       struct ieee80211_ht_cap ht_capa_mask;
 };
 
 /**
@@ -1630,9 +1668,9 @@ struct cfg80211_ibss_params {
  * @key: WEP key for shared key authentication
  * @flags:  See &enum cfg80211_assoc_req_flags
  * @bg_scan_period:  Background scan period in seconds
- *   or -1 to indicate that default value is to be used.
+ *     or -1 to indicate that default value is to be used.
  * @ht_capa:  HT Capabilities over-rides.  Values set in ht_capa_mask
- *   will be used in ht_capa.  Un-supported values will be ignored.
+ *     will be used in ht_capa.  Un-supported values will be ignored.
  * @ht_capa_mask:  The bits of ht_capa which are to be used.
  * @vht_capa:  VHT Capability overrides
  * @vht_capa_mask: The bits of vht_capa which are to be used.
@@ -1698,7 +1736,7 @@ struct cfg80211_pmksa {
 };
 
 /**
- * struct cfg80211_wowlan_trig_pkt_pattern - packet pattern
+ * struct cfg80211_pkt_pattern - packet pattern
  * @mask: bitmask where to match pattern and where to ignore bytes,
  *     one bit per byte, in same format as nl80211
  * @pattern: bytes to match where bitmask is 1
@@ -1708,7 +1746,7 @@ struct cfg80211_pmksa {
  * Internal note: @mask and @pattern are allocated in one chunk of
  * memory, free @mask only!
  */
-struct cfg80211_wowlan_trig_pkt_pattern {
+struct cfg80211_pkt_pattern {
        u8 *mask, *pattern;
        int pattern_len;
        int pkt_offset;
@@ -1770,11 +1808,40 @@ struct cfg80211_wowlan {
        bool any, disconnect, magic_pkt, gtk_rekey_failure,
             eap_identity_req, four_way_handshake,
             rfkill_release;
-       struct cfg80211_wowlan_trig_pkt_pattern *patterns;
+       struct cfg80211_pkt_pattern *patterns;
        struct cfg80211_wowlan_tcp *tcp;
        int n_patterns;
 };
 
+/**
+ * struct cfg80211_coalesce_rules - Coalesce rule parameters
+ *
+ * This structure defines coalesce rule for the device.
+ * @delay: maximum coalescing delay in msecs.
+ * @condition: condition for packet coalescence.
+ *     see &enum nl80211_coalesce_condition.
+ * @patterns: array of packet patterns
+ * @n_patterns: number of patterns
+ */
+struct cfg80211_coalesce_rules {
+       int delay;
+       enum nl80211_coalesce_condition condition;
+       struct cfg80211_pkt_pattern *patterns;
+       int n_patterns;
+};
+
+/**
+ * struct cfg80211_coalesce - Packet coalescing settings
+ *
+ * This structure defines coalescing settings.
+ * @rules: array of coalesce rules
+ * @n_rules: number of rules
+ */
+struct cfg80211_coalesce {
+       struct cfg80211_coalesce_rules *rules;
+       int n_rules;
+};
+
 /**
  * struct cfg80211_wowlan_wakeup - wakeup report
  * @disconnect: woke up by getting disconnected
@@ -2071,6 +2138,7 @@ struct cfg80211_update_ft_ies_params {
  *     driver can take the most appropriate actions.
  * @crit_proto_stop: Indicates critical protocol no longer needs increased link
  *     reliability. This operation can not fail.
+ * @set_coalesce: Set coalesce parameters.
  */
 struct cfg80211_ops {
        int     (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -2306,6 +2374,8 @@ struct cfg80211_ops {
                                    u16 duration);
        void    (*crit_proto_stop)(struct wiphy *wiphy,
                                   struct wireless_dev *wdev);
+       int     (*set_coalesce)(struct wiphy *wiphy,
+                               struct cfg80211_coalesce *coalesce);
 };
 
 /*
@@ -2531,6 +2601,25 @@ struct wiphy_wowlan_support {
        const struct wiphy_wowlan_tcp_support *tcp;
 };
 
+/**
+ * struct wiphy_coalesce_support - coalesce support data
+ * @n_rules: maximum number of coalesce rules
+ * @max_delay: maximum supported coalescing delay in msecs
+ * @n_patterns: number of supported patterns in a rule
+ *     (see nl80211.h for the pattern definition)
+ * @pattern_max_len: maximum length of each pattern
+ * @pattern_min_len: minimum length of each pattern
+ * @max_pkt_offset: maximum Rx packet offset
+ */
+struct wiphy_coalesce_support {
+       int n_rules;
+       int max_delay;
+       int n_patterns;
+       int pattern_max_len;
+       int pattern_min_len;
+       int max_pkt_offset;
+};
+
 /**
  * struct wiphy - wireless hardware description
  * @reg_notifier: the driver's regulatory notification callback,
@@ -2641,6 +2730,7 @@ struct wiphy_wowlan_support {
  *     802.11-2012 8.4.2.29 for the defined fields.
  * @extended_capabilities_mask: mask of the valid values
  * @extended_capabilities_len: length of the extended capabilities
+ * @coalesce: packet coalescing support information
  */
 struct wiphy {
        /* assign these fields before you register the wiphy */
@@ -2750,6 +2840,8 @@ struct wiphy {
        const struct iw_handler_def *wext;
 #endif
 
+       const struct wiphy_coalesce_support *coalesce;
+
        char priv[0] __aligned(NETDEV_ALIGN);
 };
 
@@ -2841,7 +2933,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv);
  *
  * Return: A non-negative wiphy index or a negative error code.
  */
-extern int wiphy_register(struct wiphy *wiphy);
+int wiphy_register(struct wiphy *wiphy);
 
 /**
  * wiphy_unregister - deregister a wiphy from cfg80211
@@ -2852,14 +2944,14 @@ extern int wiphy_register(struct wiphy *wiphy);
  * pointer, but the call may sleep to wait for an outstanding
  * request that is being handled.
  */
-extern void wiphy_unregister(struct wiphy *wiphy);
+void wiphy_unregister(struct wiphy *wiphy);
 
 /**
  * wiphy_free - free wiphy
  *
  * @wiphy: The wiphy to free
  */
-extern void wiphy_free(struct wiphy *wiphy);
+void wiphy_free(struct wiphy *wiphy);
 
 /* internal structs */
 struct cfg80211_conn;
@@ -3014,14 +3106,14 @@ static inline void *wdev_priv(struct wireless_dev *wdev)
  * @band: band, necessary due to channel number overlap
  * Return: The corresponding frequency (in MHz), or 0 if the conversion failed.
  */
-extern int ieee80211_channel_to_frequency(int chan, enum ieee80211_band band);
+int ieee80211_channel_to_frequency(int chan, enum ieee80211_band band);
 
 /**
  * ieee80211_frequency_to_channel - convert frequency to channel number
  * @freq: center frequency
  * Return: The corresponding channel, or 0 if the conversion failed.
  */
-extern int ieee80211_frequency_to_channel(int freq);
+int ieee80211_frequency_to_channel(int freq);
 
 /*
  * Name indirection necessary because the ieee80211 code also has
@@ -3030,8 +3122,8 @@ extern int ieee80211_frequency_to_channel(int freq);
  * to include both header files you'll (rightfully!) get a symbol
  * clash.
  */
-extern struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy,
-                                                        int freq);
+struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy,
+                                                 int freq);
 /**
  * ieee80211_get_channel - get channel struct from wiphy for specified frequency
  * @wiphy: the struct wiphy to get the channel for
@@ -3063,11 +3155,13 @@ ieee80211_get_response_rate(struct ieee80211_supported_band *sband,
 /**
  * ieee80211_mandatory_rates - get mandatory rates for a given band
  * @sband: the band to look for rates in
+ * @scan_width: width of the control channel
  *
  * This function returns a bitmap of the mandatory rates for the given
  * band, bits are set according to the rate position in the bitrates array.
  */
-u32 ieee80211_mandatory_rates(struct ieee80211_supported_band *sband);
+u32 ieee80211_mandatory_rates(struct ieee80211_supported_band *sband,
+                             enum nl80211_bss_scan_width scan_width);
 
 /*
  * Radiotap parsing functions -- for controlled injection support
@@ -3141,13 +3235,14 @@ struct ieee80211_radiotap_iterator {
        int _reset_on_ext;
 };
 
-extern int ieee80211_radiotap_iterator_init(
-       struct ieee80211_radiotap_iterator *iterator,
-       struct ieee80211_radiotap_header *radiotap_header,
-       int max_length, const struct ieee80211_radiotap_vendor_namespaces *vns);
+int
+ieee80211_radiotap_iterator_init(struct ieee80211_radiotap_iterator *iterator,
+                                struct ieee80211_radiotap_header *radiotap_header,
+                                int max_length,
+                                const struct ieee80211_radiotap_vendor_namespaces *vns);
 
-extern int ieee80211_radiotap_iterator_next(
-       struct ieee80211_radiotap_iterator *iterator);
+int
+ieee80211_radiotap_iterator_next(struct ieee80211_radiotap_iterator *iterator);
 
 
 extern const unsigned char rfc1042_header[6];
@@ -3307,7 +3402,7 @@ const u8 *cfg80211_find_vendor_ie(unsigned int oui, u8 oui_type,
  *
  * Return: 0 on success. -ENOMEM.
  */
-extern int regulatory_hint(struct wiphy *wiphy, const char *alpha2);
+int regulatory_hint(struct wiphy *wiphy, const char *alpha2);
 
 /**
  * wiphy_apply_custom_regulatory - apply a custom driver regulatory domain
@@ -3321,9 +3416,8 @@ extern int regulatory_hint(struct wiphy *wiphy, const char *alpha2);
  * default channel settings will be disregarded. If no rule is found for a
  * channel on the regulatory domain the channel will be disabled.
  */
-extern void wiphy_apply_custom_regulatory(
-       struct wiphy *wiphy,
-       const struct ieee80211_regdomain *regd);
+void wiphy_apply_custom_regulatory(struct wiphy *wiphy,
+                                  const struct ieee80211_regdomain *regd);
 
 /**
  * freq_reg_info - get regulatory information for the given frequency
@@ -3379,10 +3473,11 @@ void cfg80211_sched_scan_results(struct wiphy *wiphy);
 void cfg80211_sched_scan_stopped(struct wiphy *wiphy);
 
 /**
- * cfg80211_inform_bss_frame - inform cfg80211 of a received BSS frame
+ * cfg80211_inform_bss_width_frame - inform cfg80211 of a received BSS frame
  *
  * @wiphy: the wiphy reporting the BSS
  * @channel: The channel the frame was received on
+ * @scan_width: width of the control channel
  * @mgmt: the management frame (probe response or beacon)
  * @len: length of the management frame
  * @signal: the signal strength, type depends on the wiphy's signal_type
@@ -3395,16 +3490,29 @@ void cfg80211_sched_scan_stopped(struct wiphy *wiphy);
  * Or %NULL on error.
  */
 struct cfg80211_bss * __must_check
+cfg80211_inform_bss_width_frame(struct wiphy *wiphy,
+                               struct ieee80211_channel *channel,
+                               enum nl80211_bss_scan_width scan_width,
+                               struct ieee80211_mgmt *mgmt, size_t len,
+                               s32 signal, gfp_t gfp);
+
+static inline struct cfg80211_bss * __must_check
 cfg80211_inform_bss_frame(struct wiphy *wiphy,
                          struct ieee80211_channel *channel,
                          struct ieee80211_mgmt *mgmt, size_t len,
-                         s32 signal, gfp_t gfp);
+                         s32 signal, gfp_t gfp)
+{
+       return cfg80211_inform_bss_width_frame(wiphy, channel,
+                                              NL80211_BSS_CHAN_WIDTH_20,
+                                              mgmt, len, signal, gfp);
+}
 
 /**
  * cfg80211_inform_bss - inform cfg80211 of a new BSS
  *
  * @wiphy: the wiphy reporting the BSS
  * @channel: The channel the frame was received on
+ * @scan_width: width of the control channel
  * @bssid: the BSSID of the BSS
  * @tsf: the TSF sent by the peer in the beacon/probe response (or 0)
  * @capability: the capability field sent by the peer
@@ -3421,11 +3529,26 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
  * Or %NULL on error.
  */
 struct cfg80211_bss * __must_check
+cfg80211_inform_bss_width(struct wiphy *wiphy,
+                         struct ieee80211_channel *channel,
+                         enum nl80211_bss_scan_width scan_width,
+                         const u8 *bssid, u64 tsf, u16 capability,
+                         u16 beacon_interval, const u8 *ie, size_t ielen,
+                         s32 signal, gfp_t gfp);
+
+static inline struct cfg80211_bss * __must_check
 cfg80211_inform_bss(struct wiphy *wiphy,
                    struct ieee80211_channel *channel,
                    const u8 *bssid, u64 tsf, u16 capability,
                    u16 beacon_interval, const u8 *ie, size_t ielen,
-                   s32 signal, gfp_t gfp);
+                   s32 signal, gfp_t gfp)
+{
+       return cfg80211_inform_bss_width(wiphy, channel,
+                                        NL80211_BSS_CHAN_WIDTH_20,
+                                        bssid, tsf, capability,
+                                        beacon_interval, ie, ielen, signal,
+                                        gfp);
+}
 
 struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
                                      struct ieee80211_channel *channel,
@@ -3471,6 +3594,19 @@ void cfg80211_put_bss(struct wiphy *wiphy, struct cfg80211_bss *bss);
  */
 void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *bss);
 
+static inline enum nl80211_bss_scan_width
+cfg80211_chandef_to_scan_width(const struct cfg80211_chan_def *chandef)
+{
+       switch (chandef->width) {
+       case NL80211_CHAN_WIDTH_5:
+               return NL80211_BSS_CHAN_WIDTH_5;
+       case NL80211_CHAN_WIDTH_10:
+               return NL80211_BSS_CHAN_WIDTH_10;
+       default:
+               return NL80211_BSS_CHAN_WIDTH_20;
+       }
+}
+
 /**
  * cfg80211_rx_mlme_mgmt - notification of processed MLME management frame
  * @dev: network device
index 600d1d705bb86f23b00a8d0feebabe6ea303934d..8f59ca50477c6424c6a21d8a5f5ca60af62c7d32 100644 (file)
@@ -107,11 +107,11 @@ static inline void csum_replace2(__sum16 *sum, __be16 from, __be16 to)
 }
 
 struct sk_buff;
-extern void inet_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
-                                    __be32 from, __be32 to, int pseudohdr);
-extern void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb,
-                                     const __be32 *from, const __be32 *to,
-                                     int pseudohdr);
+void inet_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
+                             __be32 from, __be32 to, int pseudohdr);
+void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb,
+                              const __be32 *from, const __be32 *to,
+                              int pseudohdr);
 
 static inline void inet_proto_csum_replace2(__sum16 *sum, struct sk_buff *skb,
                                            __be16 from, __be16 to,
index 0fee0617fb7d243728583ee351de284f36aca14a..f55c14510bd60e06930e1f95850b0d9ea6d38649 100644 (file)
@@ -24,7 +24,7 @@ struct cgroup_cls_state
        u32 classid;
 };
 
-extern void sock_update_classid(struct sock *sk);
+void sock_update_classid(struct sock *sk);
 
 #if IS_BUILTIN(CONFIG_NET_CLS_CGROUP)
 static inline u32 task_cls_classid(struct task_struct *p)
index e361f4882426d26fa8e21dd20e9a6a285c578546..2f286dce92595b3712ac7c44c7267607f9b81ec6 100644 (file)
@@ -18,6 +18,7 @@ struct fib_rule {
        u32                     pref;
        u32                     flags;
        u32                     table;
+       u8                      table_prefixlen_min;
        u8                      action;
        u32                     target;
        struct fib_rule __rcu   *ctarget;
@@ -46,6 +47,8 @@ struct fib_rules_ops {
        int                     (*action)(struct fib_rule *,
                                          struct flowi *, int,
                                          struct fib_lookup_arg *);
+       bool                    (*suppress)(struct fib_rule *,
+                                           struct fib_lookup_arg *);
        int                     (*match)(struct fib_rule *,
                                         struct flowi *, int);
        int                     (*configure)(struct fib_rule *,
@@ -80,6 +83,7 @@ struct fib_rules_ops {
        [FRA_FWMARK]    = { .type = NLA_U32 }, \
        [FRA_FWMASK]    = { .type = NLA_U32 }, \
        [FRA_TABLE]     = { .type = NLA_U32 }, \
+       [FRA_TABLE_PREFIXLEN_MIN] = { .type = NLA_U8 }, \
        [FRA_GOTO]      = { .type = NLA_U32 }
 
 static inline void fib_rule_get(struct fib_rule *rule)
index c6d07cb074bc3ed04ec8ba76e417248814196e8c..8b5b714332971c547faa032574f56010f7ae3e15 100644 (file)
@@ -230,6 +230,10 @@ enum ieee80211_radiotap_type {
 #define        IEEE80211_CHAN_PASSIVE  0x0200  /* Only passive scan allowed */
 #define        IEEE80211_CHAN_DYN      0x0400  /* Dynamic CCK-OFDM channel */
 #define        IEEE80211_CHAN_GFSK     0x0800  /* GFSK channel (FHSS PHY) */
+#define        IEEE80211_CHAN_GSM      0x1000  /* GSM (900 MHz) */
+#define        IEEE80211_CHAN_STURBO   0x2000  /* Static Turbo */
+#define        IEEE80211_CHAN_HALF     0x4000  /* Half channel (10 MHz wide) */
+#define        IEEE80211_CHAN_QUARTER  0x8000  /* Quarter channel (5 MHz wide) */
 
 /* For IEEE80211_RADIOTAP_FLAGS */
 #define        IEEE80211_RADIOTAP_F_CFP        0x01    /* sent/received
index 2a601e7da1bfc8b97490075531975dcdfebc8370..48ec25a7fcb60a09a2c323c70221a31853a82261 100644 (file)
@@ -300,7 +300,7 @@ extern void                 inet6_rt_notify(int event, struct rt6_info *rt,
                                                struct nl_info *info);
 
 extern void                    fib6_run_gc(unsigned long expires,
-                                           struct net *net);
+                                           struct net *net, bool force);
 
 extern void                    fib6_gc_cleanup(void);
 
index 5b7a3dadaddec1b7cabb919a1cf9919b90ff638d..e6905e7c0a1460f08a2a569ba5f2f87d73b41837 100644 (file)
@@ -811,6 +811,8 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
  * @RX_FLAG_AMPDU_DELIM_CRC_KNOWN: The delimiter CRC field is known (the CRC
  *     is stored in the @ampdu_delimiter_crc field)
  * @RX_FLAG_STBC_MASK: STBC 2 bit bitmask. 1 - Nss=1, 2 - Nss=2, 3 - Nss=3
+ * @RX_FLAG_10MHZ: 10 MHz (half channel) was used
+ * @RX_FLAG_5MHZ: 5 MHz (quarter channel) was used
  */
 enum mac80211_rx_flags {
        RX_FLAG_MMIC_ERROR              = BIT(0),
@@ -839,6 +841,8 @@ enum mac80211_rx_flags {
        RX_FLAG_80P80MHZ                = BIT(24),
        RX_FLAG_160MHZ                  = BIT(25),
        RX_FLAG_STBC_MASK               = BIT(26) | BIT(27),
+       RX_FLAG_10MHZ                   = BIT(28),
+       RX_FLAG_5MHZ                    = BIT(29),
 };
 
 #define RX_FLAG_STBC_SHIFT             26
@@ -1004,11 +1008,11 @@ enum ieee80211_smps_mode {
  * @radar_enabled: whether radar detection is enabled
  *
  * @long_frame_max_tx_count: Maximum number of transmissions for a "long" frame
- *    (a frame not RTS protected), called "dot11LongRetryLimit" in 802.11,
- *    but actually means the number of transmissions not the number of retries
+ *     (a frame not RTS protected), called "dot11LongRetryLimit" in 802.11,
+ *     but actually means the number of transmissions not the number of retries
  * @short_frame_max_tx_count: Maximum number of transmissions for a "short"
- *    frame, called "dot11ShortRetryLimit" in 802.11, but actually means the
- *    number of transmissions not the number of retries
+ *     frame, called "dot11ShortRetryLimit" in 802.11, but actually means the
+ *     number of transmissions not the number of retries
  *
  * @smps_mode: spatial multiplexing powersave mode; note that
  *     %IEEE80211_SMPS_STATIC is used when the device is not
@@ -1092,7 +1096,7 @@ enum ieee80211_vif_flags {
  *     be off when it is %NULL there can still be races and packets could be
  *     processed after it switches back to %NULL.
  * @debugfs_dir: debugfs dentry, can be used by drivers to create own per
- *      interface debug files. Note that it will be NULL for the virtual
+ *     interface debug files. Note that it will be NULL for the virtual
  *     monitor interface (if that is requested.)
  * @drv_priv: data area for driver use, will always be aligned to
  *     sizeof(void *).
@@ -1425,10 +1429,10 @@ struct ieee80211_tx_control {
  *     the stack.
  *
  * @IEEE80211_HW_CONNECTION_MONITOR:
- *      The hardware performs its own connection monitoring, including
- *      periodic keep-alives to the AP and probing the AP on beacon loss.
- *      When this flag is set, signaling beacon-loss will cause an immediate
- *      change to disassociated state.
+ *     The hardware performs its own connection monitoring, including
+ *     periodic keep-alives to the AP and probing the AP on beacon loss.
+ *     When this flag is set, signaling beacon-loss will cause an immediate
+ *     change to disassociated state.
  *
  * @IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC:
  *     This device needs to get data from beacon before association (i.e.
@@ -1526,10 +1530,10 @@ enum ieee80211_hw_flags {
  * @channel_change_time: time (in microseconds) it takes to change channels.
  *
  * @max_signal: Maximum value for signal (rssi) in RX information, used
- *     only when @IEEE80211_HW_SIGNAL_UNSPEC or @IEEE80211_HW_SIGNAL_DB
+ *     only when @IEEE80211_HW_SIGNAL_UNSPEC or @IEEE80211_HW_SIGNAL_DB
  *
  * @max_listen_interval: max listen interval in units of beacon interval
- *     that HW supports
+ *     that HW supports
  *
  * @queues: number of available hardware transmit queues for
  *     data packets. WMM/QoS requires at least four, these
@@ -2443,7 +2447,7 @@ enum ieee80211_roc_type {
  *     The callback can sleep.
  *
  * @set_tsf: Set the TSF timer to the specified value in the firmware/hardware.
- *      Currently, this is only used for IBSS mode debugging. Is not a
+ *     Currently, this is only used for IBSS mode debugging. Is not a
  *     required function.
  *     The callback can sleep.
  *
@@ -2877,14 +2881,14 @@ enum ieee80211_tpt_led_trigger_flags {
 };
 
 #ifdef CONFIG_MAC80211_LEDS
-extern char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw);
-extern char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw);
-extern char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw);
-extern char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw);
-extern char *__ieee80211_create_tpt_led_trigger(
-                               struct ieee80211_hw *hw, unsigned int flags,
-                               const struct ieee80211_tpt_blink *blink_table,
-                               unsigned int blink_table_len);
+char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw);
+char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw);
+char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw);
+char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw);
+char *__ieee80211_create_tpt_led_trigger(struct ieee80211_hw *hw,
+                                        unsigned int flags,
+                                        const struct ieee80211_tpt_blink *blink_table,
+                                        unsigned int blink_table_len);
 #endif
 /**
  * ieee80211_get_tx_led_name - get name of TX LED
@@ -4204,8 +4208,10 @@ struct rate_control_ops {
 
        void *(*alloc_sta)(void *priv, struct ieee80211_sta *sta, gfp_t gfp);
        void (*rate_init)(void *priv, struct ieee80211_supported_band *sband,
+                         struct cfg80211_chan_def *chandef,
                          struct ieee80211_sta *sta, void *priv_sta);
        void (*rate_update)(void *priv, struct ieee80211_supported_band *sband,
+                           struct cfg80211_chan_def *chandef,
                            struct ieee80211_sta *sta, void *priv_sta,
                            u32 changed);
        void (*free_sta)(void *priv, struct ieee80211_sta *sta,
index 949d77528f2f9cd87839029b424bded13cb52136..6fea32340ae8a5c697a18b7909c9b44d86cddeaf 100644 (file)
@@ -119,7 +119,7 @@ extern struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len,
  * if RFC 3831 IPv6-over-Fibre Channel is ever implemented it may
  * also need a pad of 2.
  */
-static int ndisc_addr_option_pad(unsigned short type)
+static inline int ndisc_addr_option_pad(unsigned short type)
 {
        switch (type) {
        case ARPHRD_INFINIBAND: return 2;
index 7e748ad8b50c71900bdcedaf09a8c69e41f567a3..536501a3e58d861211656b87ec2e0e9b0e4f9a47 100644 (file)
@@ -195,68 +195,67 @@ static inline void *neighbour_priv(const struct neighbour *n)
 #define NEIGH_UPDATE_F_ISROUTER                        0x40000000
 #define NEIGH_UPDATE_F_ADMIN                   0x80000000
 
-extern void                    neigh_table_init(struct neigh_table *tbl);
-extern int                     neigh_table_clear(struct neigh_table *tbl);
-extern struct neighbour *      neigh_lookup(struct neigh_table *tbl,
-                                            const void *pkey,
-                                            struct net_device *dev);
-extern struct neighbour *      neigh_lookup_nodev(struct neigh_table *tbl,
-                                                  struct net *net,
-                                                  const void *pkey);
-extern struct neighbour *      __neigh_create(struct neigh_table *tbl,
-                                              const void *pkey,
-                                              struct net_device *dev,
-                                              bool want_ref);
+void neigh_table_init(struct neigh_table *tbl);
+int neigh_table_clear(struct neigh_table *tbl);
+struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
+                              struct net_device *dev);
+struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net,
+                                    const void *pkey);
+struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey,
+                                struct net_device *dev, bool want_ref);
 static inline struct neighbour *neigh_create(struct neigh_table *tbl,
                                             const void *pkey,
                                             struct net_device *dev)
 {
        return __neigh_create(tbl, pkey, dev, true);
 }
-extern void                    neigh_destroy(struct neighbour *neigh);
-extern int                     __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb);
-extern int                     neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, 
-                                            u32 flags);
-extern void                    neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev);
-extern int                     neigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
-extern int                     neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb);
-extern int                     neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb);
-extern int                     neigh_compat_output(struct neighbour *neigh, struct sk_buff *skb);
-extern int                     neigh_direct_output(struct neighbour *neigh, struct sk_buff *skb);
-extern struct neighbour        *neigh_event_ns(struct neigh_table *tbl,
+void neigh_destroy(struct neighbour *neigh);
+int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb);
+int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, u32 flags);
+void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev);
+int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
+int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb);
+int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb);
+int neigh_compat_output(struct neighbour *neigh, struct sk_buff *skb);
+int neigh_direct_output(struct neighbour *neigh, struct sk_buff *skb);
+struct neighbour *neigh_event_ns(struct neigh_table *tbl,
                                                u8 *lladdr, void *saddr,
                                                struct net_device *dev);
 
-extern struct neigh_parms      *neigh_parms_alloc(struct net_device *dev, struct neigh_table *tbl);
-extern void                    neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms);
+struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
+                                     struct neigh_table *tbl);
+void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms);
 
 static inline
-struct net                     *neigh_parms_net(const struct neigh_parms *parms)
+struct net *neigh_parms_net(const struct neigh_parms *parms)
 {
        return read_pnet(&parms->net);
 }
 
-extern unsigned long           neigh_rand_reach_time(unsigned long base);
+unsigned long neigh_rand_reach_time(unsigned long base);
 
-extern void                    pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
-                                              struct sk_buff *skb);
-extern struct pneigh_entry     *pneigh_lookup(struct neigh_table *tbl, struct net *net, const void *key, struct net_device *dev, int creat);
-extern struct pneigh_entry     *__pneigh_lookup(struct neigh_table *tbl,
-                                                struct net *net,
-                                                const void *key,
-                                                struct net_device *dev);
-extern int                     pneigh_delete(struct neigh_table *tbl, struct net *net, const void *key, struct net_device *dev);
+void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
+                   struct sk_buff *skb);
+struct pneigh_entry *pneigh_lookup(struct neigh_table *tbl, struct net *net,
+                                  const void *key, struct net_device *dev,
+                                  int creat);
+struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl, struct net *net,
+                                    const void *key, struct net_device *dev);
+int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *key,
+                 struct net_device *dev);
 
-static inline
-struct net                     *pneigh_net(const struct pneigh_entry *pneigh)
+static inline struct net *pneigh_net(const struct pneigh_entry *pneigh)
 {
        return read_pnet(&pneigh->net);
 }
 
-extern void neigh_app_ns(struct neighbour *n);
-extern void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie);
-extern void __neigh_for_each_release(struct neigh_table *tbl, int (*cb)(struct neighbour *));
-extern void pneigh_for_each(struct neigh_table *tbl, void (*cb)(struct pneigh_entry *));
+void neigh_app_ns(struct neighbour *n);
+void neigh_for_each(struct neigh_table *tbl,
+                   void (*cb)(struct neighbour *, void *), void *cookie);
+void __neigh_for_each_release(struct neigh_table *tbl,
+                             int (*cb)(struct neighbour *));
+void pneigh_for_each(struct neigh_table *tbl,
+                    void (*cb)(struct pneigh_entry *));
 
 struct neigh_seq_state {
        struct seq_net_private p;
@@ -270,15 +269,14 @@ struct neigh_seq_state {
 #define NEIGH_SEQ_IS_PNEIGH    0x00000002
 #define NEIGH_SEQ_SKIP_NOARP   0x00000004
 };
-extern void *neigh_seq_start(struct seq_file *, loff_t *, struct neigh_table *, unsigned int);
-extern void *neigh_seq_next(struct seq_file *, void *, loff_t *);
-extern void neigh_seq_stop(struct seq_file *, void *);
-
-extern int                     neigh_sysctl_register(struct net_device *dev, 
-                                                     struct neigh_parms *p,
-                                                     char *p_name,
-                                                     proc_handler *proc_handler);
-extern void                    neigh_sysctl_unregister(struct neigh_parms *p);
+void *neigh_seq_start(struct seq_file *, loff_t *, struct neigh_table *,
+                     unsigned int);
+void *neigh_seq_next(struct seq_file *, void *, loff_t *);
+void neigh_seq_stop(struct seq_file *, void *);
+
+int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
+                         char *p_name, proc_handler *proc_handler);
+void neigh_sysctl_unregister(struct neigh_parms *p);
 
 static inline void __neigh_parms_put(struct neigh_parms *parms)
 {
index 84e37b1ca9e17824ef33ac4fa7708d684f520edc..1313456a0994e03cab0859e7960773b0115f8652 100644 (file)
@@ -119,7 +119,6 @@ struct net {
        struct netns_ipvs       *ipvs;
 #endif
        struct sock             *diag_nlsk;
-       atomic_t                rt_genid;
        atomic_t                fnhe_genid;
 };
 
@@ -333,14 +332,42 @@ static inline void unregister_net_sysctl_table(struct ctl_table_header *header)
 }
 #endif
 
-static inline int rt_genid(struct net *net)
+static inline int rt_genid_ipv4(struct net *net)
 {
-       return atomic_read(&net->rt_genid);
+       return atomic_read(&net->ipv4.rt_genid);
 }
 
-static inline void rt_genid_bump(struct net *net)
+static inline void rt_genid_bump_ipv4(struct net *net)
 {
-       atomic_inc(&net->rt_genid);
+       atomic_inc(&net->ipv4.rt_genid);
+}
+
+#if IS_ENABLED(CONFIG_IPV6)
+static inline int rt_genid_ipv6(struct net *net)
+{
+       return atomic_read(&net->ipv6.rt_genid);
+}
+
+static inline void rt_genid_bump_ipv6(struct net *net)
+{
+       atomic_inc(&net->ipv6.rt_genid);
+}
+#else
+static inline int rt_genid_ipv6(struct net *net)
+{
+       return 0;
+}
+
+static inline void rt_genid_bump_ipv6(struct net *net)
+{
+}
+#endif
+
+/* For callers who don't really care about whether it's IPv4 or IPv6 */
+static inline void rt_genid_bump_all(struct net *net)
+{
+       rt_genid_bump_ipv4(net);
+       rt_genid_bump_ipv6(net);
 }
 
 static inline int fnhe_genid(struct net *net)
index 2ba9de89e8ec778990e8b2ff5183fd3e97eee1aa..bf2ec2202c5698b1bb73e22df60b4a3bc9d95c01 100644 (file)
@@ -77,5 +77,6 @@ struct netns_ipv4 {
        struct fib_rules_ops    *mr_rules_ops;
 #endif
 #endif
+       atomic_t        rt_genid;
 };
 #endif
index 005e2c2e39a9022bad13f4205343263f1821cb22..0fb2401197c51ecf9dd041066975cf5f0bb6a264 100644 (file)
@@ -72,6 +72,7 @@ struct netns_ipv6 {
 #endif
 #endif
        atomic_t                dev_addr_genid;
+       atomic_t                rt_genid;
 };
 
 #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
index 50ab8c26ab59b7ebe840e50d6f696d16f32969b8..379dd5db0f2f3d08955a2632c90a0d9633732c31 100644 (file)
@@ -29,7 +29,7 @@ struct cgroup_netprio_state {
        struct cgroup_subsys_state css;
 };
 
-extern void sock_update_netprioidx(struct sock *sk);
+void sock_update_netprioidx(struct sock *sk);
 
 #if IS_BUILTIN(CONFIG_NETPRIO_CGROUP)
 
index 0af851c3b038186357b8576ec4025bb5193ee1fd..b64b7bce4b94302a8edb923bc54bc1e4b2c8b997 100644 (file)
@@ -59,7 +59,7 @@ struct nfc_hci_ops {
                              struct nfc_target *target);
        int (*event_received)(struct nfc_hci_dev *hdev, u8 gate, u8 event,
                              struct sk_buff *skb);
-       int (*fw_upload)(struct nfc_hci_dev *hdev, const char *firmware_name);
+       int (*fw_download)(struct nfc_hci_dev *hdev, const char *firmware_name);
        int (*discover_se)(struct nfc_hci_dev *dev);
        int (*enable_se)(struct nfc_hci_dev *dev, u32 se_idx);
        int (*disable_se)(struct nfc_hci_dev *dev, u32 se_idx);
index 0e353f1658bb46e638b287ee2bbfdbd33b37a584..5f286b726bb691b3f62e3b6800870ea940a3d65f 100644 (file)
@@ -68,7 +68,7 @@ struct nfc_ops {
                             void *cb_context);
        int (*tm_send)(struct nfc_dev *dev, struct sk_buff *skb);
        int (*check_presence)(struct nfc_dev *dev, struct nfc_target *target);
-       int (*fw_upload)(struct nfc_dev *dev, const char *firmware_name);
+       int (*fw_download)(struct nfc_dev *dev, const char *firmware_name);
 
        /* Secure Element API */
        int (*discover_se)(struct nfc_dev *dev);
@@ -127,7 +127,7 @@ struct nfc_dev {
        int targets_generation;
        struct device dev;
        bool dev_up;
-       bool fw_upload_in_progress;
+       bool fw_download_in_progress;
        u8 rf_mode;
        bool polling;
        struct nfc_target *active_target;
index 13174509cdfd38485a48f6fb1055f285a7306936..2ebef77a2f9a39e770237c19ebf2a7bc7bd324f3 100644 (file)
@@ -14,8 +14,8 @@ struct tcf_walker {
        int     (*fn)(struct tcf_proto *, unsigned long node, struct tcf_walker *);
 };
 
-extern int register_tcf_proto_ops(struct tcf_proto_ops *ops);
-extern int unregister_tcf_proto_ops(struct tcf_proto_ops *ops);
+int register_tcf_proto_ops(struct tcf_proto_ops *ops);
+int unregister_tcf_proto_ops(struct tcf_proto_ops *ops);
 
 static inline unsigned long
 __cls_set_class(unsigned long *clp, unsigned long cl)
@@ -126,17 +126,17 @@ tcf_exts_exec(struct sk_buff *skb, struct tcf_exts *exts,
        return 0;
 }
 
-extern int tcf_exts_validate(struct net *net, struct tcf_proto *tp,
-                            struct nlattr **tb, struct nlattr *rate_tlv,
-                            struct tcf_exts *exts,
-                            const struct tcf_ext_map *map);
-extern void tcf_exts_destroy(struct tcf_proto *tp, struct tcf_exts *exts);
-extern void tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst,
-                            struct tcf_exts *src);
-extern int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts,
-                        const struct tcf_ext_map *map);
-extern int tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts,
-                              const struct tcf_ext_map *map);
+int tcf_exts_validate(struct net *net, struct tcf_proto *tp,
+                     struct nlattr **tb, struct nlattr *rate_tlv,
+                     struct tcf_exts *exts,
+                     const struct tcf_ext_map *map);
+void tcf_exts_destroy(struct tcf_proto *tp, struct tcf_exts *exts);
+void tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst,
+                    struct tcf_exts *src);
+int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts,
+                 const struct tcf_ext_map *map);
+int tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts,
+                       const struct tcf_ext_map *map);
 
 /**
  * struct tcf_pkt_info - packet information
@@ -239,14 +239,14 @@ struct tcf_ematch_ops {
        struct list_head        link;
 };
 
-extern int tcf_em_register(struct tcf_ematch_ops *);
-extern void tcf_em_unregister(struct tcf_ematch_ops *);
-extern int tcf_em_tree_validate(struct tcf_proto *, struct nlattr *,
-                               struct tcf_ematch_tree *);
-extern void tcf_em_tree_destroy(struct tcf_proto *, struct tcf_ematch_tree *);
-extern int tcf_em_tree_dump(struct sk_buff *, struct tcf_ematch_tree *, int);
-extern int __tcf_em_tree_match(struct sk_buff *, struct tcf_ematch_tree *,
-                              struct tcf_pkt_info *);
+int tcf_em_register(struct tcf_ematch_ops *);
+void tcf_em_unregister(struct tcf_ematch_ops *);
+int tcf_em_tree_validate(struct tcf_proto *, struct nlattr *,
+                        struct tcf_ematch_tree *);
+void tcf_em_tree_destroy(struct tcf_proto *, struct tcf_ematch_tree *);
+int tcf_em_tree_dump(struct sk_buff *, struct tcf_ematch_tree *, int);
+int __tcf_em_tree_match(struct sk_buff *, struct tcf_ematch_tree *,
+                       struct tcf_pkt_info *);
 
 /**
  * tcf_em_tree_change - replace ematch tree of a running classifier
index 388bf8b6d06068558726943fa58d44a91ab01374..f7c24f8fbdc5c61208a26a11123f33d4d6d385df 100644 (file)
@@ -64,8 +64,8 @@ struct qdisc_watchdog {
        struct Qdisc    *qdisc;
 };
 
-extern void qdisc_watchdog_init(struct qdisc_watchdog *wd, struct Qdisc *qdisc);
-extern void qdisc_watchdog_schedule_ns(struct qdisc_watchdog *wd, u64 expires);
+void qdisc_watchdog_init(struct qdisc_watchdog *wd, struct Qdisc *qdisc);
+void qdisc_watchdog_schedule_ns(struct qdisc_watchdog *wd, u64 expires);
 
 static inline void qdisc_watchdog_schedule(struct qdisc_watchdog *wd,
                                           psched_time_t expires)
@@ -73,31 +73,31 @@ static inline void qdisc_watchdog_schedule(struct qdisc_watchdog *wd,
        qdisc_watchdog_schedule_ns(wd, PSCHED_TICKS2NS(expires));
 }
 
-extern void qdisc_watchdog_cancel(struct qdisc_watchdog *wd);
+void qdisc_watchdog_cancel(struct qdisc_watchdog *wd);
 
 extern struct Qdisc_ops pfifo_qdisc_ops;
 extern struct Qdisc_ops bfifo_qdisc_ops;
 extern struct Qdisc_ops pfifo_head_drop_qdisc_ops;
 
-extern int fifo_set_limit(struct Qdisc *q, unsigned int limit);
-extern struct Qdisc *fifo_create_dflt(struct Qdisc *sch, struct Qdisc_ops *ops,
-                                     unsigned int limit);
-
-extern int register_qdisc(struct Qdisc_ops *qops);
-extern int unregister_qdisc(struct Qdisc_ops *qops);
-extern void qdisc_list_del(struct Qdisc *q);
-extern struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle);
-extern struct Qdisc *qdisc_lookup_class(struct net_device *dev, u32 handle);
-extern struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r,
-               struct nlattr *tab);
-extern void qdisc_put_rtab(struct qdisc_rate_table *tab);
-extern void qdisc_put_stab(struct qdisc_size_table *tab);
-extern void qdisc_warn_nonwc(char *txt, struct Qdisc *qdisc);
-extern int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q,
-                          struct net_device *dev, struct netdev_queue *txq,
-                          spinlock_t *root_lock);
-
-extern void __qdisc_run(struct Qdisc *q);
+int fifo_set_limit(struct Qdisc *q, unsigned int limit);
+struct Qdisc *fifo_create_dflt(struct Qdisc *sch, struct Qdisc_ops *ops,
+                              unsigned int limit);
+
+int register_qdisc(struct Qdisc_ops *qops);
+int unregister_qdisc(struct Qdisc_ops *qops);
+void qdisc_list_del(struct Qdisc *q);
+struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle);
+struct Qdisc *qdisc_lookup_class(struct net_device *dev, u32 handle);
+struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r,
+                                       struct nlattr *tab);
+void qdisc_put_rtab(struct qdisc_rate_table *tab);
+void qdisc_put_stab(struct qdisc_size_table *tab);
+void qdisc_warn_nonwc(char *txt, struct Qdisc *qdisc);
+int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q,
+                   struct net_device *dev, struct netdev_queue *txq,
+                   spinlock_t *root_lock);
+
+void __qdisc_run(struct Qdisc *q);
 
 static inline void qdisc_run(struct Qdisc *q)
 {
@@ -105,10 +105,10 @@ static inline void qdisc_run(struct Qdisc *q)
                __qdisc_run(q);
 }
 
-extern int tc_classify_compat(struct sk_buff *skb, const struct tcf_proto *tp,
-                             struct tcf_result *res);
-extern int tc_classify(struct sk_buff *skb, const struct tcf_proto *tp,
+int tc_classify_compat(struct sk_buff *skb, const struct tcf_proto *tp,
                       struct tcf_result *res);
+int tc_classify(struct sk_buff *skb, const struct tcf_proto *tp,
+               struct tcf_result *res);
 
 /* Calculate maximal size of packet seen by hard_start_xmit
    routine of this device.
index 6eab63363e59fe82dc3fc6119633e5583b663dd1..ffc9d883b163eb299ea07c09b243e40c57066d33 100644 (file)
@@ -350,30 +350,32 @@ qdisc_class_find(const struct Qdisc_class_hash *hash, u32 id)
        return NULL;
 }
 
-extern int qdisc_class_hash_init(struct Qdisc_class_hash *);
-extern void qdisc_class_hash_insert(struct Qdisc_class_hash *, struct Qdisc_class_common *);
-extern void qdisc_class_hash_remove(struct Qdisc_class_hash *, struct Qdisc_class_common *);
-extern void qdisc_class_hash_grow(struct Qdisc *, struct Qdisc_class_hash *);
-extern void qdisc_class_hash_destroy(struct Qdisc_class_hash *);
-
-extern void dev_init_scheduler(struct net_device *dev);
-extern void dev_shutdown(struct net_device *dev);
-extern void dev_activate(struct net_device *dev);
-extern void dev_deactivate(struct net_device *dev);
-extern void dev_deactivate_many(struct list_head *head);
-extern struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue,
-                                    struct Qdisc *qdisc);
-extern void qdisc_reset(struct Qdisc *qdisc);
-extern void qdisc_destroy(struct Qdisc *qdisc);
-extern void qdisc_tree_decrease_qlen(struct Qdisc *qdisc, unsigned int n);
-extern struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
-                                struct Qdisc_ops *ops);
-extern struct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue,
-                                      struct Qdisc_ops *ops, u32 parentid);
-extern void __qdisc_calculate_pkt_len(struct sk_buff *skb,
-                                     const struct qdisc_size_table *stab);
-extern void tcf_destroy(struct tcf_proto *tp);
-extern void tcf_destroy_chain(struct tcf_proto **fl);
+int qdisc_class_hash_init(struct Qdisc_class_hash *);
+void qdisc_class_hash_insert(struct Qdisc_class_hash *,
+                            struct Qdisc_class_common *);
+void qdisc_class_hash_remove(struct Qdisc_class_hash *,
+                            struct Qdisc_class_common *);
+void qdisc_class_hash_grow(struct Qdisc *, struct Qdisc_class_hash *);
+void qdisc_class_hash_destroy(struct Qdisc_class_hash *);
+
+void dev_init_scheduler(struct net_device *dev);
+void dev_shutdown(struct net_device *dev);
+void dev_activate(struct net_device *dev);
+void dev_deactivate(struct net_device *dev);
+void dev_deactivate_many(struct list_head *head);
+struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue,
+                             struct Qdisc *qdisc);
+void qdisc_reset(struct Qdisc *qdisc);
+void qdisc_destroy(struct Qdisc *qdisc);
+void qdisc_tree_decrease_qlen(struct Qdisc *qdisc, unsigned int n);
+struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
+                         struct Qdisc_ops *ops);
+struct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue,
+                               struct Qdisc_ops *ops, u32 parentid);
+void __qdisc_calculate_pkt_len(struct sk_buff *skb,
+                              const struct qdisc_size_table *stab);
+void tcf_destroy(struct tcf_proto *tp);
+void tcf_destroy_chain(struct tcf_proto **fl);
 
 /* Reset all TX qdiscs greater then index of a device.  */
 static inline void qdisc_reset_all_tx_gt(struct net_device *dev, unsigned int i)
@@ -692,7 +694,8 @@ static inline u64 psched_l2t_ns(const struct psched_ratecfg *r,
        return ((u64)(len + r->overhead) * r->mult) >> r->shift;
 }
 
-extern void psched_ratecfg_precompute(struct psched_ratecfg *r, const struct tc_ratespec *conf);
+void psched_ratecfg_precompute(struct psched_ratecfg *r,
+                              const struct tc_ratespec *conf);
 
 static inline void psched_ratecfg_getrate(struct tc_ratespec *res,
                                          const struct psched_ratecfg *r)
index 49bc9577c61efbfcb8caf37e686def5f3de17c81..754c511f4cf9fe66516e163414d956a07561ca51 100644 (file)
@@ -22,7 +22,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email address(es):
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
index 0cb08e6fb6df9eacfbb94ac53e9b81f51ead993e..483e6303458d41d46f7a059a7762af6fab1d0bfd 100644 (file)
@@ -25,7 +25,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email address(es):
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
@@ -85,4 +85,19 @@ static inline __le32 sctp_end_cksum(__u32 crc32)
        return cpu_to_le32(~crc32);
 }
 
+/* Calculate the CRC32C checksum of an SCTP packet.  */
+static inline __le32 sctp_compute_cksum(const struct sk_buff *skb,
+                                       unsigned int offset)
+{
+       const struct sk_buff *iter;
+
+       __u32 crc32 = sctp_start_cksum(skb->data + offset,
+                                      skb_headlen(skb) - offset);
+       skb_walk_frags(skb, iter)
+               crc32 = sctp_update_cksum((__u8 *) iter->data,
+                                         skb_headlen(iter), crc32);
+
+       return sctp_end_cksum(crc32);
+}
+
 #endif /* __sctp_checksum_h__ */
index ca50e0751e47aabda8beac5a8af9eeff07dc88db..a1e7aa5c8bbf21bf1cf7bd86c758e6289c261a8e 100644 (file)
@@ -25,7 +25,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email address(es):
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
index d8e37ecea691ae2cc9a578063e304167b36e5740..554cf88605fc513a2a55a45021d6c9286d329b34 100644 (file)
@@ -27,7 +27,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email address(es):
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
index 2a82d1384706c61a6757db53edf8d81a53cbc7de..2aa66dda4a5ab4e227b8ad3785c5f669283f2b43 100644 (file)
@@ -27,7 +27,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email addresses:
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
index e745c92a153241d6f261a646b40de71a82f2d98b..75c4c16601b6a1874385ab64f4d7373f3f157b16 100644 (file)
@@ -25,7 +25,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email addresses:
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
index 2c5d2b4d5d1eb51542df26094700250ab6191070..c361d6f7e0cb7758dba88d716ef7f08c88d6bc22 100644 (file)
@@ -28,7 +28,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email address(es):
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
index ca4693b4e09e4bb879c0ef8e483247c913bffb6b..34f0d34d22ce08b2964a0a0518d69f3555ebf55c 100644 (file)
@@ -31,7 +31,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email address(es):
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
index 00e50ba3f24b71a2db54d810ee9889f674444a7b..add3237a9fdba3643ee1f99f78fb465fc1953f5d 100644 (file)
@@ -30,7 +30,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email addresses:
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
index 95a5a2c6925ab0745b563f7f04663721465460e7..ab6a8b75207e5ab0d800e6460ff10aee4c5f4299 100644 (file)
@@ -327,7 +327,7 @@ struct sock {
 #ifdef CONFIG_RPS
        __u32                   sk_rxhash;
 #endif
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        unsigned int            sk_napi_id;
        unsigned int            sk_ll_usec;
 #endif
@@ -746,11 +746,6 @@ static inline int sk_stream_wspace(const struct sock *sk)
 
 extern void sk_stream_write_space(struct sock *sk);
 
-static inline bool sk_stream_memory_free(const struct sock *sk)
-{
-       return sk->sk_wmem_queued < sk->sk_sndbuf;
-}
-
 /* OOB backlog add */
 static inline void __sk_add_backlog(struct sock *sk, struct sk_buff *skb)
 {
@@ -950,6 +945,7 @@ struct proto {
        unsigned int            inuse_idx;
 #endif
 
+       bool                    (*stream_memory_free)(const struct sock *sk);
        /* Memory pressure */
        void                    (*enter_memory_pressure)(struct sock *sk);
        atomic_long_t           *memory_allocated;      /* Current allocated memory. */
@@ -1088,6 +1084,21 @@ static inline struct cg_proto *parent_cg_proto(struct proto *proto,
 }
 #endif
 
+static inline bool sk_stream_memory_free(const struct sock *sk)
+{
+       if (sk->sk_wmem_queued >= sk->sk_sndbuf)
+               return false;
+
+       return sk->sk_prot->stream_memory_free ?
+               sk->sk_prot->stream_memory_free(sk) : true;
+}
+
+static inline bool sk_stream_is_writeable(const struct sock *sk)
+{
+       return sk_stream_wspace(sk) >= sk_stream_min_wspace(sk) &&
+              sk_stream_memory_free(sk);
+}
+
 
 static inline bool sk_has_memory_pressure(const struct sock *sk)
 {
@@ -1509,6 +1520,7 @@ extern struct sk_buff             *sock_rmalloc(struct sock *sk,
                                              unsigned long size, int force,
                                              gfp_t priority);
 extern void                    sock_wfree(struct sk_buff *skb);
+extern void                    skb_orphan_partial(struct sk_buff *skb);
 extern void                    sock_rfree(struct sk_buff *skb);
 extern void                    sock_edemux(struct sk_buff *skb);
 
@@ -2249,6 +2261,8 @@ static inline struct sock *skb_steal_sock(struct sk_buff *skb)
 extern void sock_enable_timestamp(struct sock *sk, int flag);
 extern int sock_get_timestamp(struct sock *, struct timeval __user *);
 extern int sock_get_timestampns(struct sock *, struct timespec __user *);
+extern int sock_recv_errqueue(struct sock *sk, struct msghdr *msg, int len,
+                             int level, int type);
 
 /*
  *     Enable debug/info messages
index d1980054ec75b92c716097c377478b02fdee3762..27b652f379efcfac8c81512093db8013a329e8c5 100644 (file)
@@ -192,10 +192,6 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo);
 #define TCPOLEN_TIMESTAMP      10
 #define TCPOLEN_MD5SIG         18
 #define TCPOLEN_EXP_FASTOPEN_BASE  4
-#define TCPOLEN_COOKIE_BASE    2       /* Cookie-less header extension */
-#define TCPOLEN_COOKIE_PAIR    3       /* Cookie pair header extension */
-#define TCPOLEN_COOKIE_MIN     (TCPOLEN_COOKIE_BASE+TCP_COOKIE_MIN)
-#define TCPOLEN_COOKIE_MAX     (TCPOLEN_COOKIE_BASE+TCP_COOKIE_MAX)
 
 /* But this is what stacks really send out. */
 #define TCPOLEN_TSTAMP_ALIGNED         12
@@ -284,6 +280,7 @@ extern int sysctl_tcp_thin_dupack;
 extern int sysctl_tcp_early_retrans;
 extern int sysctl_tcp_limit_output_bytes;
 extern int sysctl_tcp_challenge_ack_limit;
+extern unsigned int sysctl_tcp_notsent_lowat;
 
 extern atomic_long_t tcp_memory_allocated;
 extern struct percpu_counter tcp_sockets_allocated;
@@ -591,7 +588,6 @@ extern void tcp_initialize_rcv_mss(struct sock *sk);
 extern int tcp_mtu_to_mss(struct sock *sk, int pmtu);
 extern int tcp_mss_to_mtu(struct sock *sk, int mss);
 extern void tcp_mtup_init(struct sock *sk);
-extern void tcp_valid_rtt_meas(struct sock *sk, u32 seq_rtt);
 extern void tcp_init_buffer_space(struct sock *sk);
 
 static inline void tcp_bound_rto(const struct sock *sk)
@@ -1094,15 +1090,6 @@ static inline void tcp_openreq_init(struct request_sock *req,
        ireq->loc_port = tcp_hdr(skb)->dest;
 }
 
-/* Compute time elapsed between SYNACK and the ACK completing 3WHS */
-static inline void tcp_synack_rtt_meas(struct sock *sk,
-                                      struct request_sock *req)
-{
-       if (tcp_rsk(req)->snt_synack)
-               tcp_valid_rtt_meas(sk,
-                   tcp_time_stamp - tcp_rsk(req)->snt_synack);
-}
-
 extern void tcp_enter_memory_pressure(struct sock *sk);
 
 static inline int keepalive_intvl_when(const struct tcp_sock *tp)
@@ -1549,6 +1536,19 @@ extern int tcp_gro_complete(struct sk_buff *skb);
 extern void __tcp_v4_send_check(struct sk_buff *skb, __be32 saddr,
                                __be32 daddr);
 
+static inline u32 tcp_notsent_lowat(const struct tcp_sock *tp)
+{
+       return tp->notsent_lowat ?: sysctl_tcp_notsent_lowat;
+}
+
+static inline bool tcp_stream_memory_free(const struct sock *sk)
+{
+       const struct tcp_sock *tp = tcp_sk(sk);
+       u32 notsent_bytes = tp->write_seq - tp->snd_nxt;
+
+       return notsent_bytes < tcp_notsent_lowat(tp);
+}
+
 #ifdef CONFIG_PROC_FS
 extern int tcp4_proc_init(void);
 extern void tcp4_proc_exit(void);
index 74c10ec5e74fa12c74801f48e2716ec2d9518588..ef2e0b7843a0036c1b31d8e67e78b624bf05f44f 100644 (file)
@@ -183,6 +183,7 @@ extern int udp_sendmsg(struct kiocb *iocb, struct sock *sk,
                            struct msghdr *msg, size_t len);
 extern int udp_push_pending_frames(struct sock *sk);
 extern void udp_flush_pending_frames(struct sock *sk);
+extern void udp4_hwcsum(struct sk_buff *skb, __be32 src, __be32 dst);
 extern int udp_rcv(struct sk_buff *skb);
 extern int udp_ioctl(struct sock *sk, int cmd, unsigned long arg);
 extern int udp_disconnect(struct sock *sk, int flags);
index 94ce082b29dcdba2d726cbc90a0c4510fd38fb2b..89d3d8ae204ec9f8e331862175b660d4377898e0 100644 (file)
@@ -1548,7 +1548,7 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8, int dir, u32
 int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info);
 u32 xfrm_get_acqseq(void);
 extern int xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi);
-struct xfrm_state *xfrm_find_acq(struct net *net, struct xfrm_mark *mark,
+struct xfrm_state *xfrm_find_acq(struct net *net, const struct xfrm_mark *mark,
                                 u8 mode, u32 reqid, u8 proto,
                                 const xfrm_address_t *daddr,
                                 const xfrm_address_t *saddr, int create,
diff --git a/include/sound/rcar_snd.h b/include/sound/rcar_snd.h
new file mode 100644 (file)
index 0000000..99d8dd0
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Renesas R-Car SRU/SCU/SSIU/SSI support
+ *
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef RCAR_SND_H
+#define RCAR_SND_H
+
+#include <linux/sh_clk.h>
+
+#define RSND_GEN1_SRU  0
+#define RSND_GEN1_ADG  1
+#define RSND_GEN1_SSI  2
+
+#define RSND_GEN2_SRU  0
+#define RSND_GEN2_ADG  1
+#define RSND_GEN2_SSIU 2
+#define RSND_GEN2_SSI  3
+
+#define RSND_BASE_MAX  4
+
+/*
+ * flags
+ *
+ * 0xA0000000
+ *
+ * A : clock sharing settings
+ */
+#define RSND_SSI_CLK_PIN_SHARE         (1 << 31)
+#define RSND_SSI_CLK_FROM_ADG          (1 << 30) /* clock parent is master */
+#define RSND_SSI_SYNC                  (1 << 29) /* SSI34_sync etc */
+
+struct rsnd_ssi_platform_info {
+       int pio_irq;
+       u32 flags;
+};
+
+struct rsnd_scu_platform_info {
+       u32 flags;
+};
+
+struct rsnd_dai_platform_info {
+       int ssi_id_playback;
+       int ssi_id_capture;
+};
+
+/*
+ * flags
+ *
+ * 0x0000000A
+ *
+ * A : generation
+ */
+#define RSND_GEN1      (1 << 0) /* fixme */
+#define RSND_GEN2      (2 << 0) /* fixme */
+
+struct rcar_snd_info {
+       u32 flags;
+       struct rsnd_ssi_platform_info *ssi_info;
+       int ssi_info_nr;
+       struct rsnd_scu_platform_info *scu_info;
+       int scu_info_nr;
+       struct rsnd_dai_platform_info *dai_info;
+       int dai_info_nr;
+       int (*start)(int id);
+       int (*stop)(int id);
+};
+
+#endif
index 3e479f4e15f5e3469ef0c7f72f6e88174f36ceba..3575721a955d875f59876322a29219d971a3dc9c 100644 (file)
@@ -70,121 +70,144 @@ struct device;
        .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
        .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
 
+#define SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert) \
+       .reg = wreg, .mask = 1, .shift = wshift, \
+       .on_val = winvert ? 0 : 1, .off_val = winvert ? 1 : 0
+
 /* path domain */
 #define SND_SOC_DAPM_PGA(wname, wreg, wshift, winvert,\
         wcontrols, wncontrols) \
-{      .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
+{      .id = snd_soc_dapm_pga, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
 #define SND_SOC_DAPM_OUT_DRV(wname, wreg, wshift, winvert,\
         wcontrols, wncontrols) \
-{      .id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
+{      .id = snd_soc_dapm_out_drv, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
 #define SND_SOC_DAPM_MIXER(wname, wreg, wshift, winvert, \
         wcontrols, wncontrols)\
-{      .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
+{      .id = snd_soc_dapm_mixer, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
 #define SND_SOC_DAPM_MIXER_NAMED_CTL(wname, wreg, wshift, winvert, \
         wcontrols, wncontrols)\
-{       .id = snd_soc_dapm_mixer_named_ctl, .name = wname, .reg = wreg, \
-       .shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \
-       .num_kcontrols = wncontrols}
+{       .id = snd_soc_dapm_mixer_named_ctl, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
 #define SND_SOC_DAPM_MICBIAS(wname, wreg, wshift, winvert) \
-{      .id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = NULL, .num_kcontrols = 0}
+{      .id = snd_soc_dapm_micbias, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = NULL, .num_kcontrols = 0}
 #define SND_SOC_DAPM_SWITCH(wname, wreg, wshift, winvert, wcontrols) \
-{      .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1}
+{      .id = snd_soc_dapm_switch, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = 1}
 #define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \
-{      .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1}
+{      .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, \
+       .kcontrol_news = wcontrols, .num_kcontrols = 1}
 #define SND_SOC_DAPM_VIRT_MUX(wname, wreg, wshift, winvert, wcontrols) \
-{      .id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1}
+{      .id = snd_soc_dapm_virt_mux, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = 1}
 #define SND_SOC_DAPM_VALUE_MUX(wname, wreg, wshift, winvert, wcontrols) \
-{      .id = snd_soc_dapm_value_mux, .name = wname, .reg = wreg, \
-       .shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \
-       .num_kcontrols = 1}
+{      .id = snd_soc_dapm_value_mux, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = 1}
 
 /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
 #define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\
         wcontrols) \
-{      .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
+{      .id = snd_soc_dapm_pga, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
 #define SOC_MIXER_ARRAY(wname, wreg, wshift, winvert, \
         wcontrols)\
-{      .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
+{      .id = snd_soc_dapm_mixer, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
 #define SOC_MIXER_NAMED_CTL_ARRAY(wname, wreg, wshift, winvert, \
         wcontrols)\
-{       .id = snd_soc_dapm_mixer_named_ctl, .name = wname, .reg = wreg, \
-       .shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \
-       .num_kcontrols = ARRAY_SIZE(wcontrols)}
+{       .id = snd_soc_dapm_mixer_named_ctl, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
 
 /* path domain with event - event handler must return 0 for success */
 #define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \
        wncontrols, wevent, wflags) \
-{      .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
+{      .id = snd_soc_dapm_pga, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
        .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_OUT_DRV_E(wname, wreg, wshift, winvert, wcontrols, \
        wncontrols, wevent, wflags) \
-{      .id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
+{      .id = snd_soc_dapm_out_drv, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
        .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_MIXER_E(wname, wreg, wshift, winvert, wcontrols, \
        wncontrols, wevent, wflags) \
-{      .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
+{      .id = snd_soc_dapm_mixer, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
        .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_MIXER_NAMED_CTL_E(wname, wreg, wshift, winvert, \
        wcontrols, wncontrols, wevent, wflags) \
-{       .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, \
+{       .id = snd_soc_dapm_mixer, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, \
        .num_kcontrols = wncontrols, .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_SWITCH_E(wname, wreg, wshift, winvert, wcontrols, \
        wevent, wflags) \
-{      .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1, \
+{      .id = snd_soc_dapm_switch, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = 1, \
        .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
        wevent, wflags) \
-{      .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1, \
+{      .id = snd_soc_dapm_mux, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = 1, \
        .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_VIRT_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
        wevent, wflags) \
-{      .id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1, \
+{      .id = snd_soc_dapm_virt_mux, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = 1, \
        .event = wevent, .event_flags = wflags}
 
 /* additional sequencing control within an event type */
 #define SND_SOC_DAPM_PGA_S(wname, wsubseq, wreg, wshift, winvert, \
        wevent, wflags) \
-{      .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .event = wevent, .event_flags = wflags, \
+{      .id = snd_soc_dapm_pga, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .event = wevent, .event_flags = wflags, \
        .subseq = wsubseq}
 #define SND_SOC_DAPM_SUPPLY_S(wname, wsubseq, wreg, wshift, winvert, wevent, \
        wflags) \
-{      .id = snd_soc_dapm_supply, .name = wname, .reg = wreg,  \
-       .shift = wshift, .invert = winvert, .event = wevent, \
-       .event_flags = wflags, .subseq = wsubseq}
+{      .id = snd_soc_dapm_supply, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .event = wevent, .event_flags = wflags, .subseq = wsubseq}
 
 /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
 #define SOC_PGA_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
        wevent, wflags) \
-{      .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
+{      .id = snd_soc_dapm_pga, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
        .event = wevent, .event_flags = wflags}
 #define SOC_MIXER_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
        wevent, wflags) \
-{      .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
+{      .id = snd_soc_dapm_mixer, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
        .event = wevent, .event_flags = wflags}
 #define SOC_MIXER_NAMED_CTL_E_ARRAY(wname, wreg, wshift, winvert, \
        wcontrols, wevent, wflags) \
-{       .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, \
-       .num_kcontrols = ARRAY_SIZE(wcontrols), .event = wevent, .event_flags = wflags}
+{       .id = snd_soc_dapm_mixer, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
+       .event = wevent, .event_flags = wflags}
 
 /* events that are pre and post DAPM */
 #define SND_SOC_DAPM_PRE(wname, wevent) \
@@ -199,35 +222,36 @@ struct device;
 /* stream domain */
 #define SND_SOC_DAPM_AIF_IN(wname, stname, wslot, wreg, wshift, winvert) \
 {      .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
-       .reg = wreg, .shift = wshift, .invert = winvert }
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), }
 #define SND_SOC_DAPM_AIF_IN_E(wname, stname, wslot, wreg, wshift, winvert, \
                              wevent, wflags)                           \
 {      .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
-       .reg = wreg, .shift = wshift, .invert = winvert, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .event = wevent, .event_flags = wflags }
 #define SND_SOC_DAPM_AIF_OUT(wname, stname, wslot, wreg, wshift, winvert) \
 {      .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
-       .reg = wreg, .shift = wshift, .invert = winvert }
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), }
 #define SND_SOC_DAPM_AIF_OUT_E(wname, stname, wslot, wreg, wshift, winvert, \
                             wevent, wflags)                            \
 {      .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
-       .reg = wreg, .shift = wshift, .invert = winvert, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .event = wevent, .event_flags = wflags }
 #define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \
-{      .id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \
-       .shift = wshift, .invert = winvert}
+{      .id = snd_soc_dapm_dac, .name = wname, .sname = stname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert) }
 #define SND_SOC_DAPM_DAC_E(wname, stname, wreg, wshift, winvert, \
                           wevent, wflags)                              \
-{      .id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \
-       .shift = wshift, .invert = winvert, \
+{      .id = snd_soc_dapm_dac, .name = wname, .sname = stname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .event = wevent, .event_flags = wflags}
+
 #define SND_SOC_DAPM_ADC(wname, stname, wreg, wshift, winvert) \
-{      .id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \
-       .shift = wshift, .invert = winvert}
+{      .id = snd_soc_dapm_adc, .name = wname, .sname = stname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), }
 #define SND_SOC_DAPM_ADC_E(wname, stname, wreg, wshift, winvert, \
                           wevent, wflags)                              \
-{      .id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \
-       .shift = wshift, .invert = winvert, \
+{      .id = snd_soc_dapm_adc, .name = wname, .sname = stname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_CLOCK_SUPPLY(wname) \
 {      .id = snd_soc_dapm_clock_supply, .name = wname, \
@@ -241,14 +265,14 @@ struct device;
        .on_val = won_val, .off_val = woff_val, .event = dapm_reg_event, \
        .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD}
 #define SND_SOC_DAPM_SUPPLY(wname, wreg, wshift, winvert, wevent, wflags) \
-{      .id = snd_soc_dapm_supply, .name = wname, .reg = wreg,  \
-       .shift = wshift, .invert = winvert, .event = wevent, \
-       .event_flags = wflags}
+{      .id = snd_soc_dapm_supply, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_REGULATOR_SUPPLY(wname, wdelay, wflags)       \
 {      .id = snd_soc_dapm_regulator_supply, .name = wname, \
        .reg = SND_SOC_NOPM, .shift = wdelay, .event = dapm_regulator_event, \
        .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \
-       .invert = wflags}
+       .on_val = wflags}
 
 
 /* dapm kcontrol types */
@@ -333,6 +357,7 @@ struct snd_soc_dapm_route;
 struct snd_soc_dapm_context;
 struct regulator;
 struct snd_soc_dapm_widget_list;
+struct snd_soc_dapm_update;
 
 int dapm_reg_event(struct snd_soc_dapm_widget *w,
                   struct snd_kcontrol *kcontrol, int event);
@@ -391,10 +416,12 @@ void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
 void snd_soc_dapm_shutdown(struct snd_soc_card *card);
 
 /* external DAPM widget events */
-int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
-               struct snd_kcontrol *kcontrol, int connect);
-int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
-                                struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e);
+int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
+               struct snd_kcontrol *kcontrol, int connect,
+               struct snd_soc_dapm_update *update);
+int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
+               struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e,
+               struct snd_soc_dapm_update *update);
 
 /* dapm sys fs - used by the core */
 int snd_soc_dapm_sys_add(struct device *dev);
@@ -424,6 +451,8 @@ void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm);
 int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
        struct snd_soc_dapm_widget_list **list);
 
+struct snd_soc_codec *snd_soc_dapm_kcontrol_codec(struct snd_kcontrol *kcontrol);
+
 /* dapm widget types */
 enum snd_soc_dapm_type {
        snd_soc_dapm_input = 0,         /* input pin */
@@ -485,7 +514,6 @@ struct snd_soc_dapm_path {
        /* source (input) and sink (output) widgets */
        struct snd_soc_dapm_widget *source;
        struct snd_soc_dapm_widget *sink;
-       struct snd_kcontrol *kcontrol;
 
        /* status */
        u32 connect:1;  /* source and sink widgets are connected */
@@ -498,6 +526,7 @@ struct snd_soc_dapm_path {
 
        struct list_head list_source;
        struct list_head list_sink;
+       struct list_head list_kcontrol;
        struct list_head list;
 };
 
@@ -518,12 +547,10 @@ struct snd_soc_dapm_widget {
        /* dapm control */
        int reg;                                /* negative reg = no direct dapm */
        unsigned char shift;                    /* bits to shift */
-       unsigned int value;                             /* widget current value */
        unsigned int mask;                      /* non-shifted mask */
        unsigned int on_val;                    /* on state value */
        unsigned int off_val;                   /* off state value */
        unsigned char power:1;                  /* block power status */
-       unsigned char invert:1;                 /* invert the power bit */
        unsigned char active:1;                 /* active stream on DAC, ADC's */
        unsigned char connected:1;              /* connected codec pin */
        unsigned char new:1;                    /* cnew complete */
@@ -559,7 +586,6 @@ struct snd_soc_dapm_widget {
 };
 
 struct snd_soc_dapm_update {
-       struct snd_soc_dapm_widget *widget;
        struct snd_kcontrol *kcontrol;
        int reg;
        int mask;
@@ -573,8 +599,6 @@ struct snd_soc_dapm_context {
        struct delayed_work delayed_work;
        unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
 
-       struct snd_soc_dapm_update *update;
-
        void (*seq_notifier)(struct snd_soc_dapm_context *,
                             enum snd_soc_dapm_type, int);
 
index 04598f1efd771f9f05e6f051edf975bd510700ce..047d657c331ce77b6c54f51ca38f18cfdc24a1d1 100644 (file)
@@ -133,6 +133,6 @@ void snd_soc_dpcm_be_set_state(struct snd_soc_pcm_runtime *be, int stream,
 /* internal use only */
 int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute);
 int soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd);
-int soc_dpcm_runtime_update(struct snd_soc_dapm_widget *);
+int soc_dpcm_runtime_update(struct snd_soc_card *);
 
 #endif
index 6eabee7ec15a90197ff3024f827d47cfaad91095..48ad07825bb74f4cd3591ade4f6348e88e724ce6 100644 (file)
@@ -475,6 +475,8 @@ int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops);
 struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
                                  void *data, const char *long_name,
                                  const char *prefix);
+struct snd_kcontrol *snd_soc_card_get_kcontrol(struct snd_soc_card *soc_card,
+                                              const char *name);
 int snd_soc_add_codec_controls(struct snd_soc_codec *codec,
        const struct snd_kcontrol_new *controls, int num_controls);
 int snd_soc_add_platform_controls(struct snd_soc_platform *platform,
@@ -1042,6 +1044,7 @@ struct snd_soc_card {
        /* Generic DAPM context for the card */
        struct snd_soc_dapm_context dapm;
        struct snd_soc_dapm_stats dapm_stats;
+       struct snd_soc_dapm_update *update;
 
 #ifdef CONFIG_DEBUG_FS
        struct dentry *debugfs_card_root;
index 098c4de4494573a3ecbb5f697d9fc9a34f8416a7..2d4fa59db9021059b387b7df5145b7a615c81007 100644 (file)
@@ -71,6 +71,7 @@ struct snd_tea575x {
        int (*ext_init)(struct snd_tea575x *tea);
 };
 
+int snd_tea575x_hw_init(struct snd_tea575x *tea);
 int snd_tea575x_init(struct snd_tea575x *tea, struct module *owner);
 void snd_tea575x_exit(struct snd_tea575x *tea);
 void snd_tea575x_set_freq(struct snd_tea575x *tea);
index 8e42410bd1591c5168d616d3ebcac66a1d22aed5..cda100d6762d250616648c6323c3ba2d7aaf6316 100644 (file)
@@ -66,6 +66,43 @@ TRACE_EVENT(machine_suspend,
        TP_printk("state=%lu", (unsigned long)__entry->state)
 );
 
+TRACE_EVENT(device_pm_report_time,
+
+       TP_PROTO(struct device *dev, const char *pm_ops, s64 ops_time,
+                char *pm_event_str, int error),
+
+       TP_ARGS(dev, pm_ops, ops_time, pm_event_str, error),
+
+       TP_STRUCT__entry(
+               __string(device, dev_name(dev))
+               __string(driver, dev_driver_string(dev))
+               __string(parent, dev->parent ? dev_name(dev->parent) : "none")
+               __string(pm_ops, pm_ops ? pm_ops : "none ")
+               __string(pm_event_str, pm_event_str)
+               __field(s64, ops_time)
+               __field(int, error)
+       ),
+
+       TP_fast_assign(
+               const char *tmp = dev->parent ? dev_name(dev->parent) : "none";
+               const char *tmp_i = pm_ops ? pm_ops : "none ";
+
+               __assign_str(device, dev_name(dev));
+               __assign_str(driver, dev_driver_string(dev));
+               __assign_str(parent, tmp);
+               __assign_str(pm_ops, tmp_i);
+               __assign_str(pm_event_str, pm_event_str);
+               __entry->ops_time = ops_time;
+               __entry->error = error;
+       ),
+
+       /* ops_str has an extra space at the end */
+       TP_printk("%s %s parent=%s state=%s ops=%snsecs=%lld err=%d",
+               __get_str(driver), __get_str(device), __get_str(parent),
+               __get_str(pm_event_str), __get_str(pm_ops),
+               __entry->ops_time, __entry->error)
+);
+
 DECLARE_EVENT_CLASS(wakeup_source,
 
        TP_PROTO(const char *name, unsigned int state),
index 238a166b9fe6091935d8357f5898510fe220ad4d..272580ca320f1c6755306d36e503de32d44572b0 100644 (file)
@@ -181,7 +181,7 @@ enum drm_map_type {
        _DRM_AGP = 3,             /**< AGP/GART */
        _DRM_SCATTER_GATHER = 4,  /**< Scatter/gather memory for PCI DMA */
        _DRM_CONSISTENT = 5,      /**< Consistent memory for PCI DMA */
-       _DRM_GEM = 6,             /**< GEM object */
+       _DRM_GEM = 6,             /**< GEM object (obsolete) */
 };
 
 /**
index 923ed7fe5775b61743ba9df9037d27c2c3fe7b6b..a1a7b6bd60d8c30f8c1f9fb95017dfa744765f89 100644 (file)
  * subject to backwards-compatibility constraints.
  */
 
+/**
+ * DOC: uevents generated by i915 on it's device node
+ *
+ * I915_L3_PARITY_UEVENT - Generated when the driver receives a parity mismatch
+ *     event from the gpu l3 cache. Additional information supplied is ROW,
+ *     BANK, SUBBANK of the affected cacheline. Userspace should keep track of
+ *     these events and if a specific cache-line seems to have a persistent
+ *     error remap it with the l3 remapping tool supplied in intel-gpu-tools.
+ *     The value supplied with the event is always 1.
+ *
+ * I915_ERROR_UEVENT - Generated upon error detection, currently only via
+ *     hangcheck. The error detection event is a good indicator of when things
+ *     began to go badly. The value supplied with the event is a 1 upon error
+ *     detection, and a 0 upon reset completion, signifying no more error
+ *     exists. NOTE: Disabling hangcheck or reset via module parameter will
+ *     cause the related events to not be seen.
+ *
+ * I915_RESET_UEVENT - Event is generated just before an attempt to reset the
+ *     the GPU. The value supplied with the event is always 1. NOTE: Disable
+ *     reset via module parameter will cause this event to not be seen.
+ */
+#define I915_L3_PARITY_UEVENT          "L3_PARITY_ERROR"
+#define I915_ERROR_UEVENT              "ERROR"
+#define I915_RESET_UEVENT              "RESET"
 
 /* Each region is a minimum of 16k, and there are at most 255 of them.
  */
index 51da65b68b8501cb2d25fe0064c2c6ff65e3d4e6..59cd31b3455ea1cf9afe039098bf3b0bfa5b0e95 100644 (file)
@@ -45,7 +45,7 @@ enum {
        FRA_FLOW,       /* flow/class id */
        FRA_UNUSED6,
        FRA_UNUSED7,
-       FRA_UNUSED8,
+       FRA_TABLE_PREFIXLEN_MIN,
        FRA_TABLE,      /* Extended table id */
        FRA_FWMASK,     /* mask for netfilter mark */
        FRA_OIFNAME,
index d500369534972c2dede7208ba69d7815e389f299..1db453e4b550ebc84b10ca27f32dd4fdc2ecffd7 100644 (file)
@@ -215,8 +215,8 @@ struct fw_cdev_event_request2 {
  * with the %FW_CDEV_ISO_INTERRUPT bit set, when explicitly requested with
  * %FW_CDEV_IOC_FLUSH_ISO, or when there have been so many completed packets
  * without the interrupt bit set that the kernel's internal buffer for @header
- * is about to overflow.  (In the last case, kernels with ABI version < 5 drop
- * header data up to the next interrupt packet.)
+ * is about to overflow.  (In the last case, ABI versions < 5 drop header data
+ * up to the next interrupt packet.)
  *
  * Isochronous transmit events (context type %FW_CDEV_ISO_CONTEXT_TRANSMIT):
  *
index 03f6170ab3372f443c0989c7c5a503b00ef0c308..04c0e7a5d48421645ee23016064d143918a08ca3 100644 (file)
@@ -143,6 +143,7 @@ enum {
        IFLA_NUM_TX_QUEUES,
        IFLA_NUM_RX_QUEUES,
        IFLA_CARRIER,
+       IFLA_PHYS_PORT_ID,
        __IFLA_MAX
 };
 
index 82334f88967e9ba269d3e3fa121f563c33e64eed..1870ee29bb37bf84ee9fda20b9d3c3c9b5a8b430 100644 (file)
@@ -71,6 +71,9 @@
 /* read-only flag */
 #define IFF_PERSIST    0x0800
 
+/* Socket options */
+#define TUN_TX_TIMESTAMP 1
+
 /* Features for GSO (TUNSETOFFLOAD). */
 #define TUN_F_CSUM     0x01    /* You can hand me unchecksummed packets. */
 #define TUN_F_TSO4     0x02    /* I can handle TSO for IPv4 packets */
index caed0f324d5ffc6fd88a59dda72f51636af0707a..8137dd8d2adffd1c91d4caf76dfa08b47501408a 100644 (file)
@@ -69,8 +69,8 @@
  *     starting a poll from a device which has a secure element enabled means
  *     we want to do SE based card emulation.
  * @NFC_CMD_DISABLE_SE: Disable the physical link to a specific secure element.
- * @NFC_CMD_FW_UPLOAD: Request to Load/flash firmware, or event to inform that
- *     some firmware was loaded
+ * @NFC_CMD_FW_DOWNLOAD: Request to Load/flash firmware, or event to inform
+ *     that some firmware was loaded
  */
 enum nfc_commands {
        NFC_CMD_UNSPEC,
@@ -94,7 +94,7 @@ enum nfc_commands {
        NFC_CMD_DISABLE_SE,
        NFC_CMD_LLC_SDREQ,
        NFC_EVENT_LLC_SDRES,
-       NFC_CMD_FW_UPLOAD,
+       NFC_CMD_FW_DOWNLOAD,
        NFC_EVENT_SE_ADDED,
        NFC_EVENT_SE_REMOVED,
 /* private: internal use only */
index 861e5eba3953b613956a6ca24f632c13d2a1e937..eb68735b33180fac625f3ac7e38137dd0c0f588e 100644 (file)
  * interfaces that a given device supports.
  */
 
+/**
+ * DOC: packet coalesce support
+ *
+ * In most cases, host that receives IPv4 and IPv6 multicast/broadcast
+ * packets does not do anything with these packets. Therefore the
+ * reception of these unwanted packets causes unnecessary processing
+ * and power consumption.
+ *
+ * Packet coalesce feature helps to reduce number of received interrupts
+ * to host by buffering these packets in firmware/hardware for some
+ * predefined time. Received interrupt will be generated when one of the
+ * following events occur.
+ * a) Expiration of hardware timer whose expiration time is set to maximum
+ * coalescing delay of matching coalesce rule.
+ * b) Coalescing buffer in hardware reaches it's limit.
+ * c) Packet doesn't match any of the configured coalesce rules.
+ *
+ * User needs to configure following parameters for creating a coalesce
+ * rule.
+ * a) Maximum coalescing delay
+ * b) List of packet patterns which needs to be matched
+ * c) Condition for coalescence. pattern 'match' or 'no match'
+ * Multiple such rules can be created.
+ */
+
 /**
  * enum nl80211_commands - supported nl80211 commands
  *
  * @NL80211_CMD_CRIT_PROTOCOL_STOP: Indicates the connection reliability can
  *     return back to normal.
  *
+ * @NL80211_CMD_GET_COALESCE: Get currently supported coalesce rules.
+ * @NL80211_CMD_SET_COALESCE: Configure coalesce rules or clear existing rules.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -810,6 +838,9 @@ enum nl80211_commands {
        NL80211_CMD_CRIT_PROTOCOL_START,
        NL80211_CMD_CRIT_PROTOCOL_STOP,
 
+       NL80211_CMD_GET_COALESCE,
+       NL80211_CMD_SET_COALESCE,
+
        /* add new commands above here */
 
        /* used to define NL80211_CMD_MAX below */
@@ -1436,6 +1467,8 @@ enum nl80211_commands {
  *     allowed to be used with the first @NL80211_CMD_SET_STATION command to
  *     update a TDLS peer STA entry.
  *
+ * @NL80211_ATTR_COALESCE_RULE: Coalesce rule information.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1736,6 +1769,8 @@ enum nl80211_attrs {
 
        NL80211_ATTR_PEER_AID,
 
+       NL80211_ATTR_COALESCE_RULE,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -2772,6 +2807,21 @@ enum nl80211_chan_width {
        NL80211_CHAN_WIDTH_10,
 };
 
+/**
+ * enum nl80211_bss_scan_width - control channel width for a BSS
+ *
+ * These values are used with the %NL80211_BSS_CHAN_WIDTH attribute.
+ *
+ * @NL80211_BSS_CHAN_WIDTH_20: control channel is 20 MHz wide or compatible
+ * @NL80211_BSS_CHAN_WIDTH_10: control channel is 10 MHz wide
+ * @NL80211_BSS_CHAN_WIDTH_5: control channel is 5 MHz wide
+ */
+enum nl80211_bss_scan_width {
+       NL80211_BSS_CHAN_WIDTH_20,
+       NL80211_BSS_CHAN_WIDTH_10,
+       NL80211_BSS_CHAN_WIDTH_5,
+};
+
 /**
  * enum nl80211_bss - netlink attributes for a BSS
  *
@@ -2796,6 +2846,8 @@ enum nl80211_chan_width {
  * @NL80211_BSS_BEACON_IES: binary attribute containing the raw information
  *     elements from a Beacon frame (bin); not present if no Beacon frame has
  *     yet been received
+ * @NL80211_BSS_CHAN_WIDTH: channel width of the control channel
+ *     (u32, enum nl80211_bss_scan_width)
  * @__NL80211_BSS_AFTER_LAST: internal
  * @NL80211_BSS_MAX: highest BSS attribute
  */
@@ -2812,6 +2864,7 @@ enum nl80211_bss {
        NL80211_BSS_STATUS,
        NL80211_BSS_SEEN_MS_AGO,
        NL80211_BSS_BEACON_IES,
+       NL80211_BSS_CHAN_WIDTH,
 
        /* keep last */
        __NL80211_BSS_AFTER_LAST,
@@ -3060,11 +3113,11 @@ enum nl80211_tx_power_setting {
 };
 
 /**
- * enum nl80211_wowlan_packet_pattern_attr - WoWLAN packet pattern attribute
- * @__NL80211_WOWLAN_PKTPAT_INVALID: invalid number for nested attribute
- * @NL80211_WOWLAN_PKTPAT_PATTERN: the pattern, values where the mask has
+ * enum nl80211_packet_pattern_attr - packet pattern attribute
+ * @__NL80211_PKTPAT_INVALID: invalid number for nested attribute
+ * @NL80211_PKTPAT_PATTERN: the pattern, values where the mask has
  *     a zero bit are ignored
- * @NL80211_WOWLAN_PKTPAT_MASK: pattern mask, must be long enough to have
+ * @NL80211_PKTPAT_MASK: pattern mask, must be long enough to have
  *     a bit for each byte in the pattern. The lowest-order bit corresponds
  *     to the first byte of the pattern, but the bytes of the pattern are
  *     in a little-endian-like format, i.e. the 9th byte of the pattern
@@ -3075,39 +3128,50 @@ enum nl80211_tx_power_setting {
  *     Note that the pattern matching is done as though frames were not
  *     802.11 frames but 802.3 frames, i.e. the frame is fully unpacked
  *     first (including SNAP header unpacking) and then matched.
- * @NL80211_WOWLAN_PKTPAT_OFFSET: packet offset, pattern is matched after
+ * @NL80211_PKTPAT_OFFSET: packet offset, pattern is matched after
  *     these fixed number of bytes of received packet
- * @NUM_NL80211_WOWLAN_PKTPAT: number of attributes
- * @MAX_NL80211_WOWLAN_PKTPAT: max attribute number
+ * @NUM_NL80211_PKTPAT: number of attributes
+ * @MAX_NL80211_PKTPAT: max attribute number
  */
-enum nl80211_wowlan_packet_pattern_attr {
-       __NL80211_WOWLAN_PKTPAT_INVALID,
-       NL80211_WOWLAN_PKTPAT_MASK,
-       NL80211_WOWLAN_PKTPAT_PATTERN,
-       NL80211_WOWLAN_PKTPAT_OFFSET,
+enum nl80211_packet_pattern_attr {
+       __NL80211_PKTPAT_INVALID,
+       NL80211_PKTPAT_MASK,
+       NL80211_PKTPAT_PATTERN,
+       NL80211_PKTPAT_OFFSET,
 
-       NUM_NL80211_WOWLAN_PKTPAT,
-       MAX_NL80211_WOWLAN_PKTPAT = NUM_NL80211_WOWLAN_PKTPAT - 1,
+       NUM_NL80211_PKTPAT,
+       MAX_NL80211_PKTPAT = NUM_NL80211_PKTPAT - 1,
 };
 
 /**
- * struct nl80211_wowlan_pattern_support - pattern support information
+ * struct nl80211_pattern_support - packet pattern support information
  * @max_patterns: maximum number of patterns supported
  * @min_pattern_len: minimum length of each pattern
  * @max_pattern_len: maximum length of each pattern
  * @max_pkt_offset: maximum Rx packet offset
  *
  * This struct is carried in %NL80211_WOWLAN_TRIG_PKT_PATTERN when
- * that is part of %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED in the
- * capability information given by the kernel to userspace.
+ * that is part of %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED or in
+ * %NL80211_ATTR_COALESCE_RULE_PKT_PATTERN when that is part of
+ * %NL80211_ATTR_COALESCE_RULE in the capability information given
+ * by the kernel to userspace.
  */
-struct nl80211_wowlan_pattern_support {
+struct nl80211_pattern_support {
        __u32 max_patterns;
        __u32 min_pattern_len;
        __u32 max_pattern_len;
        __u32 max_pkt_offset;
 } __attribute__((packed));
 
+/* only for backward compatibility */
+#define __NL80211_WOWLAN_PKTPAT_INVALID __NL80211_PKTPAT_INVALID
+#define NL80211_WOWLAN_PKTPAT_MASK NL80211_PKTPAT_MASK
+#define NL80211_WOWLAN_PKTPAT_PATTERN NL80211_PKTPAT_PATTERN
+#define NL80211_WOWLAN_PKTPAT_OFFSET NL80211_PKTPAT_OFFSET
+#define NUM_NL80211_WOWLAN_PKTPAT NUM_NL80211_PKTPAT
+#define MAX_NL80211_WOWLAN_PKTPAT MAX_NL80211_PKTPAT
+#define nl80211_wowlan_pattern_support nl80211_pattern_support
+
 /**
  * enum nl80211_wowlan_triggers - WoWLAN trigger definitions
  * @__NL80211_WOWLAN_TRIG_INVALID: invalid number for nested attributes
@@ -3127,7 +3191,7 @@ struct nl80211_wowlan_pattern_support {
  *     pattern matching is done after the packet is converted to the MSDU.
  *
  *     In %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, it is a binary attribute
- *     carrying a &struct nl80211_wowlan_pattern_support.
+ *     carrying a &struct nl80211_pattern_support.
  *
  *     When reporting wakeup. it is a u32 attribute containing the 0-based
  *     index of the pattern that caused the wakeup, in the patterns passed
@@ -3284,7 +3348,7 @@ struct nl80211_wowlan_tcp_data_token_feature {
  * @NL80211_WOWLAN_TCP_WAKE_PAYLOAD: wake packet payload, for advertising a
  *     u32 attribute holding the maximum length
  * @NL80211_WOWLAN_TCP_WAKE_MASK: Wake packet payload mask, not used for
- *     feature advertising. The mask works like @NL80211_WOWLAN_PKTPAT_MASK
+ *     feature advertising. The mask works like @NL80211_PKTPAT_MASK
  *     but on the TCP payload only.
  * @NUM_NL80211_WOWLAN_TCP: number of TCP attributes
  * @MAX_NL80211_WOWLAN_TCP: highest attribute number
@@ -3308,6 +3372,55 @@ enum nl80211_wowlan_tcp_attrs {
        MAX_NL80211_WOWLAN_TCP = NUM_NL80211_WOWLAN_TCP - 1
 };
 
+/**
+ * struct nl80211_coalesce_rule_support - coalesce rule support information
+ * @max_rules: maximum number of rules supported
+ * @pat: packet pattern support information
+ * @max_delay: maximum supported coalescing delay in msecs
+ *
+ * This struct is carried in %NL80211_ATTR_COALESCE_RULE in the
+ * capability information given by the kernel to userspace.
+ */
+struct nl80211_coalesce_rule_support {
+       __u32 max_rules;
+       struct nl80211_pattern_support pat;
+       __u32 max_delay;
+} __attribute__((packed));
+
+/**
+ * enum nl80211_attr_coalesce_rule - coalesce rule attribute
+ * @__NL80211_COALESCE_RULE_INVALID: invalid number for nested attribute
+ * @NL80211_ATTR_COALESCE_RULE_DELAY: delay in msecs used for packet coalescing
+ * @NL80211_ATTR_COALESCE_RULE_CONDITION: condition for packet coalescence,
+ *     see &enum nl80211_coalesce_condition.
+ * @NL80211_ATTR_COALESCE_RULE_PKT_PATTERN: packet offset, pattern is matched
+ *     after these fixed number of bytes of received packet
+ * @NUM_NL80211_ATTR_COALESCE_RULE: number of attributes
+ * @NL80211_ATTR_COALESCE_RULE_MAX: max attribute number
+ */
+enum nl80211_attr_coalesce_rule {
+       __NL80211_COALESCE_RULE_INVALID,
+       NL80211_ATTR_COALESCE_RULE_DELAY,
+       NL80211_ATTR_COALESCE_RULE_CONDITION,
+       NL80211_ATTR_COALESCE_RULE_PKT_PATTERN,
+
+       /* keep last */
+       NUM_NL80211_ATTR_COALESCE_RULE,
+       NL80211_ATTR_COALESCE_RULE_MAX = NUM_NL80211_ATTR_COALESCE_RULE - 1
+};
+
+/**
+ * enum nl80211_coalesce_condition - coalesce rule conditions
+ * @NL80211_COALESCE_CONDITION_MATCH: coalaesce Rx packets when patterns
+ *     in a rule are matched.
+ * @NL80211_COALESCE_CONDITION_NO_MATCH: coalesce Rx packets when patterns
+ *     in a rule are not matched.
+ */
+enum nl80211_coalesce_condition {
+       NL80211_COALESCE_CONDITION_MATCH,
+       NL80211_COALESCE_CONDITION_NO_MATCH
+};
+
 /**
  * enum nl80211_iface_limit_attrs - limit attributes
  * @NL80211_IFACE_LIMIT_UNSPEC: (reserved)
index 66b466e4ca08df99479751c55ce03f3daa39ebcb..ca451e99b28b92f5a5e1d8fde7d99446e2df06cf 100644 (file)
@@ -28,7 +28,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email address(es):
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
index 8d776ebc4829df669bbb70c4d6331ba21cc88884..377f1e59411d1572eb645b7b80be42347a7513f5 100644 (file)
@@ -111,6 +111,7 @@ enum {
 #define TCP_REPAIR_OPTIONS     22
 #define TCP_FASTOPEN           23      /* Enable FastOpen on listeners */
 #define TCP_TIMESTAMP          24
+#define TCP_NOTSENT_LOWAT      25      /* limit number of unsent bytes in write queue */
 
 struct tcp_repair_opt {
        __u32   opt_code;
index e9ed951e2b09c11bd010520e5ff0119b201ae1c9..414b74be4da1695bf677e599b8aaf5ec8500679c 100644 (file)
@@ -30,7 +30,7 @@ enum uhid_event_type {
        UHID_OPEN,
        UHID_CLOSE,
        UHID_OUTPUT,
-       UHID_OUTPUT_EV,
+       UHID_OUTPUT_EV,                 /* obsolete! */
        UHID_INPUT,
        UHID_FEATURE,
        UHID_FEATURE_ANSWER,
@@ -69,6 +69,8 @@ struct uhid_output_req {
        __u8 rtype;
 } __attribute__((__packed__));
 
+/* Obsolete! Newer kernels will no longer send these events but instead convert
+ * it into raw output reports via UHID_OUTPUT. */
 struct uhid_output_ev_req {
        __u16 type;
        __u16 code;
index c520203fac2f4b466f062e49f743e45391ac2f93..227d4ce84e79c9e39dc56be1a9e62ab370e69866 100644 (file)
@@ -70,7 +70,9 @@ struct virtio_net_config {
        __u16 max_virtqueue_pairs;
 } __attribute__((packed));
 
-/* This is the first element of the scatter-gather list.  If you don't
+/* This header comes first in the scatter-gather list.
+ * If VIRTIO_F_ANY_LAYOUT is not negotiated, it must
+ * be the first element of the scatter-gather list.  If you don't
  * specify GSO or CSUM features, you can simply ignore the header. */
 struct virtio_net_hdr {
 #define VIRTIO_NET_HDR_F_NEEDS_CSUM    1       // Use csum_start, csum_offset
index 46aa3d1c1654776b6b223d6089a7eb1597662afc..4ddd7dc4a61e2c9b2470bf58349559dc4196f938 100644 (file)
@@ -75,8 +75,10 @@ static inline int xen_acpi_get_pxm(acpi_handle h)
        return -ENXIO;
 }
 
-int xen_acpi_notify_hypervisor_state(u8 sleep_state,
+int xen_acpi_notify_hypervisor_sleep(u8 sleep_state,
                                     u32 pm1a_cnt, u32 pm1b_cnd);
+int xen_acpi_notify_hypervisor_extended_sleep(u8 sleep_state,
+                                    u32 val_a, u32 val_b);
 
 static inline int xen_acpi_suspend_lowlevel(void)
 {
@@ -93,7 +95,9 @@ static inline void xen_acpi_sleep_register(void)
 {
        if (xen_initial_domain()) {
                acpi_os_set_prepare_sleep(
-                       &xen_acpi_notify_hypervisor_state);
+                       &xen_acpi_notify_hypervisor_sleep);
+               acpi_os_set_prepare_extended_sleep(
+                       &xen_acpi_notify_hypervisor_extended_sleep);
 
                acpi_suspend_lowlevel = xen_acpi_suspend_lowlevel;
        }
index c57d5f67f702e3160aba466702e3a720412f09ed..f1331e3e7271f052cd96e1954651b6a786194bca 100644 (file)
@@ -152,10 +152,11 @@ DEFINE_GUEST_HANDLE_STRUCT(xenpf_firmware_info_t);
 #define XENPF_enter_acpi_sleep    51
 struct xenpf_enter_acpi_sleep {
        /* IN variables */
-       uint16_t pm1a_cnt_val;      /* PM1a control value. */
-       uint16_t pm1b_cnt_val;      /* PM1b control value. */
+       uint16_t val_a;             /* PM1a control / sleep type A. */
+       uint16_t val_b;             /* PM1b control / sleep type B. */
        uint32_t sleep_state;       /* Which state to enter (Sn). */
-       uint32_t flags;             /* Must be zero. */
+#define XENPF_ACPI_SLEEP_EXTENDED 0x00000001
+       uint32_t flags;             /* XENPF_ACPI_SLEEP_*. */
 };
 DEFINE_GUEST_HANDLE_STRUCT(xenpf_enter_acpi_sleep_t);
 
index 470839d1a30ed72f68789df711bfa78bdc60e5f4..35ef1185e359457323d5513b578185ad16435bc2 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for the linux kernel.
 #
 
-obj-y     = fork.o exec_domain.o panic.o printk.o \
+obj-y     = fork.o exec_domain.o panic.o \
            cpu.o exit.o itimer.o time.o softirq.o resource.o \
            sysctl.o sysctl_binary.o capability.o ptrace.o timer.o user.o \
            signal.o sys.o kmod.o workqueue.o pid.o task_work.o \
@@ -24,6 +24,7 @@ endif
 
 obj-y += sched/
 obj-y += power/
+obj-y += printk/
 obj-y += cpu/
 
 obj-$(CONFIG_CHECKPOINT_RESTORE) += kcmp.o
index 789ec4683db3b73f83e455891bdb319124215f97..e82423dc76a736fc6c15ba9d99793991abbb828a 100644 (file)
@@ -215,6 +215,8 @@ static u64 cgroup_serial_nr_next = 1;
  */
 static int need_forkexit_callback __read_mostly;
 
+static struct cftype cgroup_base_files[];
+
 static void cgroup_offline_fn(struct work_struct *work);
 static int cgroup_destroy_locked(struct cgroup *cgrp);
 static int cgroup_addrm_files(struct cgroup *cgrp, struct cgroup_subsys *subsys,
@@ -464,7 +466,7 @@ static inline void put_css_set_taskexit(struct css_set *cset)
  * @new_cgrp: cgroup that's being entered by the task
  * @template: desired set of css pointers in css_set (pre-calculated)
  *
- * Returns true if "cg" matches "old_cg" except for the hierarchy
+ * Returns true if "cset" matches "old_cset" except for the hierarchy
  * which "new_cgrp" belongs to, for which it should match "new_cgrp".
  */
 static bool compare_css_sets(struct css_set *cset,
@@ -803,8 +805,7 @@ static struct cgroup *task_cgroup_from_root(struct task_struct *task,
 
 static int cgroup_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode);
 static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry);
-static int cgroup_populate_dir(struct cgroup *cgrp, bool base_files,
-                              unsigned long subsys_mask);
+static int cgroup_populate_dir(struct cgroup *cgrp, unsigned long subsys_mask);
 static const struct inode_operations cgroup_dir_inode_operations;
 static const struct file_operations proc_cgroupstats_operations;
 
@@ -864,8 +865,6 @@ static void cgroup_free_fn(struct work_struct *work)
         */
        dput(cgrp->parent->dentry);
 
-       ida_simple_remove(&cgrp->root->cgroup_ida, cgrp->id);
-
        /*
         * Drop the active superblock reference that we took when we
         * created the cgroup. This will free cgrp->root, if we are
@@ -956,28 +955,23 @@ static void cgroup_rm_file(struct cgroup *cgrp, const struct cftype *cft)
 }
 
 /**
- * cgroup_clear_directory - selective removal of base and subsystem files
- * @dir: directory containing the files
- * @base_files: true if the base files should be removed
+ * cgroup_clear_dir - remove subsys files in a cgroup directory
+ * @cgrp: target cgroup
  * @subsys_mask: mask of the subsystem ids whose files should be removed
  */
-static void cgroup_clear_directory(struct dentry *dir, bool base_files,
-                                  unsigned long subsys_mask)
+static void cgroup_clear_dir(struct cgroup *cgrp, unsigned long subsys_mask)
 {
-       struct cgroup *cgrp = __d_cgrp(dir);
        struct cgroup_subsys *ss;
+       int i;
 
-       for_each_root_subsys(cgrp->root, ss) {
+       for_each_subsys(ss, i) {
                struct cftype_set *set;
-               if (!test_bit(ss->subsys_id, &subsys_mask))
+
+               if (!test_bit(i, &subsys_mask))
                        continue;
                list_for_each_entry(set, &ss->cftsets, node)
                        cgroup_addrm_files(cgrp, NULL, set->cfts, false);
        }
-       if (base_files) {
-               while (!list_empty(&cgrp->files))
-                       cgroup_rm_file(cgrp, NULL);
-       }
 }
 
 /*
@@ -986,9 +980,6 @@ static void cgroup_clear_directory(struct dentry *dir, bool base_files,
 static void cgroup_d_remove_dir(struct dentry *dentry)
 {
        struct dentry *parent;
-       struct cgroupfs_root *root = dentry->d_sb->s_fs_info;
-
-       cgroup_clear_directory(dentry, true, root->subsys_mask);
 
        parent = dentry->d_parent;
        spin_lock(&parent->d_lock);
@@ -1009,32 +1000,47 @@ static int rebind_subsystems(struct cgroupfs_root *root,
 {
        struct cgroup *cgrp = &root->top_cgroup;
        struct cgroup_subsys *ss;
-       int i;
+       unsigned long pinned = 0;
+       int i, ret;
 
        BUG_ON(!mutex_is_locked(&cgroup_mutex));
        BUG_ON(!mutex_is_locked(&cgroup_root_mutex));
 
        /* Check that any added subsystems are currently free */
        for_each_subsys(ss, i) {
-               unsigned long bit = 1UL << i;
-
-               if (!(bit & added_mask))
+               if (!(added_mask & (1 << i)))
                        continue;
 
+               /* is the subsystem mounted elsewhere? */
                if (ss->root != &cgroup_dummy_root) {
-                       /* Subsystem isn't free */
-                       return -EBUSY;
+                       ret = -EBUSY;
+                       goto out_put;
+               }
+
+               /* pin the module */
+               if (!try_module_get(ss->module)) {
+                       ret = -ENOENT;
+                       goto out_put;
                }
+               pinned |= 1 << i;
        }
 
-       /* Currently we don't handle adding/removing subsystems when
-        * any child cgroups exist. This is theoretically supportable
-        * but involves complex error handling, so it's being left until
-        * later */
-       if (root->number_of_cgroups > 1)
-               return -EBUSY;
+       /* subsys could be missing if unloaded between parsing and here */
+       if (added_mask != pinned) {
+               ret = -ENOENT;
+               goto out_put;
+       }
+
+       ret = cgroup_populate_dir(cgrp, added_mask);
+       if (ret)
+               goto out_put;
+
+       /*
+        * Nothing can fail from this point on.  Remove files for the
+        * removed subsystems and rebind each subsystem.
+        */
+       cgroup_clear_dir(cgrp, removed_mask);
 
-       /* Process each subsystem */
        for_each_subsys(ss, i) {
                unsigned long bit = 1UL << i;
 
@@ -1068,20 +1074,6 @@ static int rebind_subsystems(struct cgroupfs_root *root,
                        /* subsystem is now free - drop reference on module */
                        module_put(ss->module);
                        root->subsys_mask &= ~bit;
-               } else if (bit & root->subsys_mask) {
-                       /* Subsystem state should already exist */
-                       BUG_ON(!cgrp->subsys[i]);
-                       /*
-                        * a refcount was taken, but we already had one, so
-                        * drop the extra reference.
-                        */
-                       module_put(ss->module);
-#ifdef CONFIG_MODULE_UNLOAD
-                       BUG_ON(ss->module && !module_refcount(ss->module));
-#endif
-               } else {
-                       /* Subsystem state shouldn't exist */
-                       BUG_ON(cgrp->subsys[i]);
                }
        }
 
@@ -1092,6 +1084,12 @@ static int rebind_subsystems(struct cgroupfs_root *root,
        root->flags |= CGRP_ROOT_SUBSYS_BOUND;
 
        return 0;
+
+out_put:
+       for_each_subsys(ss, i)
+               if (pinned & (1 << i))
+                       module_put(ss->module);
+       return ret;
 }
 
 static int cgroup_show_options(struct seq_file *seq, struct dentry *dentry)
@@ -1142,7 +1140,6 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
        char *token, *o = data;
        bool all_ss = false, one_ss = false;
        unsigned long mask = (unsigned long)-1;
-       bool module_pin_failed = false;
        struct cgroup_subsys *ss;
        int i;
 
@@ -1285,52 +1282,9 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
        if (!opts->subsys_mask && !opts->name)
                return -EINVAL;
 
-       /*
-        * Grab references on all the modules we'll need, so the subsystems
-        * don't dance around before rebind_subsystems attaches them. This may
-        * take duplicate reference counts on a subsystem that's already used,
-        * but rebind_subsystems handles this case.
-        */
-       for_each_subsys(ss, i) {
-               if (!(opts->subsys_mask & (1UL << i)))
-                       continue;
-               if (!try_module_get(cgroup_subsys[i]->module)) {
-                       module_pin_failed = true;
-                       break;
-               }
-       }
-       if (module_pin_failed) {
-               /*
-                * oops, one of the modules was going away. this means that we
-                * raced with a module_delete call, and to the user this is
-                * essentially a "subsystem doesn't exist" case.
-                */
-               for (i--; i >= 0; i--) {
-                       /* drop refcounts only on the ones we took */
-                       unsigned long bit = 1UL << i;
-
-                       if (!(bit & opts->subsys_mask))
-                               continue;
-                       module_put(cgroup_subsys[i]->module);
-               }
-               return -ENOENT;
-       }
-
        return 0;
 }
 
-static void drop_parsed_module_refcounts(unsigned long subsys_mask)
-{
-       struct cgroup_subsys *ss;
-       int i;
-
-       mutex_lock(&cgroup_mutex);
-       for_each_subsys(ss, i)
-               if (subsys_mask & (1UL << i))
-                       module_put(cgroup_subsys[i]->module);
-       mutex_unlock(&cgroup_mutex);
-}
-
 static int cgroup_remount(struct super_block *sb, int *flags, char *data)
 {
        int ret = 0;
@@ -1370,22 +1324,15 @@ static int cgroup_remount(struct super_block *sb, int *flags, char *data)
                goto out_unlock;
        }
 
-       /*
-        * Clear out the files of subsystems that should be removed, do
-        * this before rebind_subsystems, since rebind_subsystems may
-        * change this hierarchy's subsys_list.
-        */
-       cgroup_clear_directory(cgrp->dentry, false, removed_mask);
-
-       ret = rebind_subsystems(root, added_mask, removed_mask);
-       if (ret) {
-               /* rebind_subsystems failed, re-populate the removed files */
-               cgroup_populate_dir(cgrp, false, removed_mask);
+       /* remounting is not allowed for populated hierarchies */
+       if (root->number_of_cgroups > 1) {
+               ret = -EBUSY;
                goto out_unlock;
        }
 
-       /* re-populate subsystem files */
-       cgroup_populate_dir(cgrp, false, added_mask);
+       ret = rebind_subsystems(root, added_mask, removed_mask);
+       if (ret)
+               goto out_unlock;
 
        if (opts.release_agent)
                strcpy(root->release_agent_path, opts.release_agent);
@@ -1395,8 +1342,6 @@ static int cgroup_remount(struct super_block *sb, int *flags, char *data)
        mutex_unlock(&cgroup_root_mutex);
        mutex_unlock(&cgroup_mutex);
        mutex_unlock(&cgrp->dentry->d_inode->i_mutex);
-       if (ret)
-               drop_parsed_module_refcounts(opts.subsys_mask);
        return ret;
 }
 
@@ -1431,6 +1376,7 @@ static void init_cgroup_root(struct cgroupfs_root *root)
        cgrp->root = root;
        RCU_INIT_POINTER(cgrp->name, &root_cgroup_name);
        init_cgroup_housekeeping(cgrp);
+       idr_init(&root->cgroup_idr);
 }
 
 static int cgroup_init_root_id(struct cgroupfs_root *root, int start, int end)
@@ -1503,7 +1449,6 @@ static struct cgroupfs_root *cgroup_root_from_opts(struct cgroup_sb_opts *opts)
         */
        root->subsys_mask = opts->subsys_mask;
        root->flags = opts->flags;
-       ida_init(&root->cgroup_ida);
        if (opts->release_agent)
                strcpy(root->release_agent_path, opts->release_agent);
        if (opts->name)
@@ -1519,7 +1464,7 @@ static void cgroup_free_root(struct cgroupfs_root *root)
                /* hierarhcy ID shoulid already have been released */
                WARN_ON_ONCE(root->hierarchy_id);
 
-               ida_destroy(&root->cgroup_ida);
+               idr_destroy(&root->cgroup_idr);
                kfree(root);
        }
 }
@@ -1584,7 +1529,9 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
        int ret = 0;
        struct super_block *sb;
        struct cgroupfs_root *new_root;
+       struct list_head tmp_links;
        struct inode *inode;
+       const struct cred *cred;
 
        /* First find the desired set of subsystems */
        mutex_lock(&cgroup_mutex);
@@ -1600,7 +1547,7 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
        new_root = cgroup_root_from_opts(&opts);
        if (IS_ERR(new_root)) {
                ret = PTR_ERR(new_root);
-               goto drop_modules;
+               goto out_err;
        }
        opts.new_root = new_root;
 
@@ -1609,17 +1556,15 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
        if (IS_ERR(sb)) {
                ret = PTR_ERR(sb);
                cgroup_free_root(opts.new_root);
-               goto drop_modules;
+               goto out_err;
        }
 
        root = sb->s_fs_info;
        BUG_ON(!root);
        if (root == opts.new_root) {
                /* We used the new root structure, so this is a new hierarchy */
-               struct list_head tmp_links;
                struct cgroup *root_cgrp = &root->top_cgroup;
                struct cgroupfs_root *existing_root;
-               const struct cred *cred;
                int i;
                struct css_set *cset;
 
@@ -1634,6 +1579,11 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
                mutex_lock(&cgroup_mutex);
                mutex_lock(&cgroup_root_mutex);
 
+               root_cgrp->id = idr_alloc(&root->cgroup_idr, root_cgrp,
+                                          0, 1, GFP_KERNEL);
+               if (root_cgrp->id < 0)
+                       goto unlock_drop;
+
                /* Check for name clashes with existing mounts */
                ret = -EBUSY;
                if (strlen(root->name))
@@ -1657,26 +1607,37 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
                if (ret)
                        goto unlock_drop;
 
+               sb->s_root->d_fsdata = root_cgrp;
+               root_cgrp->dentry = sb->s_root;
+
+               /*
+                * We're inside get_sb() and will call lookup_one_len() to
+                * create the root files, which doesn't work if SELinux is
+                * in use.  The following cred dancing somehow works around
+                * it.  See 2ce9738ba ("cgroupfs: use init_cred when
+                * populating new cgroupfs mount") for more details.
+                */
+               cred = override_creds(&init_cred);
+
+               ret = cgroup_addrm_files(root_cgrp, NULL, cgroup_base_files, true);
+               if (ret)
+                       goto rm_base_files;
+
                ret = rebind_subsystems(root, root->subsys_mask, 0);
-               if (ret == -EBUSY) {
-                       free_cgrp_cset_links(&tmp_links);
-                       goto unlock_drop;
-               }
+               if (ret)
+                       goto rm_base_files;
+
+               revert_creds(cred);
+
                /*
                 * There must be no failure case after here, since rebinding
                 * takes care of subsystems' refcounts, which are explicitly
                 * dropped in the failure exit path.
                 */
 
-               /* EBUSY should be the only error here */
-               BUG_ON(ret);
-
                list_add(&root->root_list, &cgroup_roots);
                cgroup_root_count++;
 
-               sb->s_root->d_fsdata = root_cgrp;
-               root->top_cgroup.dentry = sb->s_root;
-
                /* Link the top cgroup in this hierarchy into all
                 * the css_set objects */
                write_lock(&css_set_lock);
@@ -1689,9 +1650,6 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
                BUG_ON(!list_empty(&root_cgrp->children));
                BUG_ON(root->number_of_cgroups != 1);
 
-               cred = override_creds(&init_cred);
-               cgroup_populate_dir(root_cgrp, true, root->subsys_mask);
-               revert_creds(cred);
                mutex_unlock(&cgroup_root_mutex);
                mutex_unlock(&cgroup_mutex);
                mutex_unlock(&inode->i_mutex);
@@ -1711,15 +1669,16 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
                                pr_warning("cgroup: new mount options do not match the existing superblock, will be ignored\n");
                        }
                }
-
-               /* no subsys rebinding, so refcounts don't change */
-               drop_parsed_module_refcounts(opts.subsys_mask);
        }
 
        kfree(opts.release_agent);
        kfree(opts.name);
        return dget(sb->s_root);
 
+ rm_base_files:
+       free_cgrp_cset_links(&tmp_links);
+       cgroup_addrm_files(&root->top_cgroup, NULL, cgroup_base_files, false);
+       revert_creds(cred);
  unlock_drop:
        cgroup_exit_root_id(root);
        mutex_unlock(&cgroup_root_mutex);
@@ -1727,8 +1686,6 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
        mutex_unlock(&inode->i_mutex);
  drop_new_super:
        deactivate_locked_super(sb);
- drop_modules:
-       drop_parsed_module_refcounts(opts.subsys_mask);
  out_err:
        kfree(opts.release_agent);
        kfree(opts.name);
@@ -1746,6 +1703,7 @@ static void cgroup_kill_sb(struct super_block *sb) {
        BUG_ON(root->number_of_cgroups != 1);
        BUG_ON(!list_empty(&cgrp->children));
 
+       mutex_lock(&cgrp->dentry->d_inode->i_mutex);
        mutex_lock(&cgroup_mutex);
        mutex_lock(&cgroup_root_mutex);
 
@@ -1778,6 +1736,7 @@ static void cgroup_kill_sb(struct super_block *sb) {
 
        mutex_unlock(&cgroup_root_mutex);
        mutex_unlock(&cgroup_mutex);
+       mutex_unlock(&cgrp->dentry->d_inode->i_mutex);
 
        simple_xattrs_free(&cgrp->xattrs);
 
@@ -1889,7 +1848,7 @@ EXPORT_SYMBOL_GPL(task_cgroup_path);
 struct task_and_cgroup {
        struct task_struct      *task;
        struct cgroup           *cgrp;
-       struct css_set          *cg;
+       struct css_set          *cset;
 };
 
 struct cgroup_taskset {
@@ -2107,8 +2066,8 @@ static int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk,
 
                tc = flex_array_get(group, i);
                old_cset = task_css_set(tc->task);
-               tc->cg = find_css_set(old_cset, cgrp);
-               if (!tc->cg) {
+               tc->cset = find_css_set(old_cset, cgrp);
+               if (!tc->cset) {
                        retval = -ENOMEM;
                        goto out_put_css_set_refs;
                }
@@ -2121,7 +2080,7 @@ static int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk,
         */
        for (i = 0; i < group_size; i++) {
                tc = flex_array_get(group, i);
-               cgroup_task_migrate(tc->cgrp, tc->task, tc->cg);
+               cgroup_task_migrate(tc->cgrp, tc->task, tc->cset);
        }
        /* nothing is sensitive to fork() after this point. */
 
@@ -2141,9 +2100,9 @@ out_put_css_set_refs:
        if (retval) {
                for (i = 0; i < group_size; i++) {
                        tc = flex_array_get(group, i);
-                       if (!tc->cg)
+                       if (!tc->cset)
                                break;
-                       put_css_set(tc->cg);
+                       put_css_set(tc->cset);
                }
        }
 out_cancel_attach:
@@ -2253,9 +2212,9 @@ int cgroup_attach_task_all(struct task_struct *from, struct task_struct *tsk)
 
        mutex_lock(&cgroup_mutex);
        for_each_active_root(root) {
-               struct cgroup *from_cg = task_cgroup_from_root(from, root);
+               struct cgroup *from_cgrp = task_cgroup_from_root(from, root);
 
-               retval = cgroup_attach_task(from_cg, tsk, false);
+               retval = cgroup_attach_task(from_cgrp, tsk, false);
                if (retval)
                        break;
        }
@@ -2447,11 +2406,6 @@ static ssize_t cgroup_file_read(struct file *file, char __user *buf,
  * supports string->u64 maps, but can be extended in future.
  */
 
-struct cgroup_seqfile_state {
-       struct cftype *cft;
-       struct cgroup *cgroup;
-};
-
 static int cgroup_map_add(struct cgroup_map_cb *cb, const char *key, u64 value)
 {
        struct seq_file *sf = cb->state;
@@ -2460,59 +2414,45 @@ static int cgroup_map_add(struct cgroup_map_cb *cb, const char *key, u64 value)
 
 static int cgroup_seqfile_show(struct seq_file *m, void *arg)
 {
-       struct cgroup_seqfile_state *state = m->private;
-       struct cftype *cft = state->cft;
+       struct cfent *cfe = m->private;
+       struct cftype *cft = cfe->type;
+       struct cgroup *cgrp = __d_cgrp(cfe->dentry->d_parent);
+
        if (cft->read_map) {
                struct cgroup_map_cb cb = {
                        .fill = cgroup_map_add,
                        .state = m,
                };
-               return cft->read_map(state->cgroup, cft, &cb);
+               return cft->read_map(cgrp, cft, &cb);
        }
-       return cft->read_seq_string(state->cgroup, cft, m);
-}
-
-static int cgroup_seqfile_release(struct inode *inode, struct file *file)
-{
-       struct seq_file *seq = file->private_data;
-       kfree(seq->private);
-       return single_release(inode, file);
+       return cft->read_seq_string(cgrp, cft, m);
 }
 
 static const struct file_operations cgroup_seqfile_operations = {
        .read = seq_read,
        .write = cgroup_file_write,
        .llseek = seq_lseek,
-       .release = cgroup_seqfile_release,
+       .release = single_release,
 };
 
 static int cgroup_file_open(struct inode *inode, struct file *file)
 {
        int err;
+       struct cfent *cfe;
        struct cftype *cft;
 
        err = generic_file_open(inode, file);
        if (err)
                return err;
-       cft = __d_cft(file->f_dentry);
+       cfe = __d_cfe(file->f_dentry);
+       cft = cfe->type;
 
        if (cft->read_map || cft->read_seq_string) {
-               struct cgroup_seqfile_state *state;
-
-               state = kzalloc(sizeof(*state), GFP_USER);
-               if (!state)
-                       return -ENOMEM;
-
-               state->cft = cft;
-               state->cgroup = __d_cgrp(file->f_dentry->d_parent);
                file->f_op = &cgroup_seqfile_operations;
-               err = single_open(file, cgroup_seqfile_show, state);
-               if (err < 0)
-                       kfree(state);
-       } else if (cft->open)
+               err = single_open(file, cgroup_seqfile_show, cfe);
+       } else if (cft->open) {
                err = cft->open(inode, file);
-       else
-               err = 0;
+       }
 
        return err;
 }
@@ -2782,11 +2722,26 @@ out:
        return error;
 }
 
+/**
+ * cgroup_addrm_files - add or remove files to a cgroup directory
+ * @cgrp: the target cgroup
+ * @subsys: the subsystem of files to be added
+ * @cfts: array of cftypes to be added
+ * @is_add: whether to add or remove
+ *
+ * Depending on @is_add, add or remove files defined by @cfts on @cgrp.
+ * All @cfts should belong to @subsys.  For removals, this function never
+ * fails.  If addition fails, this function doesn't remove files already
+ * added.  The caller is responsible for cleaning up.
+ */
 static int cgroup_addrm_files(struct cgroup *cgrp, struct cgroup_subsys *subsys,
                              struct cftype cfts[], bool is_add)
 {
        struct cftype *cft;
-       int err, ret = 0;
+       int ret;
+
+       lockdep_assert_held(&cgrp->dentry->d_inode->i_mutex);
+       lockdep_assert_held(&cgroup_mutex);
 
        for (cft = cfts; cft->name[0] != '\0'; cft++) {
                /* does cft->flags tell us to skip this file on @cgrp? */
@@ -2798,16 +2753,17 @@ static int cgroup_addrm_files(struct cgroup *cgrp, struct cgroup_subsys *subsys,
                        continue;
 
                if (is_add) {
-                       err = cgroup_add_file(cgrp, subsys, cft);
-                       if (err)
+                       ret = cgroup_add_file(cgrp, subsys, cft);
+                       if (ret) {
                                pr_warn("cgroup_addrm_files: failed to add %s, err=%d\n",
-                                       cft->name, err);
-                       ret = err;
+                                       cft->name, ret);
+                               return ret;
+                       }
                } else {
                        cgroup_rm_file(cgrp, cft);
                }
        }
-       return ret;
+       return 0;
 }
 
 static void cgroup_cfts_prepare(void)
@@ -2822,8 +2778,8 @@ static void cgroup_cfts_prepare(void)
        mutex_lock(&cgroup_mutex);
 }
 
-static void cgroup_cfts_commit(struct cgroup_subsys *ss,
-                              struct cftype *cfts, bool is_add)
+static int cgroup_cfts_commit(struct cgroup_subsys *ss,
+                             struct cftype *cfts, bool is_add)
        __releases(&cgroup_mutex)
 {
        LIST_HEAD(pending);
@@ -2832,12 +2788,13 @@ static void cgroup_cfts_commit(struct cgroup_subsys *ss,
        struct dentry *prev = NULL;
        struct inode *inode;
        u64 update_before;
+       int ret = 0;
 
        /* %NULL @cfts indicates abort and don't bother if @ss isn't attached */
        if (!cfts || ss->root == &cgroup_dummy_root ||
            !atomic_inc_not_zero(&sb->s_active)) {
                mutex_unlock(&cgroup_mutex);
-               return;
+               return 0;
        }
 
        /*
@@ -2853,10 +2810,13 @@ static void cgroup_cfts_commit(struct cgroup_subsys *ss,
        inode = root->dentry->d_inode;
        mutex_lock(&inode->i_mutex);
        mutex_lock(&cgroup_mutex);
-       cgroup_addrm_files(root, ss, cfts, is_add);
+       ret = cgroup_addrm_files(root, ss, cfts, is_add);
        mutex_unlock(&cgroup_mutex);
        mutex_unlock(&inode->i_mutex);
 
+       if (ret)
+               goto out_deact;
+
        /* add/rm files for all cgroups created before */
        rcu_read_lock();
        cgroup_for_each_descendant_pre(cgrp, root) {
@@ -2873,15 +2833,19 @@ static void cgroup_cfts_commit(struct cgroup_subsys *ss,
                mutex_lock(&inode->i_mutex);
                mutex_lock(&cgroup_mutex);
                if (cgrp->serial_nr < update_before && !cgroup_is_dead(cgrp))
-                       cgroup_addrm_files(cgrp, ss, cfts, is_add);
+                       ret = cgroup_addrm_files(cgrp, ss, cfts, is_add);
                mutex_unlock(&cgroup_mutex);
                mutex_unlock(&inode->i_mutex);
 
                rcu_read_lock();
+               if (ret)
+                       break;
        }
        rcu_read_unlock();
        dput(prev);
+out_deact:
        deactivate_super(sb);
+       return ret;
 }
 
 /**
@@ -2901,6 +2865,7 @@ static void cgroup_cfts_commit(struct cgroup_subsys *ss,
 int cgroup_add_cftypes(struct cgroup_subsys *ss, struct cftype *cfts)
 {
        struct cftype_set *set;
+       int ret;
 
        set = kzalloc(sizeof(*set), GFP_KERNEL);
        if (!set)
@@ -2909,9 +2874,10 @@ int cgroup_add_cftypes(struct cgroup_subsys *ss, struct cftype *cfts)
        cgroup_cfts_prepare();
        set->cfts = cfts;
        list_add_tail(&set->node, &ss->cftsets);
-       cgroup_cfts_commit(ss, cfts, true);
-
-       return 0;
+       ret = cgroup_cfts_commit(ss, cfts, true);
+       if (ret)
+               cgroup_rm_cftypes(ss, cfts);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(cgroup_add_cftypes);
 
@@ -3340,8 +3306,8 @@ int cgroup_scan_tasks(struct cgroup_scanner *scan)
         * guarantees forward progress and that we don't miss any tasks.
         */
        heap->size = 0;
-       cgroup_iter_start(scan->cg, &it);
-       while ((p = cgroup_iter_next(scan->cg, &it))) {
+       cgroup_iter_start(scan->cgrp, &it);
+       while ((p = cgroup_iter_next(scan->cgrp, &it))) {
                /*
                 * Only affect tasks that qualify per the caller's callback,
                 * if he provided one
@@ -3374,7 +3340,7 @@ int cgroup_scan_tasks(struct cgroup_scanner *scan)
                 * the heap and wasn't inserted
                 */
        }
-       cgroup_iter_end(scan->cg, &it);
+       cgroup_iter_end(scan->cgrp, &it);
 
        if (heap->size) {
                for (i = 0; i < heap->size; i++) {
@@ -3420,7 +3386,7 @@ int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from)
 {
        struct cgroup_scanner scan;
 
-       scan.cg = from;
+       scan.cgrp = from;
        scan.test_task = NULL; /* select all tasks in cgroup */
        scan.process_task = cgroup_transfer_one_task;
        scan.heap = NULL;
@@ -3468,7 +3434,7 @@ struct cgroup_pidlist {
        /* pointer to the cgroup we belong to, for list removal purposes */
        struct cgroup *owner;
        /* protects the other fields */
-       struct rw_semaphore mutex;
+       struct rw_semaphore rwsem;
 };
 
 /*
@@ -3541,7 +3507,7 @@ static struct cgroup_pidlist *cgroup_pidlist_find(struct cgroup *cgrp,
        struct pid_namespace *ns = task_active_pid_ns(current);
 
        /*
-        * We can't drop the pidlist_mutex before taking the l->mutex in case
+        * We can't drop the pidlist_mutex before taking the l->rwsem in case
         * the last ref-holder is trying to remove l from the list at the same
         * time. Holding the pidlist_mutex precludes somebody taking whichever
         * list we find out from under us - compare release_pid_array().
@@ -3550,7 +3516,7 @@ static struct cgroup_pidlist *cgroup_pidlist_find(struct cgroup *cgrp,
        list_for_each_entry(l, &cgrp->pidlists, links) {
                if (l->key.type == type && l->key.ns == ns) {
                        /* make sure l doesn't vanish out from under us */
-                       down_write(&l->mutex);
+                       down_write(&l->rwsem);
                        mutex_unlock(&cgrp->pidlist_mutex);
                        return l;
                }
@@ -3561,8 +3527,8 @@ static struct cgroup_pidlist *cgroup_pidlist_find(struct cgroup *cgrp,
                mutex_unlock(&cgrp->pidlist_mutex);
                return l;
        }
-       init_rwsem(&l->mutex);
-       down_write(&l->mutex);
+       init_rwsem(&l->rwsem);
+       down_write(&l->rwsem);
        l->key.type = type;
        l->key.ns = get_pid_ns(ns);
        l->owner = cgrp;
@@ -3623,7 +3589,7 @@ static int pidlist_array_load(struct cgroup *cgrp, enum cgroup_filetype type,
        l->list = array;
        l->length = length;
        l->use_count++;
-       up_write(&l->mutex);
+       up_write(&l->rwsem);
        *lp = l;
        return 0;
 }
@@ -3701,7 +3667,7 @@ static void *cgroup_pidlist_start(struct seq_file *s, loff_t *pos)
        int index = 0, pid = *pos;
        int *iter;
 
-       down_read(&l->mutex);
+       down_read(&l->rwsem);
        if (pid) {
                int end = l->length;
 
@@ -3728,7 +3694,7 @@ static void *cgroup_pidlist_start(struct seq_file *s, loff_t *pos)
 static void cgroup_pidlist_stop(struct seq_file *s, void *v)
 {
        struct cgroup_pidlist *l = s->private;
-       up_read(&l->mutex);
+       up_read(&l->rwsem);
 }
 
 static void *cgroup_pidlist_next(struct seq_file *s, void *v, loff_t *pos)
@@ -3774,7 +3740,7 @@ static void cgroup_release_pid_array(struct cgroup_pidlist *l)
         * pidlist_mutex, we have to take pidlist_mutex first.
         */
        mutex_lock(&l->owner->pidlist_mutex);
-       down_write(&l->mutex);
+       down_write(&l->rwsem);
        BUG_ON(!l->use_count);
        if (!--l->use_count) {
                /* we're the last user if refcount is 0; remove and free */
@@ -3782,12 +3748,12 @@ static void cgroup_release_pid_array(struct cgroup_pidlist *l)
                mutex_unlock(&l->owner->pidlist_mutex);
                pidlist_free(l->list);
                put_pid_ns(l->key.ns);
-               up_write(&l->mutex);
+               up_write(&l->rwsem);
                kfree(l);
                return;
        }
        mutex_unlock(&l->owner->pidlist_mutex);
-       up_write(&l->mutex);
+       up_write(&l->rwsem);
 }
 
 static int cgroup_pidlist_release(struct inode *inode, struct file *file)
@@ -3966,11 +3932,11 @@ static void cgroup_event_ptable_queue_proc(struct file *file,
 static int cgroup_write_event_control(struct cgroup *cgrp, struct cftype *cft,
                                      const char *buffer)
 {
-       struct cgroup_event *event = NULL;
+       struct cgroup_event *event;
        struct cgroup *cgrp_cfile;
        unsigned int efd, cfd;
-       struct file *efile = NULL;
-       struct file *cfile = NULL;
+       struct file *efile;
+       struct file *cfile;
        char *endp;
        int ret;
 
@@ -3996,31 +3962,31 @@ static int cgroup_write_event_control(struct cgroup *cgrp, struct cftype *cft,
        efile = eventfd_fget(efd);
        if (IS_ERR(efile)) {
                ret = PTR_ERR(efile);
-               goto fail;
+               goto out_kfree;
        }
 
        event->eventfd = eventfd_ctx_fileget(efile);
        if (IS_ERR(event->eventfd)) {
                ret = PTR_ERR(event->eventfd);
-               goto fail;
+               goto out_put_efile;
        }
 
        cfile = fget(cfd);
        if (!cfile) {
                ret = -EBADF;
-               goto fail;
+               goto out_put_eventfd;
        }
 
        /* the process need read permission on control file */
        /* AV: shouldn't we check that it's been opened for read instead? */
        ret = inode_permission(file_inode(cfile), MAY_READ);
        if (ret < 0)
-               goto fail;
+               goto out_put_cfile;
 
        event->cft = __file_cft(cfile);
        if (IS_ERR(event->cft)) {
                ret = PTR_ERR(event->cft);
-               goto fail;
+               goto out_put_cfile;
        }
 
        /*
@@ -4030,18 +3996,18 @@ static int cgroup_write_event_control(struct cgroup *cgrp, struct cftype *cft,
        cgrp_cfile = __d_cgrp(cfile->f_dentry->d_parent);
        if (cgrp_cfile != cgrp) {
                ret = -EINVAL;
-               goto fail;
+               goto out_put_cfile;
        }
 
        if (!event->cft->register_event || !event->cft->unregister_event) {
                ret = -EINVAL;
-               goto fail;
+               goto out_put_cfile;
        }
 
        ret = event->cft->register_event(cgrp, event->cft,
                        event->eventfd, buffer);
        if (ret)
-               goto fail;
+               goto out_put_cfile;
 
        efile->f_op->poll(efile, &event->pt);
 
@@ -4061,16 +4027,13 @@ static int cgroup_write_event_control(struct cgroup *cgrp, struct cftype *cft,
 
        return 0;
 
-fail:
-       if (cfile)
-               fput(cfile);
-
-       if (event && event->eventfd && !IS_ERR(event->eventfd))
-               eventfd_ctx_put(event->eventfd);
-
-       if (!IS_ERR_OR_NULL(efile))
-               fput(efile);
-
+out_put_cfile:
+       fput(cfile);
+out_put_eventfd:
+       eventfd_ctx_put(event->eventfd);
+out_put_efile:
+       fput(efile);
+out_kfree:
        kfree(event);
 
        return ret;
@@ -4148,31 +4111,29 @@ static struct cftype cgroup_base_files[] = {
 };
 
 /**
- * cgroup_populate_dir - selectively creation of files in a directory
+ * cgroup_populate_dir - create subsys files in a cgroup directory
  * @cgrp: target cgroup
- * @base_files: true if the base files should be added
  * @subsys_mask: mask of the subsystem ids whose files should be added
+ *
+ * On failure, no file is added.
  */
-static int cgroup_populate_dir(struct cgroup *cgrp, bool base_files,
-                              unsigned long subsys_mask)
+static int cgroup_populate_dir(struct cgroup *cgrp, unsigned long subsys_mask)
 {
-       int err;
        struct cgroup_subsys *ss;
-
-       if (base_files) {
-               err = cgroup_addrm_files(cgrp, NULL, cgroup_base_files, true);
-               if (err < 0)
-                       return err;
-       }
+       int i, ret = 0;
 
        /* process cftsets of each subsystem */
-       for_each_root_subsys(cgrp->root, ss) {
+       for_each_subsys(ss, i) {
                struct cftype_set *set;
-               if (!test_bit(ss->subsys_id, &subsys_mask))
+
+               if (!test_bit(i, &subsys_mask))
                        continue;
 
-               list_for_each_entry(set, &ss->cftsets, node)
-                       cgroup_addrm_files(cgrp, ss, set->cfts, true);
+               list_for_each_entry(set, &ss->cftsets, node) {
+                       ret = cgroup_addrm_files(cgrp, ss, set->cfts, true);
+                       if (ret < 0)
+                               goto err;
+               }
        }
 
        /* This cgroup is ready now */
@@ -4190,6 +4151,9 @@ static int cgroup_populate_dir(struct cgroup *cgrp, bool base_files,
        }
 
        return 0;
+err:
+       cgroup_clear_dir(cgrp, subsys_mask);
+       return ret;
 }
 
 static void css_dput_fn(struct work_struct *work)
@@ -4229,7 +4193,7 @@ static void init_cgroup_css(struct cgroup_subsys_state *css,
        INIT_WORK(&css->dput_work, css_dput_fn);
 }
 
-/* invoke ->post_create() on a new CSS and mark it online if successful */
+/* invoke ->css_online() on a new CSS and mark it online if successful */
 static int online_css(struct cgroup_subsys *ss, struct cgroup *cgrp)
 {
        int ret = 0;
@@ -4243,9 +4207,8 @@ static int online_css(struct cgroup_subsys *ss, struct cgroup *cgrp)
        return ret;
 }
 
-/* if the CSS is online, invoke ->pre_destory() on it and mark it offline */
+/* if the CSS is online, invoke ->css_offline() on it and mark it offline */
 static void offline_css(struct cgroup_subsys *ss, struct cgroup *cgrp)
-       __releases(&cgroup_mutex) __acquires(&cgroup_mutex)
 {
        struct cgroup_subsys_state *css = cgrp->subsys[ss->subsys_id];
 
@@ -4288,7 +4251,11 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
                goto err_free_cgrp;
        rcu_assign_pointer(cgrp->name, name);
 
-       cgrp->id = ida_simple_get(&root->cgroup_ida, 1, 0, GFP_KERNEL);
+       /*
+        * Temporarily set the pointer to NULL, so idr_find() won't return
+        * a half-baked cgroup.
+        */
+       cgrp->id = idr_alloc(&root->cgroup_idr, NULL, 1, 0, GFP_KERNEL);
        if (cgrp->id < 0)
                goto err_free_name;
 
@@ -4335,8 +4302,10 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
                }
 
                err = percpu_ref_init(&css->refcnt, css_release);
-               if (err)
+               if (err) {
+                       ss->css_free(cgrp);
                        goto err_free_all;
+               }
 
                init_cgroup_css(css, ss, cgrp);
 
@@ -4386,7 +4355,13 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
                }
        }
 
-       err = cgroup_populate_dir(cgrp, true, root->subsys_mask);
+       idr_replace(&root->cgroup_idr, cgrp, cgrp->id);
+
+       err = cgroup_addrm_files(cgrp, NULL, cgroup_base_files, true);
+       if (err)
+               goto err_destroy;
+
+       err = cgroup_populate_dir(cgrp, root->subsys_mask);
        if (err)
                goto err_destroy;
 
@@ -4408,7 +4383,7 @@ err_free_all:
        /* Release the reference count that we took on the superblock */
        deactivate_super(sb);
 err_free_id:
-       ida_simple_remove(&root->cgroup_ida, cgrp->id);
+       idr_remove(&root->cgroup_idr, cgrp->id);
 err_free_name:
        kfree(rcu_dereference_raw(cgrp->name));
 err_free_cgrp:
@@ -4539,9 +4514,11 @@ static int cgroup_destroy_locked(struct cgroup *cgrp)
        raw_spin_unlock(&release_list_lock);
 
        /*
-        * Remove @cgrp directory.  The removal puts the base ref but we
-        * aren't quite done with @cgrp yet, so hold onto it.
+        * Clear and remove @cgrp directory.  The removal puts the base ref
+        * but we aren't quite done with @cgrp yet, so hold onto it.
         */
+       cgroup_clear_dir(cgrp, cgrp->root->subsys_mask);
+       cgroup_addrm_files(cgrp, NULL, cgroup_base_files, false);
        dget(d);
        cgroup_d_remove_dir(d);
 
@@ -4599,6 +4576,14 @@ static void cgroup_offline_fn(struct work_struct *work)
        /* delete this cgroup from parent->children */
        list_del_rcu(&cgrp->sibling);
 
+       /*
+        * We should remove the cgroup object from idr before its grace
+        * period starts, so we won't be looking up a cgroup while the
+        * cgroup is being freed.
+        */
+       idr_remove(&cgrp->root->cgroup_idr, cgrp->id);
+       cgrp->id = -1;
+
        dput(d);
 
        set_bit(CGRP_RELEASABLE, &parent->flags);
@@ -4800,7 +4785,7 @@ void cgroup_unload_subsys(struct cgroup_subsys *ss)
 
        /*
         * we shouldn't be called if the subsystem is in use, and the use of
-        * try_module_get in parse_cgroupfs_options should ensure that it
+        * try_module_get() in rebind_subsystems() should ensure that it
         * doesn't start being used while we're killing it off.
         */
        BUG_ON(ss->root != &cgroup_dummy_root);
@@ -4924,6 +4909,10 @@ int __init cgroup_init(void)
 
        BUG_ON(cgroup_init_root_id(&cgroup_dummy_root, 0, 1));
 
+       err = idr_alloc(&cgroup_dummy_root.cgroup_idr, cgroup_dummy_top,
+                       0, 1, GFP_KERNEL);
+       BUG_ON(err < 0);
+
        mutex_unlock(&cgroup_root_mutex);
        mutex_unlock(&cgroup_mutex);
 
index e5657788feddfefaaed5f7ce3ce2ac26ca80a9c1..1b9c31549797dcc4a6e443b9dfcae6d59f0827fc 100644 (file)
@@ -70,7 +70,6 @@ int number_of_cpusets __read_mostly;
 
 /* Forward declare cgroup structures */
 struct cgroup_subsys cpuset_subsys;
-struct cpuset;
 
 /* See "Frequency meter" comments, below. */
 
@@ -846,7 +845,7 @@ static void cpuset_change_cpumask(struct task_struct *tsk,
 {
        struct cpuset *cpus_cs;
 
-       cpus_cs = effective_cpumask_cpuset(cgroup_cs(scan->cg));
+       cpus_cs = effective_cpumask_cpuset(cgroup_cs(scan->cgrp));
        set_cpus_allowed_ptr(tsk, cpus_cs->cpus_allowed);
 }
 
@@ -867,7 +866,7 @@ static void update_tasks_cpumask(struct cpuset *cs, struct ptr_heap *heap)
 {
        struct cgroup_scanner scan;
 
-       scan.cg = cs->css.cgroup;
+       scan.cgrp = cs->css.cgroup;
        scan.test_task = NULL;
        scan.process_task = cpuset_change_cpumask;
        scan.heap = heap;
@@ -1063,7 +1062,7 @@ static void cpuset_change_task_nodemask(struct task_struct *tsk,
 static void cpuset_change_nodemask(struct task_struct *p,
                                   struct cgroup_scanner *scan)
 {
-       struct cpuset *cs = cgroup_cs(scan->cg);
+       struct cpuset *cs = cgroup_cs(scan->cgrp);
        struct mm_struct *mm;
        int migrate;
        nodemask_t *newmems = scan->data;
@@ -1103,7 +1102,7 @@ static void update_tasks_nodemask(struct cpuset *cs, struct ptr_heap *heap)
 
        guarantee_online_mems(mems_cs, &newmems);
 
-       scan.cg = cs->css.cgroup;
+       scan.cgrp = cs->css.cgroup;
        scan.test_task = NULL;
        scan.process_task = cpuset_change_nodemask;
        scan.heap = heap;
@@ -1276,7 +1275,7 @@ static int update_relax_domain_level(struct cpuset *cs, s64 val)
 static void cpuset_change_flag(struct task_struct *tsk,
                                struct cgroup_scanner *scan)
 {
-       cpuset_update_task_spread_flag(cgroup_cs(scan->cg), tsk);
+       cpuset_update_task_spread_flag(cgroup_cs(scan->cgrp), tsk);
 }
 
 /*
@@ -1296,7 +1295,7 @@ static void update_tasks_flags(struct cpuset *cs, struct ptr_heap *heap)
 {
        struct cgroup_scanner scan;
 
-       scan.cg = cs->css.cgroup;
+       scan.cgrp = cs->css.cgroup;
        scan.test_task = NULL;
        scan.process_task = cpuset_change_flag;
        scan.heap = heap;
@@ -1972,7 +1971,7 @@ static int cpuset_css_online(struct cgroup *cgrp)
        struct cpuset *cs = cgroup_cs(cgrp);
        struct cpuset *parent = parent_cs(cs);
        struct cpuset *tmp_cs;
-       struct cgroup *pos_cg;
+       struct cgroup *pos_cgrp;
 
        if (!parent)
                return 0;
@@ -2004,7 +2003,7 @@ static int cpuset_css_online(struct cgroup *cgrp)
         * (and likewise for mems) to the new cgroup.
         */
        rcu_read_lock();
-       cpuset_for_each_child(tmp_cs, pos_cg, parent) {
+       cpuset_for_each_child(tmp_cs, pos_cgrp, parent) {
                if (is_mem_exclusive(tmp_cs) || is_cpu_exclusive(tmp_cs)) {
                        rcu_read_unlock();
                        goto out_unlock;
@@ -2021,6 +2020,12 @@ out_unlock:
        return 0;
 }
 
+/*
+ * If the cpuset being removed has its flag 'sched_load_balance'
+ * enabled, then simulate turning sched_load_balance off, which
+ * will call rebuild_sched_domains_locked().
+ */
+
 static void cpuset_css_offline(struct cgroup *cgrp)
 {
        struct cpuset *cs = cgroup_cs(cgrp);
@@ -2036,12 +2041,6 @@ static void cpuset_css_offline(struct cgroup *cgrp)
        mutex_unlock(&cpuset_mutex);
 }
 
-/*
- * If the cpuset being removed has its flag 'sched_load_balance'
- * enabled, then simulate turning sched_load_balance off, which
- * will call rebuild_sched_domains_locked().
- */
-
 static void cpuset_css_free(struct cgroup *cgrp)
 {
        struct cpuset *cs = cgroup_cs(cgrp);
index ff915efef66db9d8635d13a2bf1a783c4059f00e..30c0d91ca7f2995e0a5dfe59c3c8efc6a81c26af 100644 (file)
@@ -10,14 +10,12 @@ Elf_Half __weak elf_core_extra_phdrs(void)
        return 0;
 }
 
-int __weak elf_core_write_extra_phdrs(struct file *file, loff_t offset, size_t *size,
-                                     unsigned long limit)
+int __weak elf_core_write_extra_phdrs(struct coredump_params *cprm, loff_t offset)
 {
        return 1;
 }
 
-int __weak elf_core_write_extra_data(struct file *file, size_t *size,
-                                    unsigned long limit)
+int __weak elf_core_write_extra_data(struct coredump_params *cprm)
 {
        return 1;
 }
index 8b2afc1c9df0c698eccd86664d25c33ed647fea7..b462fa197517b6176701fa860cdb966bc44a69ba 100644 (file)
@@ -33,7 +33,7 @@ static DEFINE_SPINLOCK(freezer_lock);
  */
 bool freezing_slow_path(struct task_struct *p)
 {
-       if (p->flags & PF_NOFREEZE)
+       if (p->flags & (PF_NOFREEZE | PF_SUSPEND_TASK))
                return false;
 
        if (pm_nosig_freezing || cgroup_freezing(p))
index fc0df84864495f8c44261961cb6909e66d24a21e..06ec8869dbf1629f2c7cabc63f2edc96426ea87d 100644 (file)
@@ -109,6 +109,8 @@ static int try_to_freeze_tasks(bool user_only)
 
 /**
  * freeze_processes - Signal user space processes to enter the refrigerator.
+ * The current thread will not be frozen.  The same process that calls
+ * freeze_processes must later call thaw_processes.
  *
  * On success, returns 0.  On failure, -errno and system is fully thawed.
  */
@@ -120,6 +122,9 @@ int freeze_processes(void)
        if (error)
                return error;
 
+       /* Make sure this task doesn't get frozen */
+       current->flags |= PF_SUSPEND_TASK;
+
        if (!pm_freezing)
                atomic_inc(&system_freezing_cnt);
 
@@ -168,6 +173,7 @@ int freeze_kernel_threads(void)
 void thaw_processes(void)
 {
        struct task_struct *g, *p;
+       struct task_struct *curr = current;
 
        if (pm_freezing)
                atomic_dec(&system_freezing_cnt);
@@ -182,10 +188,15 @@ void thaw_processes(void)
 
        read_lock(&tasklist_lock);
        do_each_thread(g, p) {
+               /* No other threads should have PF_SUSPEND_TASK set */
+               WARN_ON((p != curr) && (p->flags & PF_SUSPEND_TASK));
                __thaw_task(p);
        } while_each_thread(g, p);
        read_unlock(&tasklist_lock);
 
+       WARN_ON(!(curr->flags & PF_SUSPEND_TASK));
+       curr->flags &= ~PF_SUSPEND_TASK;
+
        usermodehelper_enable();
 
        schedule();
index ece04223bb1ebf99d08a1aa0aab99e14d0fbf994..62ee437b5c7ea362de8573dd18fcee1ef6286221 100644 (file)
@@ -210,6 +210,7 @@ static int suspend_enter(suspend_state_t state, bool *wakeup)
                goto Platform_wake;
        }
 
+       ftrace_stop();
        error = disable_nonboot_cpus();
        if (error || suspend_test(TEST_CPUS))
                goto Enable_cpus;
@@ -232,6 +233,7 @@ static int suspend_enter(suspend_state_t state, bool *wakeup)
 
  Enable_cpus:
        enable_nonboot_cpus();
+       ftrace_start();
 
  Platform_wake:
        if (need_suspend_ops(state) && suspend_ops->wake)
@@ -265,7 +267,6 @@ int suspend_devices_and_enter(suspend_state_t state)
                        goto Close;
        }
        suspend_console();
-       ftrace_stop();
        suspend_test_start();
        error = dpm_suspend_start(PMSG_SUSPEND);
        if (error) {
@@ -285,7 +286,6 @@ int suspend_devices_and_enter(suspend_state_t state)
        suspend_test_start();
        dpm_resume_end(PMSG_RESUME);
        suspend_test_finish("resume devices");
-       ftrace_start();
        resume_console();
  Close:
        if (need_suspend_ops(state) && suspend_ops->end)
diff --git a/kernel/printk/Makefile b/kernel/printk/Makefile
new file mode 100644 (file)
index 0000000..85405bd
--- /dev/null
@@ -0,0 +1,2 @@
+obj-y  = printk.o
+obj-$(CONFIG_A11Y_BRAILLE_CONSOLE)     += braille.o
diff --git a/kernel/printk/braille.c b/kernel/printk/braille.c
new file mode 100644 (file)
index 0000000..b51087f
--- /dev/null
@@ -0,0 +1,48 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/console.h>
+#include <linux/string.h>
+
+#include "console_cmdline.h"
+#include "braille.h"
+
+char *_braille_console_setup(char **str, char **brl_options)
+{
+       if (!memcmp(*str, "brl,", 4)) {
+               *brl_options = "";
+               *str += 4;
+       } else if (!memcmp(str, "brl=", 4)) {
+               *brl_options = *str + 4;
+               *str = strchr(*brl_options, ',');
+               if (!*str)
+                       pr_err("need port name after brl=\n");
+               else
+                       *((*str)++) = 0;
+       }
+
+       return *str;
+}
+
+int
+_braille_register_console(struct console *console, struct console_cmdline *c)
+{
+       int rtn = 0;
+
+       if (c->brl_options) {
+               console->flags |= CON_BRL;
+               rtn = braille_register_console(console, c->index, c->options,
+                                              c->brl_options);
+       }
+
+       return rtn;
+}
+
+int
+_braille_unregister_console(struct console *console)
+{
+       if (console->flags & CON_BRL)
+               return braille_unregister_console(console);
+
+       return 0;
+}
diff --git a/kernel/printk/braille.h b/kernel/printk/braille.h
new file mode 100644 (file)
index 0000000..769d771
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef _PRINTK_BRAILLE_H
+#define _PRINTK_BRAILLE_H
+
+#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
+
+static inline void
+braille_set_options(struct console_cmdline *c, char *brl_options)
+{
+       c->brl_options = brl_options;
+}
+
+char *
+_braille_console_setup(char **str, char **brl_options);
+
+int
+_braille_register_console(struct console *console, struct console_cmdline *c);
+
+int
+_braille_unregister_console(struct console *console);
+
+#else
+
+static inline void
+braille_set_options(struct console_cmdline *c, char *brl_options)
+{
+}
+
+static inline char *
+_braille_console_setup(char **str, char **brl_options)
+{
+       return NULL;
+}
+
+static inline int
+_braille_register_console(struct console *console, struct console_cmdline *c)
+{
+       return 0;
+}
+
+static inline int
+_braille_unregister_console(struct console *console)
+{
+       return 0;
+}
+
+#endif
+
+#endif
diff --git a/kernel/printk/console_cmdline.h b/kernel/printk/console_cmdline.h
new file mode 100644 (file)
index 0000000..cbd69d8
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef _CONSOLE_CMDLINE_H
+#define _CONSOLE_CMDLINE_H
+
+struct console_cmdline
+{
+       char    name[8];                        /* Name of the driver       */
+       int     index;                          /* Minor dev. to use        */
+       char    *options;                       /* Options for the driver   */
+#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
+       char    *brl_options;                   /* Options for braille driver */
+#endif
+};
+
+#endif
similarity index 95%
rename from kernel/printk.c
rename to kernel/printk/printk.c
index 69b0890ed7e54aa0679d1154056a7d26454fb7bd..5b5a7080e2a5f2822dfd93190c05302be74b1784 100644 (file)
@@ -51,6 +51,9 @@
 #define CREATE_TRACE_POINTS
 #include <trace/events/printk.h>
 
+#include "console_cmdline.h"
+#include "braille.h"
+
 /* printk's without a loglevel use this.. */
 #define DEFAULT_MESSAGE_LOGLEVEL CONFIG_DEFAULT_MESSAGE_LOGLEVEL
 
@@ -105,19 +108,11 @@ static struct console *exclusive_console;
 /*
  *     Array of consoles built from command line options (console=)
  */
-struct console_cmdline
-{
-       char    name[8];                        /* Name of the driver       */
-       int     index;                          /* Minor dev. to use        */
-       char    *options;                       /* Options for the driver   */
-#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
-       char    *brl_options;                   /* Options for braille driver */
-#endif
-};
 
 #define MAX_CMDLINECONSOLES 8
 
 static struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES];
+
 static int selected_console = -1;
 static int preferred_console = -1;
 int console_set_on_cmdline;
@@ -178,7 +173,7 @@ static int console_may_schedule;
  *         67                           "g"
  *   0032     00 00 00                  padding to next message header
  *
- * The 'struct log' buffer header must never be directly exported to
+ * The 'struct printk_log' buffer header must never be directly exported to
  * userspace, it is a kernel-private implementation detail that might
  * need to be changed in the future, when the requirements change.
  *
@@ -200,7 +195,7 @@ enum log_flags {
        LOG_CONT        = 8,    /* text is a fragment of a continuation line */
 };
 
-struct log {
+struct printk_log {
        u64 ts_nsec;            /* timestamp in nanoseconds */
        u16 len;                /* length of entire record */
        u16 text_len;           /* length of text buffer */
@@ -248,7 +243,7 @@ static u32 clear_idx;
 #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
 #define LOG_ALIGN 4
 #else
-#define LOG_ALIGN __alignof__(struct log)
+#define LOG_ALIGN __alignof__(struct printk_log)
 #endif
 #define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT)
 static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN);
@@ -259,35 +254,35 @@ static u32 log_buf_len = __LOG_BUF_LEN;
 static volatile unsigned int logbuf_cpu = UINT_MAX;
 
 /* human readable text of the record */
-static char *log_text(const struct log *msg)
+static char *log_text(const struct printk_log *msg)
 {
-       return (char *)msg + sizeof(struct log);
+       return (char *)msg + sizeof(struct printk_log);
 }
 
 /* optional key/value pair dictionary attached to the record */
-static char *log_dict(const struct log *msg)
+static char *log_dict(const struct printk_log *msg)
 {
-       return (char *)msg + sizeof(struct log) + msg->text_len;
+       return (char *)msg + sizeof(struct printk_log) + msg->text_len;
 }
 
 /* get record by index; idx must point to valid msg */
-static struct log *log_from_idx(u32 idx)
+static struct printk_log *log_from_idx(u32 idx)
 {
-       struct log *msg = (struct log *)(log_buf + idx);
+       struct printk_log *msg = (struct printk_log *)(log_buf + idx);
 
        /*
         * A length == 0 record is the end of buffer marker. Wrap around and
         * read the message at the start of the buffer.
         */
        if (!msg->len)
-               return (struct log *)log_buf;
+               return (struct printk_log *)log_buf;
        return msg;
 }
 
 /* get next record; idx must point to valid msg */
 static u32 log_next(u32 idx)
 {
-       struct log *msg = (struct log *)(log_buf + idx);
+       struct printk_log *msg = (struct printk_log *)(log_buf + idx);
 
        /* length == 0 indicates the end of the buffer; wrap */
        /*
@@ -296,7 +291,7 @@ static u32 log_next(u32 idx)
         * return the one after that.
         */
        if (!msg->len) {
-               msg = (struct log *)log_buf;
+               msg = (struct printk_log *)log_buf;
                return msg->len;
        }
        return idx + msg->len;
@@ -308,11 +303,11 @@ static void log_store(int facility, int level,
                      const char *dict, u16 dict_len,
                      const char *text, u16 text_len)
 {
-       struct log *msg;
+       struct printk_log *msg;
        u32 size, pad_len;
 
        /* number of '\0' padding bytes to next message */
-       size = sizeof(struct log) + text_len + dict_len;
+       size = sizeof(struct printk_log) + text_len + dict_len;
        pad_len = (-size) & (LOG_ALIGN - 1);
        size += pad_len;
 
@@ -324,7 +319,7 @@ static void log_store(int facility, int level,
                else
                        free = log_first_idx - log_next_idx;
 
-               if (free > size + sizeof(struct log))
+               if (free > size + sizeof(struct printk_log))
                        break;
 
                /* drop old messages until we have enough contiuous space */
@@ -332,18 +327,18 @@ static void log_store(int facility, int level,
                log_first_seq++;
        }
 
-       if (log_next_idx + size + sizeof(struct log) >= log_buf_len) {
+       if (log_next_idx + size + sizeof(struct printk_log) >= log_buf_len) {
                /*
                 * This message + an additional empty header does not fit
                 * at the end of the buffer. Add an empty header with len == 0
                 * to signify a wrap around.
                 */
-               memset(log_buf + log_next_idx, 0, sizeof(struct log));
+               memset(log_buf + log_next_idx, 0, sizeof(struct printk_log));
                log_next_idx = 0;
        }
 
        /* fill message */
-       msg = (struct log *)(log_buf + log_next_idx);
+       msg = (struct printk_log *)(log_buf + log_next_idx);
        memcpy(log_text(msg), text, text_len);
        msg->text_len = text_len;
        memcpy(log_dict(msg), dict, dict_len);
@@ -356,7 +351,7 @@ static void log_store(int facility, int level,
        else
                msg->ts_nsec = local_clock();
        memset(log_dict(msg) + dict_len, 0, pad_len);
-       msg->len = sizeof(struct log) + text_len + dict_len + pad_len;
+       msg->len = sizeof(struct printk_log) + text_len + dict_len + pad_len;
 
        /* insert message */
        log_next_idx += msg->len;
@@ -479,7 +474,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
                            size_t count, loff_t *ppos)
 {
        struct devkmsg_user *user = file->private_data;
-       struct log *msg;
+       struct printk_log *msg;
        u64 ts_usec;
        size_t i;
        char cont = '-';
@@ -724,14 +719,14 @@ void log_buf_kexec_setup(void)
        VMCOREINFO_SYMBOL(log_first_idx);
        VMCOREINFO_SYMBOL(log_next_idx);
        /*
-        * Export struct log size and field offsets. User space tools can
+        * Export struct printk_log size and field offsets. User space tools can
         * parse it and detect any changes to structure down the line.
         */
-       VMCOREINFO_STRUCT_SIZE(log);
-       VMCOREINFO_OFFSET(log, ts_nsec);
-       VMCOREINFO_OFFSET(log, len);
-       VMCOREINFO_OFFSET(log, text_len);
-       VMCOREINFO_OFFSET(log, dict_len);
+       VMCOREINFO_STRUCT_SIZE(printk_log);
+       VMCOREINFO_OFFSET(printk_log, ts_nsec);
+       VMCOREINFO_OFFSET(printk_log, len);
+       VMCOREINFO_OFFSET(printk_log, text_len);
+       VMCOREINFO_OFFSET(printk_log, dict_len);
 }
 #endif
 
@@ -884,7 +879,7 @@ static size_t print_time(u64 ts, char *buf)
                       (unsigned long)ts, rem_nsec / 1000);
 }
 
-static size_t print_prefix(const struct log *msg, bool syslog, char *buf)
+static size_t print_prefix(const struct printk_log *msg, bool syslog, char *buf)
 {
        size_t len = 0;
        unsigned int prefix = (msg->facility << 3) | msg->level;
@@ -907,7 +902,7 @@ static size_t print_prefix(const struct log *msg, bool syslog, char *buf)
        return len;
 }
 
-static size_t msg_print_text(const struct log *msg, enum log_flags prev,
+static size_t msg_print_text(const struct printk_log *msg, enum log_flags prev,
                             bool syslog, char *buf, size_t size)
 {
        const char *text = log_text(msg);
@@ -969,7 +964,7 @@ static size_t msg_print_text(const struct log *msg, enum log_flags prev,
 static int syslog_print(char __user *buf, int size)
 {
        char *text;
-       struct log *msg;
+       struct printk_log *msg;
        int len = 0;
 
        text = kmalloc(LOG_LINE_MAX + PREFIX_MAX, GFP_KERNEL);
@@ -1060,7 +1055,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
                idx = clear_idx;
                prev = 0;
                while (seq < log_next_seq) {
-                       struct log *msg = log_from_idx(idx);
+                       struct printk_log *msg = log_from_idx(idx);
 
                        len += msg_print_text(msg, prev, true, NULL, 0);
                        prev = msg->flags;
@@ -1073,7 +1068,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
                idx = clear_idx;
                prev = 0;
                while (len > size && seq < log_next_seq) {
-                       struct log *msg = log_from_idx(idx);
+                       struct printk_log *msg = log_from_idx(idx);
 
                        len -= msg_print_text(msg, prev, true, NULL, 0);
                        prev = msg->flags;
@@ -1087,7 +1082,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
                len = 0;
                prev = 0;
                while (len >= 0 && seq < next_seq) {
-                       struct log *msg = log_from_idx(idx);
+                       struct printk_log *msg = log_from_idx(idx);
                        int textlen;
 
                        textlen = msg_print_text(msg, prev, true, text,
@@ -1233,7 +1228,7 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
 
                        error = 0;
                        while (seq < log_next_seq) {
-                               struct log *msg = log_from_idx(idx);
+                               struct printk_log *msg = log_from_idx(idx);
 
                                error += msg_print_text(msg, prev, true, NULL, 0);
                                idx = log_next(idx);
@@ -1719,10 +1714,10 @@ static struct cont {
        u8 level;
        bool flushed:1;
 } cont;
-static struct log *log_from_idx(u32 idx) { return NULL; }
+static struct printk_log *log_from_idx(u32 idx) { return NULL; }
 static u32 log_next(u32 idx) { return 0; }
 static void call_console_drivers(int level, const char *text, size_t len) {}
-static size_t msg_print_text(const struct log *msg, enum log_flags prev,
+static size_t msg_print_text(const struct printk_log *msg, enum log_flags prev,
                             bool syslog, char *buf, size_t size) { return 0; }
 static size_t cont_print_text(char *text, size_t size) { return 0; }
 
@@ -1761,23 +1756,23 @@ static int __add_preferred_console(char *name, int idx, char *options,
         *      See if this tty is not yet registered, and
         *      if we have a slot free.
         */
-       for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
-               if (strcmp(console_cmdline[i].name, name) == 0 &&
-                         console_cmdline[i].index == idx) {
-                               if (!brl_options)
-                                       selected_console = i;
-                               return 0;
+       for (i = 0, c = console_cmdline;
+            i < MAX_CMDLINECONSOLES && c->name[0];
+            i++, c++) {
+               if (strcmp(c->name, name) == 0 && c->index == idx) {
+                       if (!brl_options)
+                               selected_console = i;
+                       return 0;
                }
+       }
        if (i == MAX_CMDLINECONSOLES)
                return -E2BIG;
        if (!brl_options)
                selected_console = i;
-       c = &console_cmdline[i];
        strlcpy(c->name, name, sizeof(c->name));
        c->options = options;
-#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
-       c->brl_options = brl_options;
-#endif
+       braille_set_options(c, brl_options);
+
        c->index = idx;
        return 0;
 }
@@ -1790,20 +1785,8 @@ static int __init console_setup(char *str)
        char *s, *options, *brl_options = NULL;
        int idx;
 
-#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
-       if (!memcmp(str, "brl,", 4)) {
-               brl_options = "";
-               str += 4;
-       } else if (!memcmp(str, "brl=", 4)) {
-               brl_options = str + 4;
-               str = strchr(brl_options, ',');
-               if (!str) {
-                       printk(KERN_ERR "need port name after brl=\n");
-                       return 1;
-               }
-               *(str++) = 0;
-       }
-#endif
+       if (_braille_console_setup(&str, &brl_options))
+               return 1;
 
        /*
         * Decode str into name, index, options.
@@ -1858,15 +1841,15 @@ int update_console_cmdline(char *name, int idx, char *name_new, int idx_new, cha
        struct console_cmdline *c;
        int i;
 
-       for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
-               if (strcmp(console_cmdline[i].name, name) == 0 &&
-                         console_cmdline[i].index == idx) {
-                               c = &console_cmdline[i];
-                               strlcpy(c->name, name_new, sizeof(c->name));
-                               c->name[sizeof(c->name) - 1] = 0;
-                               c->options = options;
-                               c->index = idx_new;
-                               return i;
+       for (i = 0, c = console_cmdline;
+            i < MAX_CMDLINECONSOLES && c->name[0];
+            i++, c++)
+               if (strcmp(c->name, name) == 0 && c->index == idx) {
+                       strlcpy(c->name, name_new, sizeof(c->name));
+                       c->name[sizeof(c->name) - 1] = 0;
+                       c->options = options;
+                       c->index = idx_new;
+                       return i;
                }
        /* not found */
        return -1;
@@ -2046,7 +2029,7 @@ void console_unlock(void)
        console_cont_flush(text, sizeof(text));
 again:
        for (;;) {
-               struct log *msg;
+               struct printk_log *msg;
                size_t len;
                int level;
 
@@ -2241,6 +2224,7 @@ void register_console(struct console *newcon)
        int i;
        unsigned long flags;
        struct console *bcon = NULL;
+       struct console_cmdline *c;
 
        /*
         * before we register a new CON_BOOT console, make sure we don't
@@ -2288,30 +2272,25 @@ void register_console(struct console *newcon)
         *      See if this console matches one we selected on
         *      the command line.
         */
-       for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0];
-                       i++) {
-               if (strcmp(console_cmdline[i].name, newcon->name) != 0)
+       for (i = 0, c = console_cmdline;
+            i < MAX_CMDLINECONSOLES && c->name[0];
+            i++, c++) {
+               if (strcmp(c->name, newcon->name) != 0)
                        continue;
                if (newcon->index >= 0 &&
-                   newcon->index != console_cmdline[i].index)
+                   newcon->index != c->index)
                        continue;
                if (newcon->index < 0)
-                       newcon->index = console_cmdline[i].index;
-#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
-               if (console_cmdline[i].brl_options) {
-                       newcon->flags |= CON_BRL;
-                       braille_register_console(newcon,
-                                       console_cmdline[i].index,
-                                       console_cmdline[i].options,
-                                       console_cmdline[i].brl_options);
+                       newcon->index = c->index;
+
+               if (_braille_register_console(newcon, c))
                        return;
-               }
-#endif
+
                if (newcon->setup &&
                    newcon->setup(newcon, console_cmdline[i].options) != 0)
                        break;
                newcon->flags |= CON_ENABLED;
-               newcon->index = console_cmdline[i].index;
+               newcon->index = c->index;
                if (i == selected_console) {
                        newcon->flags |= CON_CONSDEV;
                        preferred_console = selected_console;
@@ -2394,13 +2373,13 @@ EXPORT_SYMBOL(register_console);
 int unregister_console(struct console *console)
 {
         struct console *a, *b;
-       int res = 1;
+       int res;
 
-#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
-       if (console->flags & CON_BRL)
-               return braille_unregister_console(console);
-#endif
+       res = _braille_unregister_console(console);
+       if (res)
+               return res;
 
+       res = 1;
        console_lock();
        if (console_drivers == console) {
                console_drivers=console->next;
@@ -2666,7 +2645,7 @@ void kmsg_dump(enum kmsg_dump_reason reason)
 bool kmsg_dump_get_line_nolock(struct kmsg_dumper *dumper, bool syslog,
                               char *line, size_t size, size_t *len)
 {
-       struct log *msg;
+       struct printk_log *msg;
        size_t l = 0;
        bool ret = false;
 
@@ -2778,7 +2757,7 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
        idx = dumper->cur_idx;
        prev = 0;
        while (seq < dumper->next_seq) {
-               struct log *msg = log_from_idx(idx);
+               struct printk_log *msg = log_from_idx(idx);
 
                l += msg_print_text(msg, prev, true, NULL, 0);
                idx = log_next(idx);
@@ -2791,7 +2770,7 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
        idx = dumper->cur_idx;
        prev = 0;
        while (l > size && seq < dumper->next_seq) {
-               struct log *msg = log_from_idx(idx);
+               struct printk_log *msg = log_from_idx(idx);
 
                l -= msg_print_text(msg, prev, true, NULL, 0);
                idx = log_next(idx);
@@ -2806,7 +2785,7 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
        l = 0;
        prev = 0;
        while (seq < dumper->next_seq) {
-               struct log *msg = log_from_idx(idx);
+               struct printk_log *msg = log_from_idx(idx);
 
                l += msg_print_text(msg, prev, syslog, buf + l, size - l);
                idx = log_next(idx);
index bb456f44b7b1cdbfc6b4e6be3b04cd6f22da6b4d..9565645e320218f394f36eb0edbaa95236bbfcd1 100644 (file)
@@ -851,7 +851,7 @@ void task_numa_fault(int node, int pages, bool migrated)
 {
        struct task_struct *p = current;
 
-       if (!sched_feat_numa(NUMA))
+       if (!numabalancing_enabled)
                return;
 
        /* FIXME: Allocate task-specific structure for placement policy here */
@@ -5786,7 +5786,7 @@ static void task_tick_fair(struct rq *rq, struct task_struct *curr, int queued)
                entity_tick(cfs_rq, se, queued);
        }
 
-       if (sched_feat_numa(NUMA))
+       if (numabalancing_enabled)
                task_tick_numa(rq, curr);
 
        update_rq_runnable_avg(rq, 1);
index ac09d98490aabc0729eb1a4691e8d2b1ec10a34c..07f6fc468e1732734e7fcf5f73982a93670e4194 100644 (file)
@@ -2346,7 +2346,11 @@ static int do_proc_dointvec_ms_jiffies_conv(bool *negp, unsigned long *lvalp,
                                            int write, void *data)
 {
        if (write) {
-               *valp = msecs_to_jiffies(*negp ? -*lvalp : *lvalp);
+               unsigned long jif = msecs_to_jiffies(*negp ? -*lvalp : *lvalp);
+
+               if (jif > INT_MAX)
+                       return 1;
+               *valp = (int)jif;
        } else {
                int val = *valp;
                unsigned long lval;
index e80183f4a6c4f3d6abea4b6d7720e381381259e0..e77edc97e036b4e8216ae8b54fe0e6cafaa2fe71 100644 (file)
@@ -827,13 +827,10 @@ void tick_nohz_irq_exit(void)
 {
        struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);
 
-       if (ts->inidle) {
-               /* Cancel the timer because CPU already waken up from the C-states*/
-               menu_hrtimer_cancel();
+       if (ts->inidle)
                __tick_nohz_idle_enter(ts);
-       } else {
+       else
                tick_nohz_full_stop_tick(ts);
-       }
 }
 
 /**
@@ -931,8 +928,6 @@ void tick_nohz_idle_exit(void)
 
        ts->inidle = 0;
 
-       /* Cancel the timer because CPU already waken up from the C-states*/
-       menu_hrtimer_cancel();
        if (ts->idle_active || ts->tick_stopped)
                now = ktime_get();
 
index 162becacf97c3650eb39e54b21a0139a9679a764..0a7e494b2bcdab875d7aebdef5ca7346972053b9 100644 (file)
@@ -2,3 +2,4 @@ mktables
 altivec*.c
 int*.c
 tables.c
+neon?.c
index 9f7c184725d7329d25fe35f1a0c3ae701243b753..b4625787c7eeb462d2ba220a5bf497fb522cf32c 100644 (file)
@@ -5,6 +5,7 @@ raid6_pq-y      += algos.o recov.o tables.o int1.o int2.o int4.o \
 
 raid6_pq-$(CONFIG_X86) += recov_ssse3.o recov_avx2.o mmx.o sse1.o sse2.o avx2.o
 raid6_pq-$(CONFIG_ALTIVEC) += altivec1.o altivec2.o altivec4.o altivec8.o
+raid6_pq-$(CONFIG_KERNEL_MODE_NEON) += neon.o neon1.o neon2.o neon4.o neon8.o
 
 hostprogs-y    += mktables
 
@@ -16,6 +17,21 @@ ifeq ($(CONFIG_ALTIVEC),y)
 altivec_flags := -maltivec -mabi=altivec
 endif
 
+# The GCC option -ffreestanding is required in order to compile code containing
+# ARM/NEON intrinsics in a non C99-compliant environment (such as the kernel)
+ifeq ($(CONFIG_KERNEL_MODE_NEON),y)
+NEON_FLAGS := -ffreestanding
+ifeq ($(ARCH),arm)
+NEON_FLAGS += -mfloat-abi=softfp -mfpu=neon
+endif
+ifeq ($(ARCH),arm64)
+CFLAGS_REMOVE_neon1.o += -mgeneral-regs-only
+CFLAGS_REMOVE_neon2.o += -mgeneral-regs-only
+CFLAGS_REMOVE_neon4.o += -mgeneral-regs-only
+CFLAGS_REMOVE_neon8.o += -mgeneral-regs-only
+endif
+endif
+
 targets += int1.c
 $(obj)/int1.c:   UNROLL := 1
 $(obj)/int1.c:   $(src)/int.uc $(src)/unroll.awk FORCE
@@ -70,6 +86,30 @@ $(obj)/altivec8.c:   UNROLL := 8
 $(obj)/altivec8.c:   $(src)/altivec.uc $(src)/unroll.awk FORCE
        $(call if_changed,unroll)
 
+CFLAGS_neon1.o += $(NEON_FLAGS)
+targets += neon1.c
+$(obj)/neon1.c:   UNROLL := 1
+$(obj)/neon1.c:   $(src)/neon.uc $(src)/unroll.awk FORCE
+       $(call if_changed,unroll)
+
+CFLAGS_neon2.o += $(NEON_FLAGS)
+targets += neon2.c
+$(obj)/neon2.c:   UNROLL := 2
+$(obj)/neon2.c:   $(src)/neon.uc $(src)/unroll.awk FORCE
+       $(call if_changed,unroll)
+
+CFLAGS_neon4.o += $(NEON_FLAGS)
+targets += neon4.c
+$(obj)/neon4.c:   UNROLL := 4
+$(obj)/neon4.c:   $(src)/neon.uc $(src)/unroll.awk FORCE
+       $(call if_changed,unroll)
+
+CFLAGS_neon8.o += $(NEON_FLAGS)
+targets += neon8.c
+$(obj)/neon8.c:   UNROLL := 8
+$(obj)/neon8.c:   $(src)/neon.uc $(src)/unroll.awk FORCE
+       $(call if_changed,unroll)
+
 quiet_cmd_mktable = TABLE   $@
       cmd_mktable = $(obj)/mktables > $@ || ( rm -f $@ && exit 1 )
 
index 6d7316fe9f30207d83bfe6f086ca98984040207d..74e6f5629dbc793464f402087818df6fea11ee1a 100644 (file)
@@ -70,6 +70,12 @@ const struct raid6_calls * const raid6_algos[] = {
        &raid6_intx2,
        &raid6_intx4,
        &raid6_intx8,
+#ifdef CONFIG_KERNEL_MODE_NEON
+       &raid6_neonx1,
+       &raid6_neonx2,
+       &raid6_neonx4,
+       &raid6_neonx8,
+#endif
        NULL
 };
 
diff --git a/lib/raid6/neon.c b/lib/raid6/neon.c
new file mode 100644 (file)
index 0000000..36ad470
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * linux/lib/raid6/neon.c - RAID6 syndrome calculation using ARM NEON intrinsics
+ *
+ * Copyright (C) 2013 Linaro Ltd <ard.biesheuvel@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/raid/pq.h>
+
+#ifdef __KERNEL__
+#include <asm/neon.h>
+#else
+#define kernel_neon_begin()
+#define kernel_neon_end()
+#define cpu_has_neon()         (1)
+#endif
+
+/*
+ * There are 2 reasons these wrappers are kept in a separate compilation unit
+ * from the actual implementations in neonN.c (generated from neon.uc by
+ * unroll.awk):
+ * - the actual implementations use NEON intrinsics, and the GCC support header
+ *   (arm_neon.h) is not fully compatible (type wise) with the kernel;
+ * - the neonN.c files are compiled with -mfpu=neon and optimization enabled,
+ *   and we have to make sure that we never use *any* NEON/VFP instructions
+ *   outside a kernel_neon_begin()/kernel_neon_end() pair.
+ */
+
+#define RAID6_NEON_WRAPPER(_n)                                         \
+       static void raid6_neon ## _n ## _gen_syndrome(int disks,        \
+                                       size_t bytes, void **ptrs)      \
+       {                                                               \
+               void raid6_neon ## _n  ## _gen_syndrome_real(int,       \
+                                               unsigned long, void**); \
+               kernel_neon_begin();                                    \
+               raid6_neon ## _n ## _gen_syndrome_real(disks,           \
+                                       (unsigned long)bytes, ptrs);    \
+               kernel_neon_end();                                      \
+       }                                                               \
+       struct raid6_calls const raid6_neonx ## _n = {                  \
+               raid6_neon ## _n ## _gen_syndrome,                      \
+               raid6_have_neon,                                        \
+               "neonx" #_n,                                            \
+               0                                                       \
+       }
+
+static int raid6_have_neon(void)
+{
+       return cpu_has_neon();
+}
+
+RAID6_NEON_WRAPPER(1);
+RAID6_NEON_WRAPPER(2);
+RAID6_NEON_WRAPPER(4);
+RAID6_NEON_WRAPPER(8);
diff --git a/lib/raid6/neon.uc b/lib/raid6/neon.uc
new file mode 100644 (file)
index 0000000..1b9ed79
--- /dev/null
@@ -0,0 +1,80 @@
+/* -----------------------------------------------------------------------
+ *
+ *   neon.uc - RAID-6 syndrome calculation using ARM NEON instructions
+ *
+ *   Copyright (C) 2012 Rob Herring
+ *
+ *   Based on altivec.uc:
+ *     Copyright 2002-2004 H. Peter Anvin - All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ *   Boston MA 02111-1307, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * neon$#.c
+ *
+ * $#-way unrolled NEON intrinsics math RAID-6 instruction set
+ *
+ * This file is postprocessed using unroll.awk
+ */
+
+#include <arm_neon.h>
+
+typedef uint8x16_t unative_t;
+
+#define NBYTES(x) ((unative_t){x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x})
+#define NSIZE  sizeof(unative_t)
+
+/*
+ * The SHLBYTE() operation shifts each byte left by 1, *not*
+ * rolling over into the next byte
+ */
+static inline unative_t SHLBYTE(unative_t v)
+{
+       return vshlq_n_u8(v, 1);
+}
+
+/*
+ * The MASK() operation returns 0xFF in any byte for which the high
+ * bit is 1, 0x00 for any byte for which the high bit is 0.
+ */
+static inline unative_t MASK(unative_t v)
+{
+       const uint8x16_t temp = NBYTES(0);
+       return (unative_t)vcltq_s8((int8x16_t)v, (int8x16_t)temp);
+}
+
+void raid6_neon$#_gen_syndrome_real(int disks, unsigned long bytes, void **ptrs)
+{
+       uint8_t **dptr = (uint8_t **)ptrs;
+       uint8_t *p, *q;
+       int d, z, z0;
+
+       register unative_t wd$$, wq$$, wp$$, w1$$, w2$$;
+       const unative_t x1d = NBYTES(0x1d);
+
+       z0 = disks - 3;         /* Highest data disk */
+       p = dptr[z0+1];         /* XOR parity */
+       q = dptr[z0+2];         /* RS syndrome */
+
+       for ( d = 0 ; d < bytes ; d += NSIZE*$# ) {
+               wq$$ = wp$$ = vld1q_u8(&dptr[z0][d+$$*NSIZE]);
+               for ( z = z0-1 ; z >= 0 ; z-- ) {
+                       wd$$ = vld1q_u8(&dptr[z][d+$$*NSIZE]);
+                       wp$$ = veorq_u8(wp$$, wd$$);
+                       w2$$ = MASK(wq$$);
+                       w1$$ = SHLBYTE(wq$$);
+
+                       w2$$ = vandq_u8(w2$$, x1d);
+                       w1$$ = veorq_u8(w1$$, w2$$);
+                       wq$$ = veorq_u8(w1$$, wd$$);
+               }
+               vst1q_u8(&p[d+NSIZE*$$], wp$$);
+               vst1q_u8(&q[d+NSIZE*$$], wq$$);
+       }
+}
index 087332dbf8aa164630148626e33c523dfd52dbf7..28afa1a06e033f264d2a9228d654e7fc50b6fea4 100644 (file)
@@ -22,11 +22,23 @@ ifeq ($(ARCH),x86_64)
         IS_X86 = yes
 endif
 
+ifeq ($(ARCH),arm)
+        CFLAGS += -I../../../arch/arm/include -mfpu=neon
+        HAS_NEON = yes
+endif
+ifeq ($(ARCH),arm64)
+        CFLAGS += -I../../../arch/arm64/include
+        HAS_NEON = yes
+endif
+
 ifeq ($(IS_X86),yes)
         OBJS   += mmx.o sse1.o sse2.o avx2.o recov_ssse3.o recov_avx2.o
         CFLAGS += $(shell echo "vpbroadcastb %xmm0, %ymm1" |   \
                     gcc -c -x assembler - >&/dev/null &&       \
                     rm ./-.o && echo -DCONFIG_AS_AVX2=1)
+else ifeq ($(HAS_NEON),yes)
+        OBJS   += neon.o neon1.o neon2.o neon4.o neon8.o
+        CFLAGS += -DCONFIG_KERNEL_MODE_NEON=1
 else
         HAS_ALTIVEC := $(shell echo -e '\#include <altivec.h>\nvector int a;' |\
                          gcc -c -x c - >&/dev/null && \
@@ -55,6 +67,18 @@ raid6.a: $(OBJS)
 raid6test: test.c raid6.a
        $(CC) $(CFLAGS) -o raid6test $^
 
+neon1.c: neon.uc ../unroll.awk
+       $(AWK) ../unroll.awk -vN=1 < neon.uc > $@
+
+neon2.c: neon.uc ../unroll.awk
+       $(AWK) ../unroll.awk -vN=2 < neon.uc > $@
+
+neon4.c: neon.uc ../unroll.awk
+       $(AWK) ../unroll.awk -vN=4 < neon.uc > $@
+
+neon8.c: neon.uc ../unroll.awk
+       $(AWK) ../unroll.awk -vN=8 < neon.uc > $@
+
 altivec1.c: altivec.uc ../unroll.awk
        $(AWK) ../unroll.awk -vN=1 < altivec.uc > $@
 
@@ -89,7 +113,7 @@ tables.c: mktables
        ./mktables > tables.c
 
 clean:
-       rm -f *.o *.a mktables mktables.c *.uc int*.c altivec*.c tables.c raid6test
+       rm -f *.o *.a mktables mktables.c *.uc int*.c altivec*.c neon*.c tables.c raid6test
 
 spotless: clean
        rm -f *~
index 243e710c6039a287f93ec9f303639c7316dbdf0e..a92012a71702e7156baba919e636bcfcce8971f2 100644 (file)
@@ -1620,7 +1620,9 @@ static void __split_huge_page_refcount(struct page *page,
                                     ((1L << PG_referenced) |
                                      (1L << PG_swapbacked) |
                                      (1L << PG_mlocked) |
-                                     (1L << PG_uptodate)));
+                                     (1L << PG_uptodate) |
+                                     (1L << PG_active) |
+                                     (1L << PG_unevictable)));
                page_tail->flags |= (1L << PG_dirty);
 
                /* clear PageTail before overwriting first_page */
index 00a7a664b9c16b92769f98fec8117e7c712e6ab1..c290a1cf38624adf8372d67ccf60d9ec01ff1357 100644 (file)
@@ -6335,6 +6335,7 @@ static void mem_cgroup_css_offline(struct cgroup *cont)
        mem_cgroup_invalidate_reclaim_iterators(memcg);
        mem_cgroup_reparent_charges(memcg);
        mem_cgroup_destroy_all_caches(memcg);
+       vmpressure_cleanup(&memcg->vmpressure);
 }
 
 static void mem_cgroup_css_free(struct cgroup *cont)
index 74310017296ee02317b79a2c28b25ef303fc7720..4baf12e534d19031d28ddc5eba5335f72de54099 100644 (file)
@@ -732,7 +732,10 @@ static int mbind_range(struct mm_struct *mm, unsigned long start,
                if (prev) {
                        vma = prev;
                        next = vma->vm_next;
-                       continue;
+                       if (mpol_equal(vma_policy(vma), new_pol))
+                               continue;
+                       /* vma_merge() joined vma && vma->next, case 8 */
+                       goto replace;
                }
                if (vma->vm_start != vmstart) {
                        err = split_vma(vma->vm_mm, vma, vmstart, 1);
@@ -744,6 +747,7 @@ static int mbind_range(struct mm_struct *mm, unsigned long start,
                        if (err)
                                goto out;
                }
+ replace:
                err = vma_replace_policy(vma, new_pol);
                if (err)
                        goto out;
index fbad7b091090d12ba0b101815fdc8699b092ee0d..1edbaa3136c3c464cf648e569f2f98499f00642c 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -865,7 +865,7 @@ again:                      remove_next = 1 + (end > next->vm_end);
                if (next->anon_vma)
                        anon_vma_merge(vma, next);
                mm->map_count--;
-               vma_set_policy(vma, vma_policy(next));
+               mpol_put(vma_policy(next));
                kmem_cache_free(vm_area_cachep, next);
                /*
                 * In mprotect's case 6 (see comments on vma_merge),
index 2b02d666bf63aee43e60e17fab4544e31730383c..59eb122c51e7d54da5153b7c86f07e5c498f90ba 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -373,7 +373,8 @@ static inline bool __cmpxchg_double_slab(struct kmem_cache *s, struct page *page
 #endif
        {
                slab_lock(page);
-               if (page->freelist == freelist_old && page->counters == counters_old) {
+               if (page->freelist == freelist_old &&
+                                       page->counters == counters_old) {
                        page->freelist = freelist_new;
                        page->counters = counters_new;
                        slab_unlock(page);
@@ -411,7 +412,8 @@ static inline bool cmpxchg_double_slab(struct kmem_cache *s, struct page *page,
 
                local_irq_save(flags);
                slab_lock(page);
-               if (page->freelist == freelist_old && page->counters == counters_old) {
+               if (page->freelist == freelist_old &&
+                                       page->counters == counters_old) {
                        page->freelist = freelist_new;
                        page->counters = counters_new;
                        slab_unlock(page);
@@ -553,8 +555,9 @@ static void print_tracking(struct kmem_cache *s, void *object)
 
 static void print_page_info(struct page *page)
 {
-       printk(KERN_ERR "INFO: Slab 0x%p objects=%u used=%u fp=0x%p flags=0x%04lx\n",
-               page, page->objects, page->inuse, page->freelist, page->flags);
+       printk(KERN_ERR
+              "INFO: Slab 0x%p objects=%u used=%u fp=0x%p flags=0x%04lx\n",
+              page, page->objects, page->inuse, page->freelist, page->flags);
 
 }
 
@@ -629,7 +632,8 @@ static void object_err(struct kmem_cache *s, struct page *page,
        print_trailer(s, page, object);
 }
 
-static void slab_err(struct kmem_cache *s, struct page *page, const char *fmt, ...)
+static void slab_err(struct kmem_cache *s, struct page *page,
+                       const char *fmt, ...)
 {
        va_list args;
        char buf[100];
@@ -788,7 +792,8 @@ static int check_object(struct kmem_cache *s, struct page *page,
        } else {
                if ((s->flags & SLAB_POISON) && s->object_size < s->inuse) {
                        check_bytes_and_report(s, page, p, "Alignment padding",
-                               endobject, POISON_INUSE, s->inuse - s->object_size);
+                               endobject, POISON_INUSE,
+                               s->inuse - s->object_size);
                }
        }
 
@@ -918,7 +923,8 @@ static void trace(struct kmem_cache *s, struct page *page, void *object,
                        page->freelist);
 
                if (!alloc)
-                       print_section("Object ", (void *)object, s->object_size);
+                       print_section("Object ", (void *)object,
+                                       s->object_size);
 
                dump_stack();
        }
@@ -937,7 +943,8 @@ static inline int slab_pre_alloc_hook(struct kmem_cache *s, gfp_t flags)
        return should_failslab(s->object_size, flags, s->flags);
 }
 
-static inline void slab_post_alloc_hook(struct kmem_cache *s, gfp_t flags, void *object)
+static inline void slab_post_alloc_hook(struct kmem_cache *s,
+                                       gfp_t flags, void *object)
 {
        flags &= gfp_allowed_mask;
        kmemcheck_slab_alloc(s, flags, object, slab_ksize(s));
@@ -1039,7 +1046,8 @@ static void setup_object_debug(struct kmem_cache *s, struct page *page,
        init_tracking(s, object);
 }
 
-static noinline int alloc_debug_processing(struct kmem_cache *s, struct page *page,
+static noinline int alloc_debug_processing(struct kmem_cache *s,
+                                       struct page *page,
                                        void *object, unsigned long addr)
 {
        if (!check_slab(s, page))
@@ -1743,7 +1751,8 @@ static void init_kmem_cache_cpus(struct kmem_cache *s)
 /*
  * Remove the cpu slab
  */
-static void deactivate_slab(struct kmem_cache *s, struct page *page, void *freelist)
+static void deactivate_slab(struct kmem_cache *s, struct page *page,
+                               void *freelist)
 {
        enum slab_modes { M_NONE, M_PARTIAL, M_FULL, M_FREE };
        struct kmem_cache_node *n = get_node(s, page_to_nid(page));
@@ -2002,7 +2011,8 @@ static void put_cpu_partial(struct kmem_cache *s, struct page *page, int drain)
                page->pobjects = pobjects;
                page->next = oldpage;
 
-       } while (this_cpu_cmpxchg(s->cpu_slab->partial, oldpage, page) != oldpage);
+       } while (this_cpu_cmpxchg(s->cpu_slab->partial, oldpage, page)
+                                                               != oldpage);
 #endif
 }
 
@@ -2172,8 +2182,8 @@ static inline bool pfmemalloc_match(struct page *page, gfp_t gfpflags)
 }
 
 /*
- * Check the page->freelist of a page and either transfer the freelist to the per cpu freelist
- * or deactivate the page.
+ * Check the page->freelist of a page and either transfer the freelist to the
+ * per cpu freelist or deactivate the page.
  *
  * The page is still frozen if the return value is not NULL.
  *
@@ -2317,7 +2327,8 @@ new_slab:
                goto load_freelist;
 
        /* Only entered in the debug case */
-       if (kmem_cache_debug(s) && !alloc_debug_processing(s, page, freelist, addr))
+       if (kmem_cache_debug(s) &&
+                       !alloc_debug_processing(s, page, freelist, addr))
                goto new_slab;  /* Slab failed checks. Next slab needed */
 
        deactivate_slab(s, page, get_freepointer(s, freelist));
@@ -2385,13 +2396,15 @@ redo:
                 * The cmpxchg will only match if there was no additional
                 * operation and if we are on the right processor.
                 *
-                * The cmpxchg does the following atomically (without lock semantics!)
+                * The cmpxchg does the following atomically (without lock
+                * semantics!)
                 * 1. Relocate first pointer to the current per cpu area.
                 * 2. Verify that tid and freelist have not been changed
                 * 3. If they were not changed replace tid and freelist
                 *
-                * Since this is without lock semantics the protection is only against
-                * code executing on this cpu *not* from access by other cpus.
+                * Since this is without lock semantics the protection is only
+                * against code executing on this cpu *not* from access by
+                * other cpus.
                 */
                if (unlikely(!this_cpu_cmpxchg_double(
                                s->cpu_slab->freelist, s->cpu_slab->tid,
@@ -2423,7 +2436,8 @@ void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags)
 {
        void *ret = slab_alloc(s, gfpflags, _RET_IP_);
 
-       trace_kmem_cache_alloc(_RET_IP_, ret, s->object_size, s->size, gfpflags);
+       trace_kmem_cache_alloc(_RET_IP_, ret, s->object_size,
+                               s->size, gfpflags);
 
        return ret;
 }
@@ -2515,8 +2529,10 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
                        if (kmem_cache_has_cpu_partial(s) && !prior)
 
                                /*
-                                * Slab was on no list before and will be partially empty
-                                * We can defer the list move and instead freeze it.
+                                * Slab was on no list before and will be
+                                * partially empty
+                                * We can defer the list move and instead
+                                * freeze it.
                                 */
                                new.frozen = 1;
 
@@ -3074,8 +3090,8 @@ static int kmem_cache_open(struct kmem_cache *s, unsigned long flags)
         * A) The number of objects from per cpu partial slabs dumped to the
         *    per node list when we reach the limit.
         * B) The number of objects in cpu partial slabs to extract from the
-        *    per node list when we run out of per cpu objects. We only fetch 50%
-        *    to keep some capacity around for frees.
+        *    per node list when we run out of per cpu objects. We only fetch
+        *    50% to keep some capacity around for frees.
         */
        if (!kmem_cache_has_cpu_partial(s))
                s->cpu_partial = 0;
@@ -3102,8 +3118,8 @@ error:
        if (flags & SLAB_PANIC)
                panic("Cannot create slab %s size=%lu realsize=%u "
                        "order=%u offset=%u flags=%lx\n",
-                       s->name, (unsigned long)s->size, s->size, oo_order(s->oo),
-                       s->offset, flags);
+                       s->name, (unsigned long)s->size, s->size,
+                       oo_order(s->oo), s->offset, flags);
        return -EINVAL;
 }
 
@@ -3341,7 +3357,8 @@ bool verify_mem_not_deleted(const void *x)
 
        slab_lock(page);
        if (on_freelist(page->slab_cache, page, object)) {
-               object_err(page->slab_cache, page, object, "Object is on free-list");
+               object_err(page->slab_cache, page, object,
+                               "Object is on free-list");
                rv = false;
        } else {
                rv = true;
@@ -4165,15 +4182,17 @@ static int list_locations(struct kmem_cache *s, char *buf,
                                !cpumask_empty(to_cpumask(l->cpus)) &&
                                len < PAGE_SIZE - 60) {
                        len += sprintf(buf + len, " cpus=");
-                       len += cpulist_scnprintf(buf + len, PAGE_SIZE - len - 50,
+                       len += cpulist_scnprintf(buf + len,
+                                                PAGE_SIZE - len - 50,
                                                 to_cpumask(l->cpus));
                }
 
                if (nr_online_nodes > 1 && !nodes_empty(l->nodes) &&
                                len < PAGE_SIZE - 60) {
                        len += sprintf(buf + len, " nodes=");
-                       len += nodelist_scnprintf(buf + len, PAGE_SIZE - len - 50,
-                                       l->nodes);
+                       len += nodelist_scnprintf(buf + len,
+                                                 PAGE_SIZE - len - 50,
+                                                 l->nodes);
                }
 
                len += sprintf(buf + len, "\n");
@@ -4271,18 +4290,17 @@ static ssize_t show_slab_objects(struct kmem_cache *s,
        int node;
        int x;
        unsigned long *nodes;
-       unsigned long *per_cpu;
 
-       nodes = kzalloc(2 * sizeof(unsigned long) * nr_node_ids, GFP_KERNEL);
+       nodes = kzalloc(sizeof(unsigned long) * nr_node_ids, GFP_KERNEL);
        if (!nodes)
                return -ENOMEM;
-       per_cpu = nodes + nr_node_ids;
 
        if (flags & SO_CPU) {
                int cpu;
 
                for_each_possible_cpu(cpu) {
-                       struct kmem_cache_cpu *c = per_cpu_ptr(s->cpu_slab, cpu);
+                       struct kmem_cache_cpu *c = per_cpu_ptr(s->cpu_slab,
+                                                              cpu);
                        int node;
                        struct page *page;
 
@@ -4307,8 +4325,6 @@ static ssize_t show_slab_objects(struct kmem_cache *s,
                                total += x;
                                nodes[node] += x;
                        }
-
-                       per_cpu[node]++;
                }
        }
 
@@ -4318,12 +4334,11 @@ static ssize_t show_slab_objects(struct kmem_cache *s,
                for_each_node_state(node, N_NORMAL_MEMORY) {
                        struct kmem_cache_node *n = get_node(s, node);
 
-               if (flags & SO_TOTAL)
-                       x = atomic_long_read(&n->total_objects);
-               else if (flags & SO_OBJECTS)
-                       x = atomic_long_read(&n->total_objects) -
-                               count_partial(n, count_free);
-
+                       if (flags & SO_TOTAL)
+                               x = atomic_long_read(&n->total_objects);
+                       else if (flags & SO_OBJECTS)
+                               x = atomic_long_read(&n->total_objects) -
+                                       count_partial(n, count_free);
                        else
                                x = atomic_long_read(&n->nr_slabs);
                        total += x;
@@ -5139,7 +5154,8 @@ static char *create_unique_id(struct kmem_cache *s)
 
 #ifdef CONFIG_MEMCG_KMEM
        if (!is_root_cache(s))
-               p += sprintf(p, "-%08d", memcg_cache_id(s->memcg_params->memcg));
+               p += sprintf(p, "-%08d",
+                               memcg_cache_id(s->memcg_params->memcg));
 #endif
 
        BUG_ON(p > name + ID_STR_LENGTH - 1);
index 4a1d0d2c52fa4ab4ca66ff4a2025e093521556c9..62b78a6e224f2f10682e9fa11f28b8d01da1c324 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -512,12 +512,7 @@ EXPORT_SYMBOL(__lru_cache_add);
  */
 void lru_cache_add(struct page *page)
 {
-       if (PageActive(page)) {
-               VM_BUG_ON(PageUnevictable(page));
-       } else if (PageUnevictable(page)) {
-               VM_BUG_ON(PageActive(page));
-       }
-
+       VM_BUG_ON(PageActive(page) && PageUnevictable(page));
        VM_BUG_ON(PageLRU(page));
        __lru_cache_add(page);
 }
@@ -539,6 +534,7 @@ void add_page_to_unevictable_list(struct page *page)
 
        spin_lock_irq(&zone->lru_lock);
        lruvec = mem_cgroup_page_lruvec(page, zone);
+       ClearPageActive(page);
        SetPageUnevictable(page);
        SetPageLRU(page);
        add_page_to_lru_list(page, lruvec, LRU_UNEVICTABLE);
@@ -774,8 +770,6 @@ EXPORT_SYMBOL(__pagevec_release);
 void lru_add_page_tail(struct page *page, struct page *page_tail,
                       struct lruvec *lruvec, struct list_head *list)
 {
-       int uninitialized_var(active);
-       enum lru_list lru;
        const int file = 0;
 
        VM_BUG_ON(!PageHead(page));
@@ -787,20 +781,6 @@ void lru_add_page_tail(struct page *page, struct page *page_tail,
        if (!list)
                SetPageLRU(page_tail);
 
-       if (page_evictable(page_tail)) {
-               if (PageActive(page)) {
-                       SetPageActive(page_tail);
-                       active = 1;
-                       lru = LRU_ACTIVE_ANON;
-               } else {
-                       active = 0;
-                       lru = LRU_INACTIVE_ANON;
-               }
-       } else {
-               SetPageUnevictable(page_tail);
-               lru = LRU_UNEVICTABLE;
-       }
-
        if (likely(PageLRU(page)))
                list_add_tail(&page_tail->lru, &page->lru);
        else if (list) {
@@ -816,13 +796,13 @@ void lru_add_page_tail(struct page *page, struct page *page_tail,
                 * Use the standard add function to put page_tail on the list,
                 * but then correct its position so they all end up in order.
                 */
-               add_page_to_lru_list(page_tail, lruvec, lru);
+               add_page_to_lru_list(page_tail, lruvec, page_lru(page_tail));
                list_head = page_tail->lru.prev;
                list_move_tail(&page_tail->lru, list_head);
        }
 
        if (!PageUnevictable(page))
-               update_page_reclaim_stat(lruvec, file, active);
+               update_page_reclaim_stat(lruvec, file, PageActive(page_tail));
 }
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
@@ -833,7 +813,6 @@ static void __pagevec_lru_add_fn(struct page *page, struct lruvec *lruvec,
        int active = PageActive(page);
        enum lru_list lru = page_lru(page);
 
-       VM_BUG_ON(PageUnevictable(page));
        VM_BUG_ON(PageLRU(page));
 
        SetPageLRU(page);
index 736a6011c2c88606cc7908fe429b14823be18625..0c1e37d829fa026a9fc61ef93b569087939867c5 100644 (file)
@@ -180,12 +180,12 @@ static void vmpressure_work_fn(struct work_struct *work)
        if (!vmpr->scanned)
                return;
 
-       mutex_lock(&vmpr->sr_lock);
+       spin_lock(&vmpr->sr_lock);
        scanned = vmpr->scanned;
        reclaimed = vmpr->reclaimed;
        vmpr->scanned = 0;
        vmpr->reclaimed = 0;
-       mutex_unlock(&vmpr->sr_lock);
+       spin_unlock(&vmpr->sr_lock);
 
        do {
                if (vmpressure_event(vmpr, scanned, reclaimed))
@@ -240,13 +240,13 @@ void vmpressure(gfp_t gfp, struct mem_cgroup *memcg,
        if (!scanned)
                return;
 
-       mutex_lock(&vmpr->sr_lock);
+       spin_lock(&vmpr->sr_lock);
        vmpr->scanned += scanned;
        vmpr->reclaimed += reclaimed;
        scanned = vmpr->scanned;
-       mutex_unlock(&vmpr->sr_lock);
+       spin_unlock(&vmpr->sr_lock);
 
-       if (scanned < vmpressure_win || work_pending(&vmpr->work))
+       if (scanned < vmpressure_win)
                return;
        schedule_work(&vmpr->work);
 }
@@ -367,8 +367,24 @@ void vmpressure_unregister_event(struct cgroup *cg, struct cftype *cft,
  */
 void vmpressure_init(struct vmpressure *vmpr)
 {
-       mutex_init(&vmpr->sr_lock);
+       spin_lock_init(&vmpr->sr_lock);
        mutex_init(&vmpr->events_lock);
        INIT_LIST_HEAD(&vmpr->events);
        INIT_WORK(&vmpr->work, vmpressure_work_fn);
 }
+
+/**
+ * vmpressure_cleanup() - shuts down vmpressure control structure
+ * @vmpr:      Structure to be cleaned up
+ *
+ * This function should be called before the structure in which it is
+ * embedded is cleaned up.
+ */
+void vmpressure_cleanup(struct vmpressure *vmpr)
+{
+       /*
+        * Make sure there is no pending work before eventfd infrastructure
+        * goes away.
+        */
+       flush_work(&vmpr->work);
+}
index 9bb4710e35898b61c6824253501107898db76f36..ad1e781284fdd48492e7bac46c245fae5d578f95 100644 (file)
--- a/mm/zbud.c
+++ b/mm/zbud.c
@@ -257,7 +257,7 @@ int zbud_alloc(struct zbud_pool *pool, int size, gfp_t gfp,
 
        if (size <= 0 || gfp & __GFP_HIGHMEM)
                return -EINVAL;
-       if (size > PAGE_SIZE - ZHDR_SIZE_ALIGNED)
+       if (size > PAGE_SIZE - ZHDR_SIZE_ALIGNED - CHUNK_SIZE)
                return -ENOSPC;
        chunks = size_to_chunks(size);
        spin_lock(&pool->lock);
index 2fb2d88e8c2e329ec11653c20478bede1c4e5ad8..03a92e1176579a9acf486735bbf5a724e64f2067 100644 (file)
@@ -459,6 +459,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
 
        case NETDEV_NOTIFY_PEERS:
        case NETDEV_BONDING_FAILOVER:
+       case NETDEV_RESEND_IGMP:
                /* Propagate to vlan devices */
                vlan_group_for_each_dev(grp, i, vlandev)
                        call_netdevice_notifiers(event, vlandev);
index 8b93cae2d11d7d013d50c276bd08fc11a1187d08..ba93bdab2701939e2488b30c5c55be315acb0670 100644 (file)
@@ -658,17 +658,12 @@ static int p9_client_flush(struct p9_client *c, struct p9_req_t *oldreq)
 
        /*
         * if we haven't received a response for oldreq,
-        * remove it from the list, and notify the transport
-        * layer that the reply will never arrive.
+        * remove it from the list
         */
-       spin_lock(&c->lock);
        if (oldreq->status == REQ_STATUS_FLSH) {
+               spin_lock(&c->lock);
                list_del(&oldreq->req_list);
                spin_unlock(&c->lock);
-               if (c->trans_mod->cancelled)
-                       c->trans_mod->cancelled(c, req);
-       } else {
-               spin_unlock(&c->lock);
        }
 
        p9_free_req(c, req);
index 928f2bb9bf8d5d4d43d6324c3ea989a9daf12728..8f68df5d29731cf23b6de1bbee5284c904006c93 100644 (file)
@@ -588,17 +588,6 @@ static int rdma_cancel(struct p9_client *client, struct p9_req_t *req)
        return 1;
 }
 
-/* A request has been fully flushed without a reply.
- * That means we have posted one buffer in excess.
- */
-static int rdma_cancelled(struct p9_client *client, struct p9_req_t *req)
-{
-       struct p9_trans_rdma *rdma = client->trans;
-
-       atomic_inc(&rdma->excess_rc);
-       return 0;
-}
-
 /**
  * trans_create_rdma - Transport method for creating atransport instance
  * @client: client instance
index 37702491abe98eedd91738408851c56d3a8ea3a5..ee0213667272cc8eb5425af16921c69bee385311 100644 (file)
@@ -244,7 +244,7 @@ config NETPRIO_CGROUP
          Cgroup subsystem for use in assigning processes to network priorities on
          a per-interface basis
 
-config NET_LL_RX_POLL
+config NET_RX_BUSY_POLL
        boolean
        default y
 
@@ -281,7 +281,7 @@ menu "Network testing"
 
 config NET_PKTGEN
        tristate "Packet Generator (USE WITH CAUTION)"
-       depends on PROC_FS
+       depends on INET && PROC_FS
        ---help---
          This module will inject preconfigured packets, at a configurable
          rate, out of a given interface.  It is used for network interface
index e3a349977595f2aff6bd27f49e2ee9ee00164470..b91cc08d5e8247d074f22ea28fa2831cdd3dc95d 100644 (file)
@@ -513,7 +513,10 @@ static void hci_init2_req(struct hci_request *req, unsigned long opt)
 
        hci_setup_event_mask(req);
 
-       if (hdev->hci_ver > BLUETOOTH_VER_1_1)
+       /* AVM Berlin (31), aka "BlueFRITZ!", doesn't support the read
+        * local supported commands HCI command.
+        */
+       if (hdev->manufacturer != 31 && hdev->hci_ver > BLUETOOTH_VER_1_1)
                hci_req_add(req, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL);
 
        if (lmp_ssp_capable(hdev)) {
@@ -605,7 +608,7 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt)
         * as supported send it. If not supported assume that the controller
         * does not have actual support for stored link keys which makes this
         * command redundant anyway.
-         */
+        */
        if (hdev->commands[6] & 0x80) {
                struct hci_cp_delete_stored_link_key cp;
 
@@ -2165,10 +2168,6 @@ int hci_register_dev(struct hci_dev *hdev)
 
        BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
 
-       write_lock(&hci_dev_list_lock);
-       list_add(&hdev->list, &hci_dev_list);
-       write_unlock(&hci_dev_list_lock);
-
        hdev->workqueue = alloc_workqueue("%s", WQ_HIGHPRI | WQ_UNBOUND |
                                          WQ_MEM_RECLAIM, 1, hdev->name);
        if (!hdev->workqueue) {
@@ -2203,6 +2202,10 @@ int hci_register_dev(struct hci_dev *hdev)
        if (hdev->dev_type != HCI_AMP)
                set_bit(HCI_AUTO_OFF, &hdev->dev_flags);
 
+       write_lock(&hci_dev_list_lock);
+       list_add(&hdev->list, &hci_dev_list);
+       write_unlock(&hci_dev_list_lock);
+
        hci_notify(hdev, HCI_DEV_REG);
        hci_dev_hold(hdev);
 
@@ -2215,9 +2218,6 @@ err_wqueue:
        destroy_workqueue(hdev->req_workqueue);
 err:
        ida_simple_remove(&hci_index_ida, hdev->id);
-       write_lock(&hci_dev_list_lock);
-       list_del(&hdev->list);
-       write_unlock(&hci_dev_list_lock);
 
        return error;
 }
@@ -3399,8 +3399,16 @@ void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status)
         */
        if (hdev->sent_cmd) {
                req_complete = bt_cb(hdev->sent_cmd)->req.complete;
-               if (req_complete)
+
+               if (req_complete) {
+                       /* We must set the complete callback to NULL to
+                        * avoid calling the callback more than once if
+                        * this function gets called again.
+                        */
+                       bt_cb(hdev->sent_cmd)->req.complete = NULL;
+
                        goto call_complete;
+               }
        }
 
        /* Remove all pending commands belonging to this request */
index 0437200d92f45ca90bb09f3cad13d15c40a851de..50e39f4ad4299695be6b99c02f5907e4eefd7693 100644 (file)
@@ -3024,17 +3024,20 @@ unlock:
 static u8 hci_get_auth_req(struct hci_conn *conn)
 {
        /* If remote requests dedicated bonding follow that lead */
-       if (conn->remote_auth == 0x02 || conn->remote_auth == 0x03) {
+       if (conn->remote_auth == HCI_AT_DEDICATED_BONDING ||
+           conn->remote_auth == HCI_AT_DEDICATED_BONDING_MITM) {
                /* If both remote and local IO capabilities allow MITM
                 * protection then require it, otherwise don't */
-               if (conn->remote_cap == 0x03 || conn->io_capability == 0x03)
-                       return 0x02;
+               if (conn->remote_cap == HCI_IO_NO_INPUT_OUTPUT ||
+                   conn->io_capability == HCI_IO_NO_INPUT_OUTPUT)
+                       return HCI_AT_DEDICATED_BONDING;
                else
-                       return 0x03;
+                       return HCI_AT_DEDICATED_BONDING_MITM;
        }
 
        /* If remote requests no-bonding follow that lead */
-       if (conn->remote_auth == 0x00 || conn->remote_auth == 0x01)
+       if (conn->remote_auth == HCI_AT_NO_BONDING ||
+           conn->remote_auth == HCI_AT_NO_BONDING_MITM)
                return conn->remote_auth | (conn->auth_type & 0x01);
 
        return conn->auth_type;
@@ -3066,7 +3069,7 @@ static void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
                /* Change the IO capability from KeyboardDisplay
                 * to DisplayYesNo as it is not supported by BT spec. */
                cp.capability = (conn->io_capability == 0x04) ?
-                                               0x01 : conn->io_capability;
+                               HCI_IO_DISPLAY_YESNO : conn->io_capability;
                conn->auth_type = hci_get_auth_req(conn);
                cp.authentication = conn->auth_type;
 
@@ -3140,7 +3143,8 @@ static void hci_user_confirm_request_evt(struct hci_dev *hdev,
         * request. The only exception is when we're dedicated bonding
         * initiators (connect_cfm_cb set) since then we always have the MITM
         * bit set. */
-       if (!conn->connect_cfm_cb && loc_mitm && conn->remote_cap == 0x03) {
+       if (!conn->connect_cfm_cb && loc_mitm &&
+           conn->remote_cap == HCI_IO_NO_INPUT_OUTPUT) {
                BT_DBG("Rejecting request: remote device can't provide MITM");
                hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_NEG_REPLY,
                             sizeof(ev->bdaddr), &ev->bdaddr);
@@ -3148,8 +3152,8 @@ static void hci_user_confirm_request_evt(struct hci_dev *hdev,
        }
 
        /* If no side requires MITM protection; auto-accept */
-       if ((!loc_mitm || conn->remote_cap == 0x03) &&
-           (!rem_mitm || conn->io_capability == 0x03)) {
+       if ((!loc_mitm || conn->remote_cap == HCI_IO_NO_INPUT_OUTPUT) &&
+           (!rem_mitm || conn->io_capability == HCI_IO_NO_INPUT_OUTPUT)) {
 
                /* If we're not the initiators request authorization to
                 * proceed from user space (mgmt_user_confirm with
index 0c699cdc3696edbdf7e7c3d3e213a88979da662e..bdc35a7a7feeaf4ac7a918547e82d5d19a7ef537 100644 (file)
@@ -225,17 +225,47 @@ static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb)
 
 static int hidp_send_report(struct hidp_session *session, struct hid_report *report)
 {
-       unsigned char buf[32], hdr;
-       int rsize;
+       unsigned char hdr;
+       u8 *buf;
+       int rsize, ret;
 
-       rsize = ((report->size - 1) >> 3) + 1 + (report->id > 0);
-       if (rsize > sizeof(buf))
+       buf = hid_alloc_report_buf(report, GFP_ATOMIC);
+       if (!buf)
                return -EIO;
 
        hid_output_report(report, buf);
        hdr = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT;
 
-       return hidp_send_intr_message(session, hdr, buf, rsize);
+       rsize = ((report->size - 1) >> 3) + 1 + (report->id > 0);
+       ret = hidp_send_intr_message(session, hdr, buf, rsize);
+
+       kfree(buf);
+       return ret;
+}
+
+static int hidp_hidinput_event(struct input_dev *dev, unsigned int type,
+                              unsigned int code, int value)
+{
+       struct hid_device *hid = input_get_drvdata(dev);
+       struct hidp_session *session = hid->driver_data;
+       struct hid_field *field;
+       int offset;
+
+       BT_DBG("session %p type %d code %d value %d",
+              session, type, code, value);
+
+       if (type != EV_LED)
+               return -1;
+
+       offset = hidinput_find_field(hid, type, code, &field);
+       if (offset == -1) {
+               hid_warn(dev, "event field not found\n");
+               return -1;
+       }
+
+       hid_set_field(field, offset, value);
+
+       return hidp_send_report(session, field->report);
 }
 
 static int hidp_get_raw_report(struct hid_device *hid,
@@ -678,20 +708,6 @@ static int hidp_parse(struct hid_device *hid)
 
 static int hidp_start(struct hid_device *hid)
 {
-       struct hidp_session *session = hid->driver_data;
-       struct hid_report *report;
-
-       if (hid->quirks & HID_QUIRK_NO_INIT_REPORTS)
-               return 0;
-
-       list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].
-                       report_list, list)
-               hidp_send_report(session, report);
-
-       list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].
-                       report_list, list)
-               hidp_send_report(session, report);
-
        return 0;
 }
 
@@ -711,6 +727,7 @@ static struct hid_ll_driver hidp_hid_driver = {
        .stop = hidp_stop,
        .open  = hidp_open,
        .close = hidp_close,
+       .hidinput_input_event = hidp_hidinput_event,
 };
 
 /* This function sets up the hid device. It does not add it
index 8c3499bec89319289073b2f1e7f3f202cd179ca6..b3bb7bca8e606439edbd9f9838bb8021200bb28c 100644 (file)
@@ -1415,8 +1415,9 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
                        sk->sk_state_change(sk);
                        release_sock(sk);
 
-               } else if (chan->state == BT_CONNECT)
+               } else if (chan->state == BT_CONNECT) {
                        l2cap_do_start(chan);
+               }
 
                l2cap_chan_unlock(chan);
        }
index 2ef66781fedb3a9211448fa3db73eedab2c7d8a2..0feaaa0d37d11979999a898fe297f0e31397c07b 100644 (file)
@@ -70,7 +70,8 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
                }
 
                mdst = br_mdb_get(br, skb, vid);
-               if (mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb))
+               if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) &&
+                   br_multicast_querier_exists(br))
                        br_multicast_deliver(mdst, skb);
                else
                        br_flood_deliver(br, skb, false);
@@ -244,22 +245,22 @@ fail:
 int br_netpoll_enable(struct net_bridge_port *p, gfp_t gfp)
 {
        struct netpoll *np;
-       int err = 0;
+       int err;
+
+       if (!p->br->dev->npinfo)
+               return 0;
 
        np = kzalloc(sizeof(*p->np), gfp);
-       err = -ENOMEM;
        if (!np)
-               goto out;
+               return -ENOMEM;
 
        err = __netpoll_setup(np, p->dev, gfp);
        if (err) {
                kfree(np);
-               goto out;
+               return err;
        }
 
        p->np = np;
-
-out:
        return err;
 }
 
index 5623be6b9ecda3f77d62cb2db7fc5e9aef2bd65c..aa6c9a8ba32a8df827e0749c6c4f870f6c3f2362 100644 (file)
@@ -363,7 +363,8 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
        if (err)
                goto err2;
 
-       if (br_netpoll_info(br) && ((err = br_netpoll_enable(p, GFP_KERNEL))))
+       err = br_netpoll_enable(p, GFP_KERNEL);
+       if (err)
                goto err3;
 
        err = netdev_master_upper_dev_link(dev, br->dev);
index 1b8b8b824cd766b05665e1d89f0e1394abdfbe2f..8c561c0aa636e49615b13e267c98e4e5bdce1a23 100644 (file)
@@ -101,7 +101,8 @@ int br_handle_frame_finish(struct sk_buff *skb)
                unicast = false;
        } else if (is_multicast_ether_addr(dest)) {
                mdst = br_mdb_get(br, skb, vid);
-               if (mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) {
+               if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) &&
+                   br_multicast_querier_exists(br)) {
                        if ((mdst && mdst->mglist) ||
                            br_multicast_is_router(br))
                                skb2 = skb;
index 69af490cce4437bdc107f8b5b1216780b4c126af..61c5e819380e52d6347cde7186251467e921c1a0 100644 (file)
@@ -619,6 +619,9 @@ rehash:
        mp->br = br;
        mp->addr = *group;
 
+       setup_timer(&mp->timer, br_multicast_group_expired,
+                   (unsigned long)mp);
+
        hlist_add_head_rcu(&mp->hlist[mdb->ver], &mdb->mhash[hash]);
        mdb->size++;
 
@@ -1011,6 +1014,16 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
 }
 #endif
 
+static void br_multicast_update_querier_timer(struct net_bridge *br,
+                                             unsigned long max_delay)
+{
+       if (!timer_pending(&br->multicast_querier_timer))
+               br->multicast_querier_delay_time = jiffies + max_delay;
+
+       mod_timer(&br->multicast_querier_timer,
+                 jiffies + br->multicast_querier_interval);
+}
+
 /*
  * Add port to router_list
  *  list is maintained ordered by pointer value
@@ -1061,11 +1074,11 @@ timer:
 
 static void br_multicast_query_received(struct net_bridge *br,
                                        struct net_bridge_port *port,
-                                       int saddr)
+                                       int saddr,
+                                       unsigned long max_delay)
 {
        if (saddr)
-               mod_timer(&br->multicast_querier_timer,
-                         jiffies + br->multicast_querier_interval);
+               br_multicast_update_querier_timer(br, max_delay);
        else if (timer_pending(&br->multicast_querier_timer))
                return;
 
@@ -1093,8 +1106,6 @@ static int br_ip4_multicast_query(struct net_bridge *br,
            (port && port->state == BR_STATE_DISABLED))
                goto out;
 
-       br_multicast_query_received(br, port, !!iph->saddr);
-
        group = ih->group;
 
        if (skb->len == sizeof(*ih)) {
@@ -1118,6 +1129,8 @@ static int br_ip4_multicast_query(struct net_bridge *br,
                            IGMPV3_MRC(ih3->code) * (HZ / IGMP_TIMER_SCALE) : 1;
        }
 
+       br_multicast_query_received(br, port, !!iph->saddr, max_delay);
+
        if (!group)
                goto out;
 
@@ -1126,7 +1139,6 @@ static int br_ip4_multicast_query(struct net_bridge *br,
        if (!mp)
                goto out;
 
-       setup_timer(&mp->timer, br_multicast_group_expired, (unsigned long)mp);
        mod_timer(&mp->timer, now + br->multicast_membership_interval);
        mp->timer_armed = true;
 
@@ -1174,8 +1186,6 @@ static int br_ip6_multicast_query(struct net_bridge *br,
            (port && port->state == BR_STATE_DISABLED))
                goto out;
 
-       br_multicast_query_received(br, port, !ipv6_addr_any(&ip6h->saddr));
-
        if (skb->len == sizeof(*mld)) {
                if (!pskb_may_pull(skb, sizeof(*mld))) {
                        err = -EINVAL;
@@ -1196,6 +1206,9 @@ static int br_ip6_multicast_query(struct net_bridge *br,
                max_delay = mld2q->mld2q_mrc ? MLDV2_MRC(ntohs(mld2q->mld2q_mrc)) : 1;
        }
 
+       br_multicast_query_received(br, port, !ipv6_addr_any(&ip6h->saddr),
+                                   max_delay);
+
        if (!group)
                goto out;
 
@@ -1204,7 +1217,6 @@ static int br_ip6_multicast_query(struct net_bridge *br,
        if (!mp)
                goto out;
 
-       setup_timer(&mp->timer, br_multicast_group_expired, (unsigned long)mp);
        mod_timer(&mp->timer, now + br->multicast_membership_interval);
        mp->timer_armed = true;
 
@@ -1642,6 +1654,8 @@ void br_multicast_init(struct net_bridge *br)
        br->multicast_querier_interval = 255 * HZ;
        br->multicast_membership_interval = 260 * HZ;
 
+       br->multicast_querier_delay_time = 0;
+
        spin_lock_init(&br->multicast_lock);
        setup_timer(&br->multicast_router_timer,
                    br_multicast_local_router_expired, 0);
@@ -1830,6 +1844,8 @@ unlock:
 
 int br_multicast_set_querier(struct net_bridge *br, unsigned long val)
 {
+       unsigned long max_delay;
+
        val = !!val;
 
        spin_lock_bh(&br->multicast_lock);
@@ -1837,8 +1853,14 @@ int br_multicast_set_querier(struct net_bridge *br, unsigned long val)
                goto unlock;
 
        br->multicast_querier = val;
-       if (val)
-               br_multicast_start_querier(br);
+       if (!val)
+               goto unlock;
+
+       max_delay = br->multicast_query_response_interval;
+       if (!timer_pending(&br->multicast_querier_timer))
+               br->multicast_querier_delay_time = jiffies + max_delay;
+
+       br_multicast_start_querier(br);
 
 unlock:
        spin_unlock_bh(&br->multicast_lock);
index 3a3f371b28415c110e4db6a21069f9153dafe904..2998dd1769a055b244c21a4fb9d9579b04099222 100644 (file)
@@ -102,6 +102,11 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
        case NETDEV_PRE_TYPE_CHANGE:
                /* Forbid underlaying device to change its type. */
                return NOTIFY_BAD;
+
+       case NETDEV_RESEND_IGMP:
+               /* Propagate to master device */
+               call_netdevice_notifiers(event, br->dev);
+               break;
        }
 
        /* Events that may cause spanning tree to refresh */
index 3be89b3ce17b5a314215609790cadec6e5453727..1514c9f4f1029c0e932c3c3f4d2e8735504995cb 100644 (file)
@@ -267,6 +267,7 @@ struct net_bridge
        unsigned long                   multicast_query_interval;
        unsigned long                   multicast_query_response_interval;
        unsigned long                   multicast_startup_query_interval;
+       unsigned long                   multicast_querier_delay_time;
 
        spinlock_t                      multicast_lock;
        struct net_bridge_mdb_htable __rcu *mdb;
@@ -333,11 +334,6 @@ extern void br_dev_delete(struct net_device *dev, struct list_head *list);
 extern netdev_tx_t br_dev_xmit(struct sk_buff *skb,
                               struct net_device *dev);
 #ifdef CONFIG_NET_POLL_CONTROLLER
-static inline struct netpoll_info *br_netpoll_info(struct net_bridge *br)
-{
-       return br->dev->npinfo;
-}
-
 static inline void br_netpoll_send_skb(const struct net_bridge_port *p,
                                       struct sk_buff *skb)
 {
@@ -350,11 +346,6 @@ static inline void br_netpoll_send_skb(const struct net_bridge_port *p,
 extern int br_netpoll_enable(struct net_bridge_port *p, gfp_t gfp);
 extern void br_netpoll_disable(struct net_bridge_port *p);
 #else
-static inline struct netpoll_info *br_netpoll_info(struct net_bridge *br)
-{
-       return NULL;
-}
-
 static inline void br_netpoll_send_skb(const struct net_bridge_port *p,
                                       struct sk_buff *skb)
 {
@@ -501,6 +492,13 @@ static inline bool br_multicast_is_router(struct net_bridge *br)
               (br->multicast_router == 1 &&
                timer_pending(&br->multicast_router_timer));
 }
+
+static inline bool br_multicast_querier_exists(struct net_bridge *br)
+{
+       return time_is_before_jiffies(br->multicast_querier_delay_time) &&
+              (br->multicast_querier ||
+               timer_pending(&br->multicast_querier_timer));
+}
 #else
 static inline int br_multicast_rcv(struct net_bridge *br,
                                   struct net_bridge_port *port,
@@ -557,6 +555,10 @@ static inline bool br_multicast_is_router(struct net_bridge *br)
 {
        return 0;
 }
+static inline bool br_multicast_querier_exists(struct net_bridge *br)
+{
+       return false;
+}
 static inline void br_mdb_init(void)
 {
 }
index eb0a46a49bd42351d23878f118384ab09a8d2ee8..3be308e143026ac3d831e4aefc13faa198400d21 100644 (file)
@@ -409,7 +409,7 @@ static void ceph_sock_write_space(struct sock *sk)
         * and net/core/stream.c:sk_stream_write_space().
         */
        if (con_flag_test(con, CON_FLAG_WRITE_PENDING)) {
-               if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk)) {
+               if (sk_stream_is_writeable(sk)) {
                        dout("%s %p queueing write work\n", __func__, con);
                        clear_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
                        queue_con(con);
index dd47889adc4aec94941d6f17105878ebe235db8f..7d40a612232ac7306d7e6c1966381f29b16950f2 100644 (file)
@@ -2129,7 +2129,8 @@ int ceph_osdc_start_request(struct ceph_osd_client *osdc,
                        dout("osdc_start_request failed map, "
                                " will retry %lld\n", req->r_tid);
                        rc = 0;
-               }
+               } else
+                       __unregister_request(osdc, req);
                goto out_unlock;
        }
        if (req->r_osd == NULL) {
index 26755dd40daa82ff5db7dcb994cabb3d6bf6252f..58eb802584b99453822c2db9f07106db3d510918 100644 (file)
@@ -174,7 +174,7 @@ static DEFINE_SPINLOCK(napi_hash_lock);
 static unsigned int napi_gen_id;
 static DEFINE_HASHTABLE(napi_hash, 8);
 
-seqcount_t devnet_rename_seq;
+static seqcount_t devnet_rename_seq;
 
 static inline void dev_base_seq_inc(struct net *net)
 {
@@ -4988,6 +4988,24 @@ int dev_change_carrier(struct net_device *dev, bool new_carrier)
 }
 EXPORT_SYMBOL(dev_change_carrier);
 
+/**
+ *     dev_get_phys_port_id - Get device physical port ID
+ *     @dev: device
+ *     @ppid: port ID
+ *
+ *     Get device physical port ID
+ */
+int dev_get_phys_port_id(struct net_device *dev,
+                        struct netdev_phys_port_id *ppid)
+{
+       const struct net_device_ops *ops = dev->netdev_ops;
+
+       if (!ops->ndo_get_phys_port_id)
+               return -EOPNOTSUPP;
+       return ops->ndo_get_phys_port_id(dev, ppid);
+}
+EXPORT_SYMBOL(dev_get_phys_port_id);
+
 /**
  *     dev_new_index   -       allocate an ifindex
  *     @net: the applicable net namespace
index 21735440c44a85b611308e6b3c97bef77452c9a1..2ef5040c99c8d509571071df339bfefb9460c06a 100644 (file)
@@ -226,6 +226,9 @@ jumped:
                else
                        err = ops->action(rule, fl, flags, arg);
 
+               if (!err && ops->suppress && ops->suppress(rule, arg))
+                       continue;
+
                if (err != -EAGAIN) {
                        if ((arg->flags & FIB_LOOKUP_NOREF) ||
                            likely(atomic_inc_not_zero(&rule->refcnt))) {
@@ -337,6 +340,8 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh)
        rule->action = frh->action;
        rule->flags = frh->flags;
        rule->table = frh_get_table(frh, tb);
+       if (tb[FRA_TABLE_PREFIXLEN_MIN])
+               rule->table_prefixlen_min = nla_get_u8(tb[FRA_TABLE_PREFIXLEN_MIN]);
 
        if (!tb[FRA_PRIORITY] && ops->default_pref)
                rule->pref = ops->default_pref(ops);
@@ -523,6 +528,7 @@ static inline size_t fib_rule_nlmsg_size(struct fib_rules_ops *ops,
                         + nla_total_size(IFNAMSIZ) /* FRA_OIFNAME */
                         + nla_total_size(4) /* FRA_PRIORITY */
                         + nla_total_size(4) /* FRA_TABLE */
+                        + nla_total_size(1) /* FRA_TABLE_PREFIXLEN_MIN */
                         + nla_total_size(4) /* FRA_FWMARK */
                         + nla_total_size(4); /* FRA_FWMASK */
 
@@ -548,6 +554,8 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule,
        frh->table = rule->table;
        if (nla_put_u32(skb, FRA_TABLE, rule->table))
                goto nla_put_failure;
+       if (nla_put_u8(skb, FRA_TABLE_PREFIXLEN_MIN, rule->table_prefixlen_min))
+               goto nla_put_failure;
        frh->res1 = 0;
        frh->res2 = 0;
        frh->action = rule->action;
index 00ee068efc1c2374bc0195d9458eca00392359c6..ade9ff1c198049164f1aeda0fa3e8aa69ef4d8a4 100644 (file)
@@ -139,7 +139,11 @@ ipv6:
                break;
        }
        case IPPROTO_IPIP:
-               goto again;
+               proto = htons(ETH_P_IP);
+               goto ip;
+       case IPPROTO_IPV6:
+               proto = htons(ETH_P_IPV6);
+               goto ipv6;
        default:
                break;
        }
index b7de821f98df2875dd5c4c7b08f32b2f3d7f98a2..9232c68941abb4b5b5ec23f5d6cd56054d8b4c67 100644 (file)
@@ -2767,6 +2767,7 @@ EXPORT_SYMBOL(neigh_app_ns);
 
 #ifdef CONFIG_SYSCTL
 static int zero;
+static int int_max = INT_MAX;
 static int unres_qlen_max = INT_MAX / SKB_TRUESIZE(ETH_FRAME_LEN);
 
 static int proc_unres_qlen(struct ctl_table *ctl, int write,
@@ -2819,19 +2820,25 @@ static struct neigh_sysctl_table {
                        .procname       = "mcast_solicit",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = proc_dointvec,
+                       .extra1         = &zero,
+                       .extra2         = &int_max,
+                       .proc_handler   = proc_dointvec_minmax,
                },
                [NEIGH_VAR_UCAST_PROBE] = {
                        .procname       = "ucast_solicit",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = proc_dointvec,
+                       .extra1         = &zero,
+                       .extra2         = &int_max,
+                       .proc_handler   = proc_dointvec_minmax,
                },
                [NEIGH_VAR_APP_PROBE] = {
                        .procname       = "app_solicit",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = proc_dointvec,
+                       .extra1         = &zero,
+                       .extra2         = &int_max,
+                       .proc_handler   = proc_dointvec_minmax,
                },
                [NEIGH_VAR_RETRANS_TIME] = {
                        .procname       = "retrans_time",
@@ -2874,7 +2881,9 @@ static struct neigh_sysctl_table {
                        .procname       = "proxy_qlen",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = proc_dointvec,
+                       .extra1         = &zero,
+                       .extra2         = &int_max,
+                       .proc_handler   = proc_dointvec_minmax,
                },
                [NEIGH_VAR_ANYCAST_DELAY] = {
                        .procname       = "anycast_delay",
@@ -2916,19 +2925,25 @@ static struct neigh_sysctl_table {
                        .procname       = "gc_thresh1",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = proc_dointvec,
+                       .extra1         = &zero,
+                       .extra2         = &int_max,
+                       .proc_handler   = proc_dointvec_minmax,
                },
                [NEIGH_VAR_GC_THRESH2] = {
                        .procname       = "gc_thresh2",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = proc_dointvec,
+                       .extra1         = &zero,
+                       .extra2         = &int_max,
+                       .proc_handler   = proc_dointvec_minmax,
                },
                [NEIGH_VAR_GC_THRESH3] = {
                        .procname       = "gc_thresh3",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = proc_dointvec,
+                       .extra1         = &zero,
+                       .extra2         = &int_max,
+                       .proc_handler   = proc_dointvec_minmax,
                },
                {},
        },
index 981fed397d1d8af3b0d607a1ac260ad0cc847ade..8826b0d1e0cc4f6d9db1ebf7d7c54811432c008d 100644 (file)
@@ -334,6 +334,27 @@ static ssize_t store_group(struct device *dev, struct device_attribute *attr,
        return netdev_store(dev, attr, buf, len, change_group);
 }
 
+static ssize_t show_phys_port_id(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct net_device *netdev = to_net_dev(dev);
+       ssize_t ret = -EINVAL;
+
+       if (!rtnl_trylock())
+               return restart_syscall();
+
+       if (dev_isalive(netdev)) {
+               struct netdev_phys_port_id ppid;
+
+               ret = dev_get_phys_port_id(netdev, &ppid);
+               if (!ret)
+                       ret = sprintf(buf, "%*phN\n", ppid.id_len, ppid.id);
+       }
+       rtnl_unlock();
+
+       return ret;
+}
+
 static struct device_attribute net_class_attributes[] = {
        __ATTR(addr_assign_type, S_IRUGO, show_addr_assign_type, NULL),
        __ATTR(addr_len, S_IRUGO, show_addr_len, NULL),
@@ -355,6 +376,7 @@ static struct device_attribute net_class_attributes[] = {
        __ATTR(tx_queue_len, S_IRUGO | S_IWUSR, show_tx_queue_len,
               store_tx_queue_len),
        __ATTR(netdev_group, S_IRUGO | S_IWUSR, show_group, store_group),
+       __ATTR(phys_port_id, S_IRUGO, show_phys_port_id, NULL),
        {}
 };
 
index 9640972ec50e5658eac7493fb0da180a0de353c9..261357a663001ccf98a92ba5f6d0f6ad141c7ce3 100644 (file)
 #include <net/net_namespace.h>
 #include <net/checksum.h>
 #include <net/ipv6.h>
+#include <net/udp.h>
+#include <net/ip6_checksum.h>
 #include <net/addrconf.h>
 #ifdef CONFIG_XFRM
 #include <net/xfrm.h>
 #define F_QUEUE_MAP_RND (1<<13)        /* queue map Random */
 #define F_QUEUE_MAP_CPU (1<<14)        /* queue map mirrors smp_processor_id() */
 #define F_NODE          (1<<15)        /* Node memory alloc*/
+#define F_UDPCSUM       (1<<16)        /* Include UDP checksum */
 
 /* Thread control flag bits */
 #define T_STOP        (1<<0)   /* Stop run */
@@ -631,6 +634,9 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
        if (pkt_dev->flags & F_UDPDST_RND)
                seq_printf(seq, "UDPDST_RND  ");
 
+       if (pkt_dev->flags & F_UDPCSUM)
+               seq_printf(seq, "UDPCSUM  ");
+
        if (pkt_dev->flags & F_MPLS_RND)
                seq_printf(seq,  "MPLS_RND  ");
 
@@ -1228,6 +1234,12 @@ static ssize_t pktgen_if_write(struct file *file,
                else if (strcmp(f, "!NODE_ALLOC") == 0)
                        pkt_dev->flags &= ~F_NODE;
 
+               else if (strcmp(f, "UDPCSUM") == 0)
+                       pkt_dev->flags |= F_UDPCSUM;
+
+               else if (strcmp(f, "!UDPCSUM") == 0)
+                       pkt_dev->flags &= ~F_UDPCSUM;
+
                else {
                        sprintf(pg_result,
                                "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s",
@@ -2733,7 +2745,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
        udph->source = htons(pkt_dev->cur_udp_src);
        udph->dest = htons(pkt_dev->cur_udp_dst);
        udph->len = htons(datalen + 8); /* DATA + udphdr */
-       udph->check = 0;        /* No checksum */
+       udph->check = 0;
 
        iph->ihl = 5;
        iph->version = 4;
@@ -2747,11 +2759,28 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
        iph->frag_off = 0;
        iplen = 20 + 8 + datalen;
        iph->tot_len = htons(iplen);
-       iph->check = 0;
-       iph->check = ip_fast_csum((void *)iph, iph->ihl);
+       ip_send_check(iph);
        skb->protocol = protocol;
        skb->dev = odev;
        skb->pkt_type = PACKET_HOST;
+
+       if (!(pkt_dev->flags & F_UDPCSUM)) {
+               skb->ip_summed = CHECKSUM_NONE;
+       } else if (odev->features & NETIF_F_V4_CSUM) {
+               skb->ip_summed = CHECKSUM_PARTIAL;
+               skb->csum = 0;
+               udp4_hwcsum(skb, udph->source, udph->dest);
+       } else {
+               __wsum csum = udp_csum(skb);
+
+               /* add protocol-dependent pseudo-header */
+               udph->check = csum_tcpudp_magic(udph->source, udph->dest,
+                                               datalen + 8, IPPROTO_UDP, csum);
+
+               if (udph->check == 0)
+                       udph->check = CSUM_MANGLED_0;
+       }
+
        pktgen_finalize_skb(pkt_dev, skb, datalen);
 
 #ifdef CONFIG_XFRM
@@ -2768,7 +2797,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
        struct sk_buff *skb = NULL;
        __u8 *eth;
        struct udphdr *udph;
-       int datalen;
+       int datalen, udplen;
        struct ipv6hdr *iph;
        __be16 protocol = htons(ETH_P_IPV6);
        __be32 *mpls;
@@ -2844,10 +2873,11 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
                net_info_ratelimited("increased datalen to %d\n", datalen);
        }
 
+       udplen = datalen + sizeof(struct udphdr);
        udph->source = htons(pkt_dev->cur_udp_src);
        udph->dest = htons(pkt_dev->cur_udp_dst);
-       udph->len = htons(datalen + sizeof(struct udphdr));
-       udph->check = 0;        /* No checksum */
+       udph->len = htons(udplen);
+       udph->check = 0;
 
        *(__be32 *) iph = htonl(0x60000000);    /* Version + flow */
 
@@ -2858,7 +2888,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
 
        iph->hop_limit = 32;
 
-       iph->payload_len = htons(sizeof(struct udphdr) + datalen);
+       iph->payload_len = htons(udplen);
        iph->nexthdr = IPPROTO_UDP;
 
        iph->daddr = pkt_dev->cur_in6_daddr;
@@ -2868,6 +2898,23 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
        skb->dev = odev;
        skb->pkt_type = PACKET_HOST;
 
+       if (!(pkt_dev->flags & F_UDPCSUM)) {
+               skb->ip_summed = CHECKSUM_NONE;
+       } else if (odev->features & NETIF_F_V6_CSUM) {
+               skb->ip_summed = CHECKSUM_PARTIAL;
+               skb->csum_start = skb_transport_header(skb) - skb->head;
+               skb->csum_offset = offsetof(struct udphdr, check);
+               udph->check = ~csum_ipv6_magic(&iph->saddr, &iph->daddr, udplen, IPPROTO_UDP, 0);
+       } else {
+               __wsum csum = udp_csum(skb);
+
+               /* add protocol-dependent pseudo-header */
+               udph->check = csum_ipv6_magic(&iph->saddr, &iph->daddr, udplen, IPPROTO_UDP, csum);
+
+               if (udph->check == 0)
+                       udph->check = CSUM_MANGLED_0;
+       }
+
        pktgen_finalize_skb(pkt_dev, skb, datalen);
 
        return skb;
index 3de740834d1ffcfa35fe31735b41d5a0dcb58c3a..0b2972c59b97824f24a96c899e906a9371ea84ab 100644 (file)
@@ -767,7 +767,8 @@ static noinline size_t if_nlmsg_size(const struct net_device *dev,
               + rtnl_vfinfo_size(dev, ext_filter_mask) /* IFLA_VFINFO_LIST */
               + rtnl_port_size(dev) /* IFLA_VF_PORTS + IFLA_PORT_SELF */
               + rtnl_link_get_size(dev) /* IFLA_LINKINFO */
-              + rtnl_link_get_af_size(dev); /* IFLA_AF_SPEC */
+              + rtnl_link_get_af_size(dev) /* IFLA_AF_SPEC */
+              + nla_total_size(MAX_PHYS_PORT_ID_LEN); /* IFLA_PHYS_PORT_ID */
 }
 
 static int rtnl_vf_ports_fill(struct sk_buff *skb, struct net_device *dev)
@@ -846,6 +847,24 @@ static int rtnl_port_fill(struct sk_buff *skb, struct net_device *dev)
        return 0;
 }
 
+static int rtnl_phys_port_id_fill(struct sk_buff *skb, struct net_device *dev)
+{
+       int err;
+       struct netdev_phys_port_id ppid;
+
+       err = dev_get_phys_port_id(dev, &ppid);
+       if (err) {
+               if (err == -EOPNOTSUPP)
+                       return 0;
+               return err;
+       }
+
+       if (nla_put(skb, IFLA_PHYS_PORT_ID, ppid.id_len, ppid.id))
+               return -EMSGSIZE;
+
+       return 0;
+}
+
 static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
                            int type, u32 pid, u32 seq, u32 change,
                            unsigned int flags, u32 ext_filter_mask)
@@ -913,6 +932,9 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
                        goto nla_put_failure;
        }
 
+       if (rtnl_phys_port_id_fill(skb, dev))
+               goto nla_put_failure;
+
        attr = nla_reserve(skb, IFLA_STATS,
                        sizeof(struct rtnl_link_stats));
        if (attr == NULL)
@@ -1113,6 +1135,7 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = {
        [IFLA_PROMISCUITY]      = { .type = NLA_U32 },
        [IFLA_NUM_TX_QUEUES]    = { .type = NLA_U32 },
        [IFLA_NUM_RX_QUEUES]    = { .type = NLA_U32 },
+       [IFLA_PHYS_PORT_ID]     = { .type = NLA_BINARY, .len = MAX_PHYS_PORT_ID_LEN },
 };
 EXPORT_SYMBOL(ifla_policy);
 
index 20e02d2605ecb2f10f5f74ab6f00cbd8fb852615..2c3d0f53d198c5915669a967f273c5f5b13b12af 100644 (file)
@@ -309,7 +309,8 @@ EXPORT_SYMBOL(__alloc_skb);
  * @frag_size: size of fragment, or 0 if head was kmalloced
  *
  * Allocate a new &sk_buff. Caller provides space holding head and
- * skb_shared_info. @data must have been allocated by kmalloc()
+ * skb_shared_info. @data must have been allocated by kmalloc() only if
+ * @frag_size is 0, otherwise data should come from the page allocator.
  * The return is the new skb buffer.
  * On a failure the return is %NULL, and @data is not freed.
  * Notes :
@@ -739,7 +740,7 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
 
        skb_copy_secmark(new, old);
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        new->napi_id    = old->napi_id;
 #endif
 }
index 548d716c5f62ac8c9d90d0959d19022714f9585d..83667de45ec95dd3b323e9462cb2264ff6dd2b23 100644 (file)
@@ -93,6 +93,7 @@
 
 #include <linux/capability.h>
 #include <linux/errno.h>
+#include <linux/errqueue.h>
 #include <linux/types.h>
 #include <linux/socket.h>
 #include <linux/in.h>
@@ -900,7 +901,7 @@ set_rcvbuf:
                sock_valbool_flag(sk, SOCK_SELECT_ERR_QUEUE, valbool);
                break;
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        case SO_BUSY_POLL:
                /* allow unprivileged users to decrease the value */
                if ((val > sk->sk_ll_usec) && !capable(CAP_NET_ADMIN))
@@ -1170,7 +1171,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
                v.val = sock_flag(sk, SOCK_SELECT_ERR_QUEUE);
                break;
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        case SO_BUSY_POLL:
                v.val = sk->sk_ll_usec;
                break;
@@ -1575,6 +1576,25 @@ void sock_wfree(struct sk_buff *skb)
 }
 EXPORT_SYMBOL(sock_wfree);
 
+void skb_orphan_partial(struct sk_buff *skb)
+{
+       /* TCP stack sets skb->ooo_okay based on sk_wmem_alloc,
+        * so we do not completely orphan skb, but transfert all
+        * accounted bytes but one, to avoid unexpected reorders.
+        */
+       if (skb->destructor == sock_wfree
+#ifdef CONFIG_INET
+           || skb->destructor == tcp_wfree
+#endif
+               ) {
+               atomic_sub(skb->truesize - 1, &skb->sk->sk_wmem_alloc);
+               skb->truesize = 1;
+       } else {
+               skb_orphan(skb);
+       }
+}
+EXPORT_SYMBOL(skb_orphan_partial);
+
 /*
  * Read buffer destructor automatically called from kfree_skb.
  */
@@ -2292,7 +2312,7 @@ void sock_init_data(struct socket *sock, struct sock *sk)
 
        sk->sk_stamp = ktime_set(-1L, 0);
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        sk->sk_napi_id          =       0;
        sk->sk_ll_usec          =       sysctl_net_busy_read;
 #endif
@@ -2425,6 +2445,52 @@ void sock_enable_timestamp(struct sock *sk, int flag)
        }
 }
 
+int sock_recv_errqueue(struct sock *sk, struct msghdr *msg, int len,
+                      int level, int type)
+{
+       struct sock_exterr_skb *serr;
+       struct sk_buff *skb, *skb2;
+       int copied, err;
+
+       err = -EAGAIN;
+       skb = skb_dequeue(&sk->sk_error_queue);
+       if (skb == NULL)
+               goto out;
+
+       copied = skb->len;
+       if (copied > len) {
+               msg->msg_flags |= MSG_TRUNC;
+               copied = len;
+       }
+       err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+       if (err)
+               goto out_free_skb;
+
+       sock_recv_timestamp(msg, sk, skb);
+
+       serr = SKB_EXT_ERR(skb);
+       put_cmsg(msg, level, type, sizeof(serr->ee), &serr->ee);
+
+       msg->msg_flags |= MSG_ERRQUEUE;
+       err = copied;
+
+       /* Reset and regenerate socket error */
+       spin_lock_bh(&sk->sk_error_queue.lock);
+       sk->sk_err = 0;
+       if ((skb2 = skb_peek(&sk->sk_error_queue)) != NULL) {
+               sk->sk_err = SKB_EXT_ERR(skb2)->ee.ee_errno;
+               spin_unlock_bh(&sk->sk_error_queue.lock);
+               sk->sk_error_report(sk);
+       } else
+               spin_unlock_bh(&sk->sk_error_queue.lock);
+
+out_free_skb:
+       kfree_skb(skb);
+out:
+       return err;
+}
+EXPORT_SYMBOL(sock_recv_errqueue);
+
 /*
  *     Get a socket option on an socket.
  *
index f5df85dcd20bc7f790aec8f58967f55e02586444..512f0a24269b59cc45baa14c13e586b34fce9b60 100644 (file)
@@ -30,7 +30,7 @@ void sk_stream_write_space(struct sock *sk)
        struct socket *sock = sk->sk_socket;
        struct socket_wq *wq;
 
-       if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk) && sock) {
+       if (sk_stream_is_writeable(sk) && sock) {
                clear_bit(SOCK_NOSPACE, &sock->flags);
 
                rcu_read_lock();
index 6609686166379765233cdbfab0e3d580a3d23051..b59b6804fd987c079720cd43c9b2f91dd21c9a8d 100644 (file)
@@ -298,7 +298,7 @@ static struct ctl_table net_core_table[] = {
                .proc_handler   = flow_limit_table_len_sysctl
        },
 #endif /* CONFIG_NET_FLOW_LIMIT */
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        {
                .procname       = "busy_poll",
                .data           = &sysctl_net_busy_poll,
index 6c7c78b839403f7582c8fd9daef4cfe0e1e571a0..ba64750f038726a990caa71d90e45f77bad93230 100644 (file)
@@ -336,7 +336,7 @@ unsigned int dccp_poll(struct file *file, struct socket *sock,
                        mask |= POLLIN | POLLRDNORM;
 
                if (!(sk->sk_shutdown & SEND_SHUTDOWN)) {
-                       if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk)) {
+                       if (sk_stream_is_writeable(sk)) {
                                mask |= POLLOUT | POLLWRNORM;
                        } else {  /* send SIGIO later */
                                set_bit(SOCK_ASYNC_NOSPACE,
@@ -347,7 +347,7 @@ unsigned int dccp_poll(struct file *file, struct socket *sock,
                                 * wspace test but before the flags are set,
                                 * IO signal will be lost.
                                 */
-                               if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk))
+                               if (sk_stream_is_writeable(sk))
                                        mask |= POLLOUT | POLLWRNORM;
                        }
                }
index 8d48c392adccec6dc1f2ca8e3c8fd5a6750283e5..1b7f7ae8514a5a08ee10e94cfb234686bc3182a9 100644 (file)
@@ -1124,10 +1124,7 @@ static int inet_gifconf(struct net_device *dev, char __user *buf, int len)
                if (len < (int) sizeof(ifr))
                        break;
                memset(&ifr, 0, sizeof(struct ifreq));
-               if (ifa->ifa_label)
-                       strcpy(ifr.ifr_name, ifa->ifa_label);
-               else
-                       strcpy(ifr.ifr_name, dev->name);
+               strcpy(ifr.ifr_name, ifa->ifa_label);
 
                (*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET;
                (*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr =
index 26aa65d1fce49dfeaa45cbc02046218b5bc70453..9f2906679d1f0c874245381d4b338ce8b1d3965b 100644 (file)
@@ -101,6 +101,19 @@ errout:
        return err;
 }
 
+static bool fib4_rule_suppress(struct fib_rule *rule, struct fib_lookup_arg *arg)
+{
+       /* do not accept result if the route does
+        * not meet the required prefix length
+        */
+       struct fib_result *result = (struct fib_result *) arg->result;
+       if (result->prefixlen < rule->table_prefixlen_min) {
+               if (!(arg->flags & FIB_LOOKUP_NOREF))
+                       fib_info_put(result->fi);
+               return true;
+       }
+       return false;
+}
 
 static int fib4_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)
 {
@@ -267,6 +280,7 @@ static const struct fib_rules_ops __net_initconst fib4_rules_ops_template = {
        .rule_size      = sizeof(struct fib4_rule),
        .addr_size      = sizeof(u32),
        .action         = fib4_rule_action,
+       .suppress       = fib4_rule_suppress,
        .match          = fib4_rule_match,
        .configure      = fib4_rule_configure,
        .delete         = fib4_rule_delete,
index 49616fed9340265b203c7b1fbf10390f92c38020..108a1e9c9eac388515530bb790d0e56e4dba0bfd 100644 (file)
@@ -2133,7 +2133,7 @@ static void trie_show_stats(struct seq_file *seq, struct trie_stat *stat)
                max--;
 
        pointers = 0;
-       for (i = 1; i <= max; i++)
+       for (i = 1; i < max; i++)
                if (stat->nodesizes[i] != 0) {
                        seq_printf(seq, "  %u: %u",  i, stat->nodesizes[i]);
                        pointers += (1<<i) * stat->nodesizes[i];
index cd71190d29625c11fe25aa603026cc98e0e2c34b..ef7618630f3614d00fb05b8a94f14891caa57932 100644 (file)
@@ -88,6 +88,7 @@
 #include <linux/if_arp.h>
 #include <linux/rtnetlink.h>
 #include <linux/times.h>
+#include <linux/pkt_sched.h>
 
 #include <net/net_namespace.h>
 #include <net/arp.h>
@@ -315,6 +316,7 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size)
                if (size < 256)
                        return NULL;
        }
+       skb->priority = TC_PRIO_CONTROL;
        igmp_skb_size(skb) = size;
 
        rt = ip_route_output_ports(net, &fl4, NULL, IGMPV3_ALL_MCR, 0,
@@ -670,6 +672,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc,
                ip_rt_put(rt);
                return -1;
        }
+       skb->priority = TC_PRIO_CONTROL;
 
        skb_dst_set(skb, &rt->dst);
 
@@ -1323,16 +1326,17 @@ out:
 EXPORT_SYMBOL(ip_mc_inc_group);
 
 /*
- *     Resend IGMP JOIN report; used for bonding.
- *     Called with rcu_read_lock()
+ *     Resend IGMP JOIN report; used by netdev notifier.
  */
-void ip_mc_rejoin_groups(struct in_device *in_dev)
+static void ip_mc_rejoin_groups(struct in_device *in_dev)
 {
 #ifdef CONFIG_IP_MULTICAST
        struct ip_mc_list *im;
        int type;
 
-       for_each_pmc_rcu(in_dev, im) {
+       ASSERT_RTNL();
+
+       for_each_pmc_rtnl(in_dev, im) {
                if (im->multiaddr == IGMP_ALL_HOSTS)
                        continue;
 
@@ -1349,7 +1353,6 @@ void ip_mc_rejoin_groups(struct in_device *in_dev)
        }
 #endif
 }
-EXPORT_SYMBOL(ip_mc_rejoin_groups);
 
 /*
  *     A socket has left a multicast group on device dev
@@ -2735,8 +2738,42 @@ static struct pernet_operations igmp_net_ops = {
        .exit = igmp_net_exit,
 };
 
+static int igmp_netdev_event(struct notifier_block *this,
+                            unsigned long event, void *ptr)
+{
+       struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+       struct in_device *in_dev;
+
+       switch (event) {
+       case NETDEV_RESEND_IGMP:
+               in_dev = __in_dev_get_rtnl(dev);
+               if (in_dev)
+                       ip_mc_rejoin_groups(in_dev);
+               break;
+       default:
+               break;
+       }
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block igmp_notifier = {
+       .notifier_call = igmp_netdev_event,
+};
+
 int __init igmp_mc_proc_init(void)
 {
-       return register_pernet_subsys(&igmp_net_ops);
+       int err;
+
+       err = register_pernet_subsys(&igmp_net_ops);
+       if (err)
+               return err;
+       err = register_netdevice_notifier(&igmp_notifier);
+       if (err)
+               goto reg_notif_fail;
+       return 0;
+
+reg_notif_fail:
+       unregister_pernet_subsys(&igmp_net_ops);
+       return err;
 }
 #endif
index 17cc0ffa8c0d0ea2a3732b76b63be1f85c896778..79b263da416854b101043ad9a3047fa6d07e285e 100644 (file)
 #include <net/net_namespace.h>
 #include <net/netns/generic.h>
 
-#define HASH_SIZE  16
-#define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&(HASH_SIZE-1))
-
 static struct rtnl_link_ops vti_link_ops __read_mostly;
 
 static int vti_net_id __read_mostly;
-struct vti_net {
-       struct ip_tunnel __rcu *tunnels_r_l[HASH_SIZE];
-       struct ip_tunnel __rcu *tunnels_r[HASH_SIZE];
-       struct ip_tunnel __rcu *tunnels_l[HASH_SIZE];
-       struct ip_tunnel __rcu *tunnels_wc[1];
-       struct ip_tunnel __rcu **tunnels[4];
-
-       struct net_device *fb_tunnel_dev;
-};
-
-static int vti_fb_tunnel_init(struct net_device *dev);
 static int vti_tunnel_init(struct net_device *dev);
-static void vti_tunnel_setup(struct net_device *dev);
-static void vti_dev_free(struct net_device *dev);
-static int vti_tunnel_bind_dev(struct net_device *dev);
-
-#define VTI_XMIT(stats1, stats2) do {                          \
-       int err;                                                \
-       int pkt_len = skb->len;                                 \
-       err = dst_output(skb);                                  \
-       if (net_xmit_eval(err) == 0) {                          \
-               u64_stats_update_begin(&(stats1)->syncp);       \
-               (stats1)->tx_bytes += pkt_len;                  \
-               (stats1)->tx_packets++;                         \
-               u64_stats_update_end(&(stats1)->syncp);         \
-       } else {                                                \
-               (stats2)->tx_errors++;                          \
-               (stats2)->tx_aborted_errors++;                  \
-       }                                                       \
-} while (0)
-
-
-static struct ip_tunnel *vti_tunnel_lookup(struct net *net,
-                                          __be32 remote, __be32 local)
-{
-       unsigned h0 = HASH(remote);
-       unsigned h1 = HASH(local);
-       struct ip_tunnel *t;
-       struct vti_net *ipn = net_generic(net, vti_net_id);
-
-       for_each_ip_tunnel_rcu(t, ipn->tunnels_r_l[h0 ^ h1])
-               if (local == t->parms.iph.saddr &&
-                   remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP))
-                       return t;
-       for_each_ip_tunnel_rcu(t, ipn->tunnels_r[h0])
-               if (remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP))
-                       return t;
-
-       for_each_ip_tunnel_rcu(t, ipn->tunnels_l[h1])
-               if (local == t->parms.iph.saddr && (t->dev->flags&IFF_UP))
-                       return t;
-
-       for_each_ip_tunnel_rcu(t, ipn->tunnels_wc[0])
-               if (t && (t->dev->flags&IFF_UP))
-                       return t;
-       return NULL;
-}
-
-static struct ip_tunnel __rcu **__vti_bucket(struct vti_net *ipn,
-                                            struct ip_tunnel_parm *parms)
-{
-       __be32 remote = parms->iph.daddr;
-       __be32 local = parms->iph.saddr;
-       unsigned h = 0;
-       int prio = 0;
-
-       if (remote) {
-               prio |= 2;
-               h ^= HASH(remote);
-       }
-       if (local) {
-               prio |= 1;
-               h ^= HASH(local);
-       }
-       return &ipn->tunnels[prio][h];
-}
-
-static inline struct ip_tunnel __rcu **vti_bucket(struct vti_net *ipn,
-                                                 struct ip_tunnel *t)
-{
-       return __vti_bucket(ipn, &t->parms);
-}
-
-static void vti_tunnel_unlink(struct vti_net *ipn, struct ip_tunnel *t)
-{
-       struct ip_tunnel __rcu **tp;
-       struct ip_tunnel *iter;
-
-       for (tp = vti_bucket(ipn, t);
-            (iter = rtnl_dereference(*tp)) != NULL;
-            tp = &iter->next) {
-               if (t == iter) {
-                       rcu_assign_pointer(*tp, t->next);
-                       break;
-               }
-       }
-}
-
-static void vti_tunnel_link(struct vti_net *ipn, struct ip_tunnel *t)
-{
-       struct ip_tunnel __rcu **tp = vti_bucket(ipn, t);
-
-       rcu_assign_pointer(t->next, rtnl_dereference(*tp));
-       rcu_assign_pointer(*tp, t);
-}
-
-static struct ip_tunnel *vti_tunnel_locate(struct net *net,
-                                          struct ip_tunnel_parm *parms,
-                                          int create)
-{
-       __be32 remote = parms->iph.daddr;
-       __be32 local = parms->iph.saddr;
-       struct ip_tunnel *t, *nt;
-       struct ip_tunnel __rcu **tp;
-       struct net_device *dev;
-       char name[IFNAMSIZ];
-       struct vti_net *ipn = net_generic(net, vti_net_id);
-
-       for (tp = __vti_bucket(ipn, parms);
-            (t = rtnl_dereference(*tp)) != NULL;
-            tp = &t->next) {
-               if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr)
-                       return t;
-       }
-       if (!create)
-               return NULL;
-
-       if (parms->name[0])
-               strlcpy(name, parms->name, IFNAMSIZ);
-       else
-               strcpy(name, "vti%d");
-
-       dev = alloc_netdev(sizeof(*t), name, vti_tunnel_setup);
-       if (dev == NULL)
-               return NULL;
-
-       dev_net_set(dev, net);
-
-       nt = netdev_priv(dev);
-       nt->parms = *parms;
-       dev->rtnl_link_ops = &vti_link_ops;
-
-       vti_tunnel_bind_dev(dev);
-
-       if (register_netdevice(dev) < 0)
-               goto failed_free;
-
-       dev_hold(dev);
-       vti_tunnel_link(ipn, nt);
-       return nt;
-
-failed_free:
-       free_netdev(dev);
-       return NULL;
-}
-
-static void vti_tunnel_uninit(struct net_device *dev)
-{
-       struct net *net = dev_net(dev);
-       struct vti_net *ipn = net_generic(net, vti_net_id);
-
-       vti_tunnel_unlink(ipn, netdev_priv(dev));
-       dev_put(dev);
-}
 
 static int vti_err(struct sk_buff *skb, u32 info)
 {
@@ -222,6 +56,8 @@ static int vti_err(struct sk_buff *skb, u32 info)
         * 8 bytes of packet payload. It means, that precise relaying of
         * ICMP in the real Internet is absolutely infeasible.
         */
+       struct net *net = dev_net(skb->dev);
+       struct ip_tunnel_net *itn = net_generic(net, vti_net_id);
        struct iphdr *iph = (struct iphdr *)skb->data;
        const int type = icmp_hdr(skb)->type;
        const int code = icmp_hdr(skb)->code;
@@ -252,7 +88,8 @@ static int vti_err(struct sk_buff *skb, u32 info)
 
        err = -ENOENT;
 
-       t = vti_tunnel_lookup(dev_net(skb->dev), iph->daddr, iph->saddr);
+       t = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
+                            iph->daddr, iph->saddr, 0);
        if (t == NULL)
                goto out;
 
@@ -281,8 +118,11 @@ static int vti_rcv(struct sk_buff *skb)
 {
        struct ip_tunnel *tunnel;
        const struct iphdr *iph = ip_hdr(skb);
+       struct net *net = dev_net(skb->dev);
+       struct ip_tunnel_net *itn = net_generic(net, vti_net_id);
 
-       tunnel = vti_tunnel_lookup(dev_net(skb->dev), iph->saddr, iph->daddr);
+       tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
+                                 iph->saddr, iph->daddr, 0);
        if (tunnel != NULL) {
                struct pcpu_tstats *tstats;
 
@@ -311,7 +151,6 @@ static int vti_rcv(struct sk_buff *skb)
 static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct ip_tunnel *tunnel = netdev_priv(dev);
-       struct pcpu_tstats *tstats;
        struct iphdr  *tiph = &tunnel->parms.iph;
        u8     tos;
        struct rtable *rt;              /* Route to the other host */
@@ -319,6 +158,7 @@ static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
        struct iphdr  *old_iph = ip_hdr(skb);
        __be32 dst = tiph->daddr;
        struct flowi4 fl4;
+       int err;
 
        if (skb->protocol != htons(ETH_P_IP))
                goto tx_error;
@@ -367,8 +207,10 @@ static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
        nf_reset(skb);
        skb->dev = skb_dst(skb)->dev;
 
-       tstats = this_cpu_ptr(dev->tstats);
-       VTI_XMIT(tstats, &dev->stats);
+       err = dst_output(skb);
+       if (net_xmit_eval(err) == 0)
+               err = skb->len;
+       iptunnel_xmit_stats(err, &dev->stats, dev->tstats);
        return NETDEV_TX_OK;
 
 tx_error_icmp:
@@ -379,198 +221,57 @@ tx_error:
        return NETDEV_TX_OK;
 }
 
-static int vti_tunnel_bind_dev(struct net_device *dev)
-{
-       struct net_device *tdev = NULL;
-       struct ip_tunnel *tunnel;
-       struct iphdr *iph;
-
-       tunnel = netdev_priv(dev);
-       iph = &tunnel->parms.iph;
-
-       if (iph->daddr) {
-               struct rtable *rt;
-               struct flowi4 fl4;
-               memset(&fl4, 0, sizeof(fl4));
-               flowi4_init_output(&fl4, tunnel->parms.link,
-                                  be32_to_cpu(tunnel->parms.i_key),
-                                  RT_TOS(iph->tos), RT_SCOPE_UNIVERSE,
-                                  IPPROTO_IPIP, 0,
-                                  iph->daddr, iph->saddr, 0, 0);
-               rt = ip_route_output_key(dev_net(dev), &fl4);
-               if (!IS_ERR(rt)) {
-                       tdev = rt->dst.dev;
-                       ip_rt_put(rt);
-               }
-               dev->flags |= IFF_POINTOPOINT;
-       }
-
-       if (!tdev && tunnel->parms.link)
-               tdev = __dev_get_by_index(dev_net(dev), tunnel->parms.link);
-
-       if (tdev) {
-               dev->hard_header_len = tdev->hard_header_len +
-                                      sizeof(struct iphdr);
-               dev->mtu = tdev->mtu;
-       }
-       dev->iflink = tunnel->parms.link;
-       return dev->mtu;
-}
-
 static int
 vti_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
        int err = 0;
        struct ip_tunnel_parm p;
-       struct ip_tunnel *t;
-       struct net *net = dev_net(dev);
-       struct vti_net *ipn = net_generic(net, vti_net_id);
-
-       switch (cmd) {
-       case SIOCGETTUNNEL:
-               t = NULL;
-               if (dev == ipn->fb_tunnel_dev) {
-                       if (copy_from_user(&p, ifr->ifr_ifru.ifru_data,
-                                          sizeof(p))) {
-                               err = -EFAULT;
-                               break;
-                       }
-                       t = vti_tunnel_locate(net, &p, 0);
-               }
-               if (t == NULL)
-                       t = netdev_priv(dev);
-               memcpy(&p, &t->parms, sizeof(p));
-               p.i_flags |= GRE_KEY | VTI_ISVTI;
-               p.o_flags |= GRE_KEY;
-               if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
-                       err = -EFAULT;
-               break;
-
-       case SIOCADDTUNNEL:
-       case SIOCCHGTUNNEL:
-               err = -EPERM;
-               if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
-                       goto done;
 
-               err = -EFAULT;
-               if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
-                       goto done;
+       if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
+               return -EFAULT;
 
-               err = -EINVAL;
+       if (cmd == SIOCADDTUNNEL || cmd == SIOCCHGTUNNEL) {
                if (p.iph.version != 4 || p.iph.protocol != IPPROTO_IPIP ||
                    p.iph.ihl != 5)
-                       goto done;
-
-               t = vti_tunnel_locate(net, &p, cmd == SIOCADDTUNNEL);
-
-               if (dev != ipn->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) {
-                       if (t != NULL) {
-                               if (t->dev != dev) {
-                                       err = -EEXIST;
-                                       break;
-                               }
-                       } else {
-                               if (((dev->flags&IFF_POINTOPOINT) &&
-                                   !p.iph.daddr) ||
-                                   (!(dev->flags&IFF_POINTOPOINT) &&
-                                   p.iph.daddr)) {
-                                       err = -EINVAL;
-                                       break;
-                               }
-                               t = netdev_priv(dev);
-                               vti_tunnel_unlink(ipn, t);
-                               synchronize_net();
-                               t->parms.iph.saddr = p.iph.saddr;
-                               t->parms.iph.daddr = p.iph.daddr;
-                               t->parms.i_key = p.i_key;
-                               t->parms.o_key = p.o_key;
-                               t->parms.iph.protocol = IPPROTO_IPIP;
-                               memcpy(dev->dev_addr, &p.iph.saddr, 4);
-                               memcpy(dev->broadcast, &p.iph.daddr, 4);
-                               vti_tunnel_link(ipn, t);
-                               netdev_state_change(dev);
-                       }
-               }
-
-               if (t) {
-                       err = 0;
-                       if (cmd == SIOCCHGTUNNEL) {
-                               t->parms.i_key = p.i_key;
-                               t->parms.o_key = p.o_key;
-                               if (t->parms.link != p.link) {
-                                       t->parms.link = p.link;
-                                       vti_tunnel_bind_dev(dev);
-                                       netdev_state_change(dev);
-                               }
-                       }
-                       p.i_flags |= GRE_KEY | VTI_ISVTI;
-                       p.o_flags |= GRE_KEY;
-                       if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms,
-                                        sizeof(p)))
-                               err = -EFAULT;
-               } else
-                       err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT);
-               break;
+                       return -EINVAL;
+       }
 
-       case SIOCDELTUNNEL:
-               err = -EPERM;
-               if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
-                       goto done;
-
-               if (dev == ipn->fb_tunnel_dev) {
-                       err = -EFAULT;
-                       if (copy_from_user(&p, ifr->ifr_ifru.ifru_data,
-                                          sizeof(p)))
-                               goto done;
-                       err = -ENOENT;
-
-                       t = vti_tunnel_locate(net, &p, 0);
-                       if (t == NULL)
-                               goto done;
-                       err = -EPERM;
-                       if (t->dev == ipn->fb_tunnel_dev)
-                               goto done;
-                       dev = t->dev;
-               }
-               unregister_netdevice(dev);
-               err = 0;
-               break;
+       err = ip_tunnel_ioctl(dev, &p, cmd);
+       if (err)
+               return err;
 
-       default:
-               err = -EINVAL;
+       if (cmd != SIOCDELTUNNEL) {
+               p.i_flags |= GRE_KEY | VTI_ISVTI;
+               p.o_flags |= GRE_KEY;
        }
 
-done:
-       return err;
-}
-
-static int vti_tunnel_change_mtu(struct net_device *dev, int new_mtu)
-{
-       if (new_mtu < 68 || new_mtu > 0xFFF8)
-               return -EINVAL;
-       dev->mtu = new_mtu;
+       if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
+               return -EFAULT;
        return 0;
 }
 
 static const struct net_device_ops vti_netdev_ops = {
        .ndo_init       = vti_tunnel_init,
-       .ndo_uninit     = vti_tunnel_uninit,
+       .ndo_uninit     = ip_tunnel_uninit,
        .ndo_start_xmit = vti_tunnel_xmit,
        .ndo_do_ioctl   = vti_tunnel_ioctl,
-       .ndo_change_mtu = vti_tunnel_change_mtu,
+       .ndo_change_mtu = ip_tunnel_change_mtu,
        .ndo_get_stats64 = ip_tunnel_get_stats64,
 };
 
-static void vti_dev_free(struct net_device *dev)
+static void vti_tunnel_setup(struct net_device *dev)
 {
-       free_percpu(dev->tstats);
-       free_netdev(dev);
+       dev->netdev_ops         = &vti_netdev_ops;
+       ip_tunnel_setup(dev, vti_net_id);
 }
 
-static void vti_tunnel_setup(struct net_device *dev)
+static int vti_tunnel_init(struct net_device *dev)
 {
-       dev->netdev_ops         = &vti_netdev_ops;
-       dev->destructor         = vti_dev_free;
+       struct ip_tunnel *tunnel = netdev_priv(dev);
+       struct iphdr *iph = &tunnel->parms.iph;
+
+       memcpy(dev->dev_addr, &iph->saddr, 4);
+       memcpy(dev->broadcast, &iph->daddr, 4);
 
        dev->type               = ARPHRD_TUNNEL;
        dev->hard_header_len    = LL_MAX_HEADER + sizeof(struct iphdr);
@@ -581,38 +282,18 @@ static void vti_tunnel_setup(struct net_device *dev)
        dev->features           |= NETIF_F_NETNS_LOCAL;
        dev->features           |= NETIF_F_LLTX;
        dev->priv_flags         &= ~IFF_XMIT_DST_RELEASE;
-}
 
-static int vti_tunnel_init(struct net_device *dev)
-{
-       struct ip_tunnel *tunnel = netdev_priv(dev);
-
-       tunnel->dev = dev;
-       strcpy(tunnel->parms.name, dev->name);
-
-       memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4);
-       memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
-
-       dev->tstats = alloc_percpu(struct pcpu_tstats);
-       if (!dev->tstats)
-               return -ENOMEM;
-
-       return 0;
+       return ip_tunnel_init(dev);
 }
 
-static int __net_init vti_fb_tunnel_init(struct net_device *dev)
+static void __net_init vti_fb_tunnel_init(struct net_device *dev)
 {
        struct ip_tunnel *tunnel = netdev_priv(dev);
        struct iphdr *iph = &tunnel->parms.iph;
-       struct vti_net *ipn = net_generic(dev_net(dev), vti_net_id);
 
        iph->version            = 4;
        iph->protocol           = IPPROTO_IPIP;
        iph->ihl                = 5;
-
-       dev_hold(dev);
-       rcu_assign_pointer(ipn->tunnels_wc[0], tunnel);
-       return 0;
 }
 
 static struct xfrm_tunnel vti_handler __read_mostly = {
@@ -621,76 +302,30 @@ static struct xfrm_tunnel vti_handler __read_mostly = {
        .priority       =       1,
 };
 
-static void vti_destroy_tunnels(struct vti_net *ipn, struct list_head *head)
-{
-       int prio;
-
-       for (prio = 1; prio < 4; prio++) {
-               int h;
-               for (h = 0; h < HASH_SIZE; h++) {
-                       struct ip_tunnel *t;
-
-                       t = rtnl_dereference(ipn->tunnels[prio][h]);
-                       while (t != NULL) {
-                               unregister_netdevice_queue(t->dev, head);
-                               t = rtnl_dereference(t->next);
-                       }
-               }
-       }
-}
-
 static int __net_init vti_init_net(struct net *net)
 {
        int err;
-       struct vti_net *ipn = net_generic(net, vti_net_id);
-
-       ipn->tunnels[0] = ipn->tunnels_wc;
-       ipn->tunnels[1] = ipn->tunnels_l;
-       ipn->tunnels[2] = ipn->tunnels_r;
-       ipn->tunnels[3] = ipn->tunnels_r_l;
-
-       ipn->fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel),
-                                         "ip_vti0",
-                                         vti_tunnel_setup);
-       if (!ipn->fb_tunnel_dev) {
-               err = -ENOMEM;
-               goto err_alloc_dev;
-       }
-       dev_net_set(ipn->fb_tunnel_dev, net);
-
-       err = vti_fb_tunnel_init(ipn->fb_tunnel_dev);
-       if (err)
-               goto err_reg_dev;
-       ipn->fb_tunnel_dev->rtnl_link_ops = &vti_link_ops;
+       struct ip_tunnel_net *itn;
 
-       err = register_netdev(ipn->fb_tunnel_dev);
+       err = ip_tunnel_init_net(net, vti_net_id, &vti_link_ops, "ip_vti0");
        if (err)
-               goto err_reg_dev;
+               return err;
+       itn = net_generic(net, vti_net_id);
+       vti_fb_tunnel_init(itn->fb_tunnel_dev);
        return 0;
-
-err_reg_dev:
-       vti_dev_free(ipn->fb_tunnel_dev);
-err_alloc_dev:
-       /* nothing */
-       return err;
 }
 
 static void __net_exit vti_exit_net(struct net *net)
 {
-       struct vti_net *ipn = net_generic(net, vti_net_id);
-       LIST_HEAD(list);
-
-       rtnl_lock();
-       vti_destroy_tunnels(ipn, &list);
-       unregister_netdevice_many(&list);
-       rtnl_unlock();
+       struct ip_tunnel_net *itn = net_generic(net, vti_net_id);
+       ip_tunnel_delete_net(itn);
 }
 
 static struct pernet_operations vti_net_ops = {
        .init = vti_init_net,
        .exit = vti_exit_net,
        .id   = &vti_net_id,
-       .size = sizeof(struct vti_net),
+       .size = sizeof(struct ip_tunnel_net),
 };
 
 static int vti_tunnel_validate(struct nlattr *tb[], struct nlattr *data[])
@@ -728,78 +363,19 @@ static void vti_netlink_parms(struct nlattr *data[],
 static int vti_newlink(struct net *src_net, struct net_device *dev,
                       struct nlattr *tb[], struct nlattr *data[])
 {
-       struct ip_tunnel *nt;
-       struct net *net = dev_net(dev);
-       struct vti_net *ipn = net_generic(net, vti_net_id);
-       int mtu;
-       int err;
-
-       nt = netdev_priv(dev);
-       vti_netlink_parms(data, &nt->parms);
-
-       if (vti_tunnel_locate(net, &nt->parms, 0))
-               return -EEXIST;
+       struct ip_tunnel_parm parms;
 
-       mtu = vti_tunnel_bind_dev(dev);
-       if (!tb[IFLA_MTU])
-               dev->mtu = mtu;
-
-       err = register_netdevice(dev);
-       if (err)
-               goto out;
-
-       dev_hold(dev);
-       vti_tunnel_link(ipn, nt);
-
-out:
-       return err;
+       vti_netlink_parms(data, &parms);
+       return ip_tunnel_newlink(dev, tb, &parms);
 }
 
 static int vti_changelink(struct net_device *dev, struct nlattr *tb[],
                          struct nlattr *data[])
 {
-       struct ip_tunnel *t, *nt;
-       struct net *net = dev_net(dev);
-       struct vti_net *ipn = net_generic(net, vti_net_id);
        struct ip_tunnel_parm p;
-       int mtu;
-
-       if (dev == ipn->fb_tunnel_dev)
-               return -EINVAL;
 
-       nt = netdev_priv(dev);
        vti_netlink_parms(data, &p);
-
-       t = vti_tunnel_locate(net, &p, 0);
-
-       if (t) {
-               if (t->dev != dev)
-                       return -EEXIST;
-       } else {
-               t = nt;
-
-               vti_tunnel_unlink(ipn, t);
-               t->parms.iph.saddr = p.iph.saddr;
-               t->parms.iph.daddr = p.iph.daddr;
-               t->parms.i_key = p.i_key;
-               t->parms.o_key = p.o_key;
-               if (dev->type != ARPHRD_ETHER) {
-                       memcpy(dev->dev_addr, &p.iph.saddr, 4);
-                       memcpy(dev->broadcast, &p.iph.daddr, 4);
-               }
-               vti_tunnel_link(ipn, t);
-               netdev_state_change(dev);
-       }
-
-       if (t->parms.link != p.link) {
-               t->parms.link = p.link;
-               mtu = vti_tunnel_bind_dev(dev);
-               if (!tb[IFLA_MTU])
-                       dev->mtu = mtu;
-               netdev_state_change(dev);
-       }
-
-       return 0;
+       return ip_tunnel_changelink(dev, tb, &p);
 }
 
 static size_t vti_get_size(const struct net_device *dev)
@@ -865,7 +441,7 @@ static int __init vti_init(void)
        err = xfrm4_mode_tunnel_input_register(&vti_handler);
        if (err < 0) {
                unregister_pernet_device(&vti_net_ops);
-               pr_info(KERN_INFO "vti init: can't register tunnel\n");
+               pr_info("vti init: can't register tunnel\n");
        }
 
        err = rtnl_link_register(&vti_link_ops);
index 132a09664704ed73ed850e8961f11fa3e3641473..bacc0bcf48ce5b1cec365e5886d820492d41566d 100644 (file)
@@ -127,9 +127,9 @@ static struct kmem_cache *mrt_cachep __read_mostly;
 static struct mr_table *ipmr_new_table(struct net *net, u32 id);
 static void ipmr_free_table(struct mr_table *mrt);
 
-static int ip_mr_forward(struct net *net, struct mr_table *mrt,
-                        struct sk_buff *skb, struct mfc_cache *cache,
-                        int local);
+static void ip_mr_forward(struct net *net, struct mr_table *mrt,
+                         struct sk_buff *skb, struct mfc_cache *cache,
+                         int local);
 static int ipmr_cache_report(struct mr_table *mrt,
                             struct sk_buff *pkt, vifi_t vifi, int assert);
 static int __ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
@@ -1795,9 +1795,9 @@ static int ipmr_find_vif(struct mr_table *mrt, struct net_device *dev)
 
 /* "local" means that we should preserve one skb (for local delivery) */
 
-static int ip_mr_forward(struct net *net, struct mr_table *mrt,
-                        struct sk_buff *skb, struct mfc_cache *cache,
-                        int local)
+static void ip_mr_forward(struct net *net, struct mr_table *mrt,
+                         struct sk_buff *skb, struct mfc_cache *cache,
+                         int local)
 {
        int psend = -1;
        int vif, ct;
@@ -1903,14 +1903,13 @@ last_forward:
                                ipmr_queue_xmit(net, mrt, skb2, cache, psend);
                } else {
                        ipmr_queue_xmit(net, mrt, skb, cache, psend);
-                       return 0;
+                       return;
                }
        }
 
 dont_forward:
        if (!local)
                kfree_skb(skb);
-       return 0;
 }
 
 static struct mr_table *ipmr_rt_fib_lookup(struct net *net, struct sk_buff *skb)
index a9a54a2368323243be30f536d45646d48ec6c42d..e805481eff722ec80cfdf2117f93810781c3bd7e 100644 (file)
@@ -435,12 +435,12 @@ static inline int ip_rt_proc_init(void)
 
 static inline bool rt_is_expired(const struct rtable *rth)
 {
-       return rth->rt_genid != rt_genid(dev_net(rth->dst.dev));
+       return rth->rt_genid != rt_genid_ipv4(dev_net(rth->dst.dev));
 }
 
 void rt_cache_flush(struct net *net)
 {
-       rt_genid_bump(net);
+       rt_genid_bump_ipv4(net);
 }
 
 static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst,
@@ -1458,7 +1458,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
 #endif
        rth->dst.output = ip_rt_bug;
 
-       rth->rt_genid   = rt_genid(dev_net(dev));
+       rth->rt_genid   = rt_genid_ipv4(dev_net(dev));
        rth->rt_flags   = RTCF_MULTICAST;
        rth->rt_type    = RTN_MULTICAST;
        rth->rt_is_input= 1;
@@ -1589,7 +1589,7 @@ static int __mkroute_input(struct sk_buff *skb,
                goto cleanup;
        }
 
-       rth->rt_genid = rt_genid(dev_net(rth->dst.dev));
+       rth->rt_genid = rt_genid_ipv4(dev_net(rth->dst.dev));
        rth->rt_flags = flags;
        rth->rt_type = res->type;
        rth->rt_is_input = 1;
@@ -1760,7 +1760,7 @@ local_input:
        rth->dst.tclassid = itag;
 #endif
 
-       rth->rt_genid = rt_genid(net);
+       rth->rt_genid = rt_genid_ipv4(net);
        rth->rt_flags   = flags|RTCF_LOCAL;
        rth->rt_type    = res.type;
        rth->rt_is_input = 1;
@@ -1945,7 +1945,7 @@ add:
 
        rth->dst.output = ip_output;
 
-       rth->rt_genid = rt_genid(dev_net(dev_out));
+       rth->rt_genid = rt_genid_ipv4(dev_net(dev_out));
        rth->rt_flags   = flags;
        rth->rt_type    = type;
        rth->rt_is_input = 0;
@@ -2227,7 +2227,7 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or
                rt->rt_iif = ort->rt_iif;
                rt->rt_pmtu = ort->rt_pmtu;
 
-               rt->rt_genid = rt_genid(net);
+               rt->rt_genid = rt_genid_ipv4(net);
                rt->rt_flags = ort->rt_flags;
                rt->rt_type = ort->rt_type;
                rt->rt_gateway = ort->rt_gateway;
@@ -2665,7 +2665,7 @@ static __net_initdata struct pernet_operations sysctl_route_ops = {
 
 static __net_init int rt_genid_init(struct net *net)
 {
-       atomic_set(&net->rt_genid, 0);
+       atomic_set(&net->ipv4.rt_genid, 0);
        atomic_set(&net->fnhe_genid, 0);
        get_random_bytes(&net->ipv4.dev_addr_genid,
                         sizeof(net->ipv4.dev_addr_genid));
index b2c123c44d6947afe1f6d588808643c5db3be9b8..8ed7c32ae28e47bbb73052f4686643d0f5cf7eb6 100644 (file)
@@ -36,6 +36,8 @@ static int tcp_adv_win_scale_min = -31;
 static int tcp_adv_win_scale_max = 31;
 static int ip_ttl_min = 1;
 static int ip_ttl_max = 255;
+static int tcp_syn_retries_min = 1;
+static int tcp_syn_retries_max = MAX_TCP_SYNCNT;
 static int ip_ping_group_range_min[] = { 0, 0 };
 static int ip_ping_group_range_max[] = { GID_T_MAX, GID_T_MAX };
 
@@ -332,7 +334,9 @@ static struct ctl_table ipv4_table[] = {
                .data           = &sysctl_tcp_syn_retries,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &tcp_syn_retries_min,
+               .extra2         = &tcp_syn_retries_max
        },
        {
                .procname       = "tcp_synack_retries",
@@ -554,6 +558,13 @@ static struct ctl_table ipv4_table[] = {
                .proc_handler   = proc_dointvec_minmax,
                .extra1         = &one,
        },
+       {
+               .procname       = "tcp_notsent_lowat",
+               .data           = &sysctl_tcp_notsent_lowat,
+               .maxlen         = sizeof(sysctl_tcp_notsent_lowat),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+       },
        {
                .procname       = "tcp_rmem",
                .data           = &sysctl_tcp_rmem,
index 5423223e93c25074f87c92dc60b338fddcb66f3f..ab64eea042fadea779783247f96cb686b38526fa 100644 (file)
@@ -410,10 +410,6 @@ void tcp_init_sock(struct sock *sk)
 
        icsk->icsk_sync_mss = tcp_sync_mss;
 
-       /* Presumed zeroed, in order of appearance:
-        *      cookie_in_always, cookie_out_never,
-        *      s_data_constant, s_data_in, s_data_out
-        */
        sk->sk_sndbuf = sysctl_tcp_wmem[1];
        sk->sk_rcvbuf = sysctl_tcp_rmem[1];
 
@@ -499,7 +495,7 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait)
                        mask |= POLLIN | POLLRDNORM;
 
                if (!(sk->sk_shutdown & SEND_SHUTDOWN)) {
-                       if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk)) {
+                       if (sk_stream_is_writeable(sk)) {
                                mask |= POLLOUT | POLLWRNORM;
                        } else {  /* send SIGIO later */
                                set_bit(SOCK_ASYNC_NOSPACE,
@@ -510,7 +506,7 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait)
                                 * wspace test but before the flags are set,
                                 * IO signal will be lost.
                                 */
-                               if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk))
+                               if (sk_stream_is_writeable(sk))
                                        mask |= POLLOUT | POLLWRNORM;
                        }
                } else
@@ -2631,6 +2627,10 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
                else
                        tp->tsoffset = val - tcp_time_stamp;
                break;
+       case TCP_NOTSENT_LOWAT:
+               tp->notsent_lowat = val;
+               sk->sk_write_space(sk);
+               break;
        default:
                err = -ENOPROTOOPT;
                break;
@@ -2847,6 +2847,9 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
        case TCP_TIMESTAMP:
                val = tcp_time_stamp + tp->tsoffset;
                break;
+       case TCP_NOTSENT_LOWAT:
+               val = tp->notsent_lowat;
+               break;
        default:
                return -ENOPROTOOPT;
        }
index 28af45abe0622fabac4d53ab651099a580808766..b61274b666f6556e9469dd06b6c84e88534fbc6f 100644 (file)
@@ -1048,6 +1048,7 @@ struct tcp_sacktag_state {
        int reord;
        int fack_count;
        int flag;
+       s32 rtt; /* RTT measured by SACKing never-retransmitted data */
 };
 
 /* Check if skb is fully within the SACK block. In presence of GSO skbs,
@@ -1108,7 +1109,7 @@ static int tcp_match_skb_to_sack(struct sock *sk, struct sk_buff *skb,
 static u8 tcp_sacktag_one(struct sock *sk,
                          struct tcp_sacktag_state *state, u8 sacked,
                          u32 start_seq, u32 end_seq,
-                         bool dup_sack, int pcount)
+                         int dup_sack, int pcount, u32 xmit_time)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        int fack_count = state->fack_count;
@@ -1148,6 +1149,9 @@ static u8 tcp_sacktag_one(struct sock *sk,
                                                           state->reord);
                                if (!after(end_seq, tp->high_seq))
                                        state->flag |= FLAG_ORIG_SACK_ACKED;
+                               /* Pick the earliest sequence sacked for RTT */
+                               if (state->rtt < 0)
+                                       state->rtt = tcp_time_stamp - xmit_time;
                        }
 
                        if (sacked & TCPCB_LOST) {
@@ -1205,7 +1209,8 @@ static bool tcp_shifted_skb(struct sock *sk, struct sk_buff *skb,
         * tcp_highest_sack_seq() when skb is highest_sack.
         */
        tcp_sacktag_one(sk, state, TCP_SKB_CB(skb)->sacked,
-                       start_seq, end_seq, dup_sack, pcount);
+                       start_seq, end_seq, dup_sack, pcount,
+                       TCP_SKB_CB(skb)->when);
 
        if (skb == tp->lost_skb_hint)
                tp->lost_cnt_hint += pcount;
@@ -1479,7 +1484,8 @@ static struct sk_buff *tcp_sacktag_walk(struct sk_buff *skb, struct sock *sk,
                                                TCP_SKB_CB(skb)->seq,
                                                TCP_SKB_CB(skb)->end_seq,
                                                dup_sack,
-                                               tcp_skb_pcount(skb));
+                                               tcp_skb_pcount(skb),
+                                               TCP_SKB_CB(skb)->when);
 
                        if (!before(TCP_SKB_CB(skb)->seq,
                                    tcp_highest_sack_seq(tp)))
@@ -1536,7 +1542,7 @@ static int tcp_sack_cache_ok(const struct tcp_sock *tp, const struct tcp_sack_bl
 
 static int
 tcp_sacktag_write_queue(struct sock *sk, const struct sk_buff *ack_skb,
-                       u32 prior_snd_una)
+                       u32 prior_snd_una, s32 *sack_rtt)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        const unsigned char *ptr = (skb_transport_header(ack_skb) +
@@ -1554,6 +1560,7 @@ tcp_sacktag_write_queue(struct sock *sk, const struct sk_buff *ack_skb,
 
        state.flag = 0;
        state.reord = tp->packets_out;
+       state.rtt = -1;
 
        if (!tp->sacked_out) {
                if (WARN_ON(tp->fackets_out))
@@ -1737,6 +1744,7 @@ out:
        WARN_ON((int)tp->retrans_out < 0);
        WARN_ON((int)tcp_packets_in_flight(tp) < 0);
 #endif
+       *sack_rtt = state.rtt;
        return state.flag;
 }
 
@@ -2792,65 +2800,51 @@ static void tcp_fastretrans_alert(struct sock *sk, const int acked,
        tcp_xmit_retransmit_queue(sk);
 }
 
-void tcp_valid_rtt_meas(struct sock *sk, u32 seq_rtt)
+static inline bool tcp_ack_update_rtt(struct sock *sk, const int flag,
+                                     s32 seq_rtt, s32 sack_rtt)
 {
-       tcp_rtt_estimator(sk, seq_rtt);
-       tcp_set_rto(sk);
-       inet_csk(sk)->icsk_backoff = 0;
-}
-EXPORT_SYMBOL(tcp_valid_rtt_meas);
+       const struct tcp_sock *tp = tcp_sk(sk);
+
+       /* Prefer RTT measured from ACK's timing to TS-ECR. This is because
+        * broken middle-boxes or peers may corrupt TS-ECR fields. But
+        * Karn's algorithm forbids taking RTT if some retransmitted data
+        * is acked (RFC6298).
+        */
+       if (flag & FLAG_RETRANS_DATA_ACKED)
+               seq_rtt = -1;
+
+       if (seq_rtt < 0)
+               seq_rtt = sack_rtt;
 
-/* Read draft-ietf-tcplw-high-performance before mucking
- * with this code. (Supersedes RFC1323)
- */
-static void tcp_ack_saw_tstamp(struct sock *sk, int flag)
-{
        /* RTTM Rule: A TSecr value received in a segment is used to
         * update the averaged RTT measurement only if the segment
         * acknowledges some new data, i.e., only if it advances the
         * left edge of the send window.
-        *
         * See draft-ietf-tcplw-high-performance-00, section 3.3.
-        * 1998/04/10 Andrey V. Savochkin <saw@msu.ru>
-        *
-        * Changed: reset backoff as soon as we see the first valid sample.
-        * If we do not, we get strongly overestimated rto. With timestamps
-        * samples are accepted even from very old segments: f.e., when rtt=1
-        * increases to 8, we retransmit 5 times and after 8 seconds delayed
-        * answer arrives rto becomes 120 seconds! If at least one of segments
-        * in window is lost... Voila.                          --ANK (010210)
         */
-       struct tcp_sock *tp = tcp_sk(sk);
-
-       tcp_valid_rtt_meas(sk, tcp_time_stamp - tp->rx_opt.rcv_tsecr);
-}
+       if (seq_rtt < 0 && tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr)
+               seq_rtt = tcp_time_stamp - tp->rx_opt.rcv_tsecr;
 
-static void tcp_ack_no_tstamp(struct sock *sk, u32 seq_rtt, int flag)
-{
-       /* We don't have a timestamp. Can only use
-        * packets that are not retransmitted to determine
-        * rtt estimates. Also, we must not reset the
-        * backoff for rto until we get a non-retransmitted
-        * packet. This allows us to deal with a situation
-        * where the network delay has increased suddenly.
-        * I.e. Karn's algorithm. (SIGCOMM '87, p5.)
-        */
+       if (seq_rtt < 0)
+               return false;
 
-       if (flag & FLAG_RETRANS_DATA_ACKED)
-               return;
+       tcp_rtt_estimator(sk, seq_rtt);
+       tcp_set_rto(sk);
 
-       tcp_valid_rtt_meas(sk, seq_rtt);
+       /* RFC6298: only reset backoff on valid RTT measurement. */
+       inet_csk(sk)->icsk_backoff = 0;
+       return true;
 }
 
-static inline void tcp_ack_update_rtt(struct sock *sk, const int flag,
-                                     const s32 seq_rtt)
+/* Compute time elapsed between (last) SYNACK and the ACK completing 3WHS. */
+static void tcp_synack_rtt_meas(struct sock *sk, struct request_sock *req)
 {
-       const struct tcp_sock *tp = tcp_sk(sk);
-       /* Note that peer MAY send zero echo. In this case it is ignored. (rfc1323) */
-       if (tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr)
-               tcp_ack_saw_tstamp(sk, flag);
-       else if (seq_rtt >= 0)
-               tcp_ack_no_tstamp(sk, seq_rtt, flag);
+       struct tcp_sock *tp = tcp_sk(sk);
+       s32 seq_rtt = -1;
+
+       if (tp->lsndtime && !tp->total_retrans)
+               seq_rtt = tcp_time_stamp - tp->lsndtime;
+       tcp_ack_update_rtt(sk, FLAG_SYN_ACKED, seq_rtt, -1);
 }
 
 static void tcp_cong_avoid(struct sock *sk, u32 ack, u32 in_flight)
@@ -2939,7 +2933,7 @@ static u32 tcp_tso_acked(struct sock *sk, struct sk_buff *skb)
  * arrived at the other end.
  */
 static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
-                              u32 prior_snd_una)
+                              u32 prior_snd_una, s32 sack_rtt)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        const struct inet_connection_sock *icsk = inet_csk(sk);
@@ -2978,8 +2972,6 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
                        if (sacked & TCPCB_SACKED_RETRANS)
                                tp->retrans_out -= acked_pcount;
                        flag |= FLAG_RETRANS_DATA_ACKED;
-                       ca_seq_rtt = -1;
-                       seq_rtt = -1;
                } else {
                        ca_seq_rtt = now - scb->when;
                        last_ackt = skb->tstamp;
@@ -3031,6 +3023,10 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
        if (skb && (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED))
                flag |= FLAG_SACK_RENEGING;
 
+       if (tcp_ack_update_rtt(sk, flag, seq_rtt, sack_rtt) ||
+           (flag & FLAG_ACKED))
+               tcp_rearm_rto(sk);
+
        if (flag & FLAG_ACKED) {
                const struct tcp_congestion_ops *ca_ops
                        = inet_csk(sk)->icsk_ca_ops;
@@ -3040,9 +3036,6 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
                        tcp_mtup_probe_success(sk);
                }
 
-               tcp_ack_update_rtt(sk, flag, seq_rtt);
-               tcp_rearm_rto(sk);
-
                if (tcp_is_reno(tp)) {
                        tcp_remove_reno_sacks(sk, pkts_acked);
                } else {
@@ -3274,6 +3267,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
        int prior_packets = tp->packets_out;
        const int prior_unsacked = tp->packets_out - tp->sacked_out;
        int acked = 0; /* Number of packets newly acked */
+       s32 sack_rtt = -1;
 
        /* If the ack is older than previous acks
         * then we can probably ignore it.
@@ -3330,7 +3324,8 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
                flag |= tcp_ack_update_window(sk, skb, ack, ack_seq);
 
                if (TCP_SKB_CB(skb)->sacked)
-                       flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una);
+                       flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una,
+                                                       &sack_rtt);
 
                if (TCP_ECN_rcv_ecn_echo(tp, tcp_hdr(skb)))
                        flag |= FLAG_ECE;
@@ -3349,7 +3344,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
 
        /* See if we can take anything off of the retransmit queue. */
        acked = tp->packets_out;
-       flag |= tcp_clean_rtx_queue(sk, prior_fackets, prior_snd_una);
+       flag |= tcp_clean_rtx_queue(sk, prior_fackets, prior_snd_una, sack_rtt);
        acked -= tp->packets_out;
 
        if (tcp_ack_is_dubious(sk, flag)) {
@@ -3402,7 +3397,8 @@ old_ack:
         * If data was DSACKed, see if we can undo a cwnd reduction.
         */
        if (TCP_SKB_CB(skb)->sacked) {
-               flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una);
+               flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una,
+                                               &sack_rtt);
                tcp_fastretrans_alert(sk, acked, prior_unsacked,
                                      is_dupack, flag);
        }
@@ -5624,9 +5620,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                 * so release it.
                 */
                if (req) {
-                       tcp_synack_rtt_meas(sk, req);
                        tp->total_retrans = req->num_retrans;
-
                        reqsk_fastopen_remove(sk, req, false);
                } else {
                        /* Make sure socket is routed, for correct metrics. */
@@ -5651,6 +5645,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                tp->snd_una = TCP_SKB_CB(skb)->ack_seq;
                tp->snd_wnd = ntohs(th->window) << tp->rx_opt.snd_wscale;
                tcp_init_wl(tp, TCP_SKB_CB(skb)->seq);
+               tcp_synack_rtt_meas(sk, req);
 
                if (tp->rx_opt.tstamp_ok)
                        tp->advmss -= TCPOLEN_TSTAMP_ALIGNED;
index b299da5ff4996fb5785d2725c66c43d91db918d4..280efe5f19c1c86385bf8e15c146d8ac31135198 100644 (file)
@@ -890,7 +890,7 @@ bool tcp_syn_flood_action(struct sock *sk,
                NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPREQQFULLDROP);
 
        lopt = inet_csk(sk)->icsk_accept_queue.listen_opt;
-       if (!lopt->synflood_warned) {
+       if (!lopt->synflood_warned && sysctl_tcp_syncookies != 2) {
                lopt->synflood_warned = 1;
                pr_info("%s: Possible SYN flooding on port %d. %s.  Check SNMP counters.\n",
                        proto, ntohs(tcp_hdr(skb)->dest), msg);
@@ -1462,7 +1462,8 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
         * limitations, they conserve resources and peer is
         * evidently real one.
         */
-       if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
+       if ((sysctl_tcp_syncookies == 2 ||
+            inet_csk_reqsk_queue_is_full(sk)) && !isn) {
                want_cookie = tcp_syn_flood_action(sk, skb, "TCP");
                if (!want_cookie)
                        goto drop;
@@ -1671,8 +1672,6 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
                newtp->advmss = tcp_sk(sk)->rx_opt.user_mss;
 
        tcp_initialize_rcv_mss(newsk);
-       tcp_synack_rtt_meas(newsk, req);
-       newtp->total_retrans = req->num_retrans;
 
 #ifdef CONFIG_TCP_MD5SIG
        /* Copy over the MD5 key from the original socket */
@@ -2802,6 +2801,7 @@ struct proto tcp_prot = {
        .unhash                 = inet_unhash,
        .get_port               = inet_csk_get_port,
        .enter_memory_pressure  = tcp_enter_memory_pressure,
+       .stream_memory_free     = tcp_stream_memory_free,
        .sockets_allocated      = &tcp_sockets_allocated,
        .orphan_count           = &tcp_orphan_count,
        .memory_allocated       = &tcp_memory_allocated,
index ab1c08658528e7737fd1683841a4d11701cbc0bb..58a3e69aef6440d36061ea9e6291152442954239 100644 (file)
@@ -411,6 +411,8 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
                newtp->snd_ssthresh = TCP_INFINITE_SSTHRESH;
                tcp_enable_early_retrans(newtp);
                newtp->tlp_high_seq = 0;
+               newtp->lsndtime = treq->snt_synack;
+               newtp->total_retrans = req->num_retrans;
 
                /* So many TCP implementations out there (incorrectly) count the
                 * initial SYN frame in their delayed-ACK and congestion control
@@ -666,12 +668,6 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
        if (!(flg & TCP_FLAG_ACK))
                return NULL;
 
-       /* Got ACK for our SYNACK, so update baseline for SYNACK RTT sample. */
-       if (tmp_opt.saw_tstamp && tmp_opt.rcv_tsecr)
-               tcp_rsk(req)->snt_synack = tmp_opt.rcv_tsecr;
-       else if (req->num_retrans) /* don't take RTT sample if retrans && ~TS */
-               tcp_rsk(req)->snt_synack = 0;
-
        /* For Fast Open no more processing is needed (sk is the
         * child socket).
         */
index 92fde8d1aa821c38b59ba467fe386eb3306c2dfe..884efff5b531f9c6177a789ea5013c0492939afa 100644 (file)
@@ -65,6 +65,9 @@ int sysctl_tcp_base_mss __read_mostly = TCP_BASE_MSS;
 /* By default, RFC2861 behavior.  */
 int sysctl_tcp_slow_start_after_idle __read_mostly = 1;
 
+unsigned int sysctl_tcp_notsent_lowat __read_mostly = UINT_MAX;
+EXPORT_SYMBOL(sysctl_tcp_notsent_lowat);
+
 static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
                           int push_one, gfp_t gfp);
 
index 766e6bab911362cb0caa44511b10bb82418e7980..9e88af0e8ab0356a1e7a8c72ab6cf8ef1ad2e8ac 100644 (file)
@@ -704,7 +704,7 @@ EXPORT_SYMBOL(udp_flush_pending_frames);
  *     @src:   source IP address
  *     @dst:   destination IP address
  */
-static void udp4_hwcsum(struct sk_buff *skb, __be32 src, __be32 dst)
+void udp4_hwcsum(struct sk_buff *skb, __be32 src, __be32 dst)
 {
        struct udphdr *uh = udp_hdr(skb);
        struct sk_buff *frags = skb_shinfo(skb)->frag_list;
@@ -740,6 +740,7 @@ static void udp4_hwcsum(struct sk_buff *skb, __be32 src, __be32 dst)
                        uh->check = CSUM_MANGLED_0;
        }
 }
+EXPORT_SYMBOL_GPL(udp4_hwcsum);
 
 static int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4)
 {
index cfdcf7b2daf68ff681608351e0bca7202923824b..7fd8572bac8090fbfac136718dbfd782dfb98a2c 100644 (file)
@@ -813,8 +813,9 @@ static u32 inet6_addr_hash(const struct in6_addr *addr)
 /* On success it returns ifp with increased reference count */
 
 static struct inet6_ifaddr *
-ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
-             int scope, u32 flags)
+ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr,
+             const struct in6_addr *peer_addr, int pfxlen,
+             int scope, u32 flags, u32 valid_lft, u32 prefered_lft)
 {
        struct inet6_ifaddr *ifa = NULL;
        struct rt6_info *rt;
@@ -863,6 +864,8 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
        }
 
        ifa->addr = *addr;
+       if (peer_addr)
+               ifa->peer_addr = *peer_addr;
 
        spin_lock_init(&ifa->lock);
        spin_lock_init(&ifa->state_lock);
@@ -872,6 +875,8 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
        ifa->scope = scope;
        ifa->prefix_len = pfxlen;
        ifa->flags = flags | IFA_F_TENTATIVE;
+       ifa->valid_lft = valid_lft;
+       ifa->prefered_lft = prefered_lft;
        ifa->cstamp = ifa->tstamp = jiffies;
        ifa->tokenized = false;
 
@@ -1123,8 +1128,9 @@ retry:
 
        ift = !max_addresses ||
              ipv6_count_addresses(idev) < max_addresses ?
-               ipv6_add_addr(idev, &addr, tmp_plen, ipv6_addr_scope(&addr),
-                             addr_flags) : NULL;
+               ipv6_add_addr(idev, &addr, NULL, tmp_plen,
+                             ipv6_addr_scope(&addr), addr_flags,
+                             tmp_valid_lft, tmp_prefered_lft) : NULL;
        if (IS_ERR_OR_NULL(ift)) {
                in6_ifa_put(ifp);
                in6_dev_put(idev);
@@ -1136,8 +1142,6 @@ retry:
 
        spin_lock_bh(&ift->lock);
        ift->ifpub = ifp;
-       ift->valid_lft = tmp_valid_lft;
-       ift->prefered_lft = tmp_prefered_lft;
        ift->cstamp = now;
        ift->tstamp = tmp_tstamp;
        spin_unlock_bh(&ift->lock);
@@ -2179,16 +2183,19 @@ ok:
                         */
                        if (!max_addresses ||
                            ipv6_count_addresses(in6_dev) < max_addresses)
-                               ifp = ipv6_add_addr(in6_dev, &addr, pinfo->prefix_len,
+                               ifp = ipv6_add_addr(in6_dev, &addr, NULL,
+                                                   pinfo->prefix_len,
                                                    addr_type&IPV6_ADDR_SCOPE_MASK,
-                                                   addr_flags);
+                                                   addr_flags, valid_lft,
+                                                   prefered_lft);
 
                        if (IS_ERR_OR_NULL(ifp)) {
                                in6_dev_put(in6_dev);
                                return;
                        }
 
-                       update_lft = create = 1;
+                       update_lft = 0;
+                       create = 1;
                        ifp->cstamp = jiffies;
                        ifp->tokenized = tokenized;
                        addrconf_dad_start(ifp);
@@ -2209,7 +2216,7 @@ ok:
                                stored_lft = ifp->valid_lft - (now - ifp->tstamp) / HZ;
                        else
                                stored_lft = 0;
-                       if (!update_lft && stored_lft) {
+                       if (!update_lft && !create && stored_lft) {
                                if (valid_lft > MIN_VALID_LIFETIME ||
                                    valid_lft > stored_lft)
                                        update_lft = 1;
@@ -2455,17 +2462,10 @@ static int inet6_addr_add(struct net *net, int ifindex, const struct in6_addr *p
                prefered_lft = timeout;
        }
 
-       ifp = ipv6_add_addr(idev, pfx, plen, scope, ifa_flags);
+       ifp = ipv6_add_addr(idev, pfx, peer_pfx, plen, scope, ifa_flags,
+                           valid_lft, prefered_lft);
 
        if (!IS_ERR(ifp)) {
-               spin_lock_bh(&ifp->lock);
-               ifp->valid_lft = valid_lft;
-               ifp->prefered_lft = prefered_lft;
-               ifp->tstamp = jiffies;
-               if (peer_pfx)
-                       ifp->peer_addr = *peer_pfx;
-               spin_unlock_bh(&ifp->lock);
-
                addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev,
                                      expires, flags);
                /*
@@ -2557,7 +2557,8 @@ static void add_addr(struct inet6_dev *idev, const struct in6_addr *addr,
 {
        struct inet6_ifaddr *ifp;
 
-       ifp = ipv6_add_addr(idev, addr, plen, scope, IFA_F_PERMANENT);
+       ifp = ipv6_add_addr(idev, addr, NULL, plen,
+                           scope, IFA_F_PERMANENT, 0, 0);
        if (!IS_ERR(ifp)) {
                spin_lock_bh(&ifp->lock);
                ifp->flags &= ~IFA_F_TENTATIVE;
@@ -2683,7 +2684,7 @@ static void addrconf_add_linklocal(struct inet6_dev *idev, const struct in6_addr
 #endif
 
 
-       ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, addr_flags);
+       ifp = ipv6_add_addr(idev, addr, NULL, 64, IFA_LINK, addr_flags, 0, 0);
        if (!IS_ERR(ifp)) {
                addrconf_prefix_route(&ifp->addr, ifp->prefix_len, idev->dev, 0, 0);
                addrconf_dad_start(ifp);
@@ -4653,6 +4654,7 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
                break;
        }
        atomic_inc(&net->ipv6.dev_addr_genid);
+       rt_genid_bump_ipv6(net);
 }
 
 static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
index a5ac969aeefe5337d7fa4c5601912fb96b1a5496..0d1a9b153fbb8c82d680015d382429472d42cfcb 100644 (file)
@@ -766,6 +766,7 @@ static int __net_init inet6_net_init(struct net *net)
 
        net->ipv6.sysctl.bindv6only = 0;
        net->ipv6.sysctl.icmpv6_time = 1*HZ;
+       atomic_set(&net->ipv6.rt_genid, 0);
 
        err = ipv6_init_mibs(net);
        if (err)
index 2e1a432867c0897f4e0d4439f9c6fd5d3f4c66cb..554a4fbabfb3b2dbf9ab4418e3b4c0683c0580d1 100644 (file)
@@ -55,26 +55,33 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
        struct fib6_table *table;
        struct net *net = rule->fr_net;
        pol_lookup_t lookup = arg->lookup_ptr;
+       int err = 0;
 
        switch (rule->action) {
        case FR_ACT_TO_TBL:
                break;
        case FR_ACT_UNREACHABLE:
+               err = -ENETUNREACH;
                rt = net->ipv6.ip6_null_entry;
                goto discard_pkt;
        default:
        case FR_ACT_BLACKHOLE:
+               err = -EINVAL;
                rt = net->ipv6.ip6_blk_hole_entry;
                goto discard_pkt;
        case FR_ACT_PROHIBIT:
+               err = -EACCES;
                rt = net->ipv6.ip6_prohibit_entry;
                goto discard_pkt;
        }
 
        table = fib6_get_table(net, rule->table);
-       if (table)
-               rt = lookup(net, table, flp6, flags);
+       if (!table) {
+               err = -EAGAIN;
+               goto out;
+       }
 
+       rt = lookup(net, table, flp6, flags);
        if (rt != net->ipv6.ip6_null_entry) {
                struct fib6_rule *r = (struct fib6_rule *)rule;
 
@@ -101,6 +108,7 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
        }
 again:
        ip6_rt_put(rt);
+       err = -EAGAIN;
        rt = NULL;
        goto out;
 
@@ -108,9 +116,21 @@ discard_pkt:
        dst_hold(&rt->dst);
 out:
        arg->result = rt;
-       return rt == NULL ? -EAGAIN : 0;
+       return err;
 }
 
+static bool fib6_rule_suppress(struct fib_rule *rule, struct fib_lookup_arg *arg)
+{
+       struct rt6_info *rt = (struct rt6_info *) arg->result;
+       /* do not accept result if the route does
+        * not meet the required prefix length
+        */
+       if (rt->rt6i_dst.plen < rule->table_prefixlen_min) {
+               ip6_rt_put(rt);
+               return true;
+       }
+       return false;
+}
 
 static int fib6_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)
 {
@@ -244,6 +264,7 @@ static const struct fib_rules_ops __net_initconst fib6_rules_ops_template = {
        .addr_size              = sizeof(struct in6_addr),
        .action                 = fib6_rule_action,
        .match                  = fib6_rule_match,
+       .suppress               = fib6_rule_suppress,
        .configure              = fib6_rule_configure,
        .compare                = fib6_rule_compare,
        .fill                   = fib6_rule_fill,
index 5fc9c7a68d8d102aef37b7b13ab1dd772553a9cb..ed828d6f37b20c7917a0bbee96b64cbe15786ab7 100644 (file)
@@ -425,8 +425,8 @@ out:
  *     node.
  */
 
-static struct fib6_node * fib6_add_1(struct fib6_node *root, void *addr,
-                                    int addrlen, int plen,
+static struct fib6_node *fib6_add_1(struct fib6_node *root,
+                                    struct in6_addr *addr, int plen,
                                     int offset, int allow_create,
                                     int replace_required)
 {
@@ -543,7 +543,7 @@ insert_above:
           but if it is >= plen, the value is ignored in any case.
         */
 
-       bit = __ipv6_addr_diff(addr, &key->addr, addrlen);
+       bit = __ipv6_addr_diff(addr, &key->addr, sizeof(*addr));
 
        /*
         *              (intermediate)[in]
@@ -822,9 +822,9 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info)
        if (!allow_create && !replace_required)
                pr_warn("RTM_NEWROUTE with no NLM_F_CREATE or NLM_F_REPLACE\n");
 
-       fn = fib6_add_1(root, &rt->rt6i_dst.addr, sizeof(struct in6_addr),
-                       rt->rt6i_dst.plen, offsetof(struct rt6_info, rt6i_dst),
-                       allow_create, replace_required);
+       fn = fib6_add_1(root, &rt->rt6i_dst.addr, rt->rt6i_dst.plen,
+                       offsetof(struct rt6_info, rt6i_dst), allow_create,
+                       replace_required);
 
        if (IS_ERR(fn)) {
                err = PTR_ERR(fn);
@@ -863,7 +863,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info)
                        /* Now add the first leaf node to new subtree */
 
                        sn = fib6_add_1(sfn, &rt->rt6i_src.addr,
-                                       sizeof(struct in6_addr), rt->rt6i_src.plen,
+                                       rt->rt6i_src.plen,
                                        offsetof(struct rt6_info, rt6i_src),
                                        allow_create, replace_required);
 
@@ -882,7 +882,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info)
                        fn->subtree = sfn;
                } else {
                        sn = fib6_add_1(fn->subtree, &rt->rt6i_src.addr,
-                                       sizeof(struct in6_addr), rt->rt6i_src.plen,
+                                       rt->rt6i_src.plen,
                                        offsetof(struct rt6_info, rt6i_src),
                                        allow_create, replace_required);
 
@@ -1632,27 +1632,28 @@ static int fib6_age(struct rt6_info *rt, void *arg)
 
 static DEFINE_SPINLOCK(fib6_gc_lock);
 
-void fib6_run_gc(unsigned long expires, struct net *net)
+void fib6_run_gc(unsigned long expires, struct net *net, bool force)
 {
-       if (expires != ~0UL) {
+       unsigned long now;
+
+       if (force) {
                spin_lock_bh(&fib6_gc_lock);
-               gc_args.timeout = expires ? (int)expires :
-                       net->ipv6.sysctl.ip6_rt_gc_interval;
-       } else {
-               if (!spin_trylock_bh(&fib6_gc_lock)) {
-                       mod_timer(&net->ipv6.ip6_fib_timer, jiffies + HZ);
-                       return;
-               }
-               gc_args.timeout = net->ipv6.sysctl.ip6_rt_gc_interval;
+       } else if (!spin_trylock_bh(&fib6_gc_lock)) {
+               mod_timer(&net->ipv6.ip6_fib_timer, jiffies + HZ);
+               return;
        }
+       gc_args.timeout = expires ? (int)expires :
+                         net->ipv6.sysctl.ip6_rt_gc_interval;
 
        gc_args.more = icmp6_dst_gc();
 
        fib6_clean_all(net, fib6_age, 0, NULL);
+       now = jiffies;
+       net->ipv6.ip6_rt_last_gc = now;
 
        if (gc_args.more)
                mod_timer(&net->ipv6.ip6_fib_timer,
-                         round_jiffies(jiffies
+                         round_jiffies(now
                                        + net->ipv6.sysctl.ip6_rt_gc_interval));
        else
                del_timer(&net->ipv6.ip6_fib_timer);
@@ -1661,7 +1662,7 @@ void fib6_run_gc(unsigned long expires, struct net *net)
 
 static void fib6_gc_timer_cb(unsigned long arg)
 {
-       fib6_run_gc(0, (struct net *)arg);
+       fib6_run_gc(0, (struct net *)arg, true);
 }
 
 static int __net_init fib6_net_init(struct net *net)
index 583e8d435f9a2c47437d3897b7167ac4a4025a40..a60a84ef04f7f880b23479e9f8fa047b3905af75 100644 (file)
@@ -110,8 +110,8 @@ static struct kmem_cache *mrt_cachep __read_mostly;
 static struct mr6_table *ip6mr_new_table(struct net *net, u32 id);
 static void ip6mr_free_table(struct mr6_table *mrt);
 
-static int ip6_mr_forward(struct net *net, struct mr6_table *mrt,
-                         struct sk_buff *skb, struct mfc6_cache *cache);
+static void ip6_mr_forward(struct net *net, struct mr6_table *mrt,
+                          struct sk_buff *skb, struct mfc6_cache *cache);
 static int ip6mr_cache_report(struct mr6_table *mrt, struct sk_buff *pkt,
                              mifi_t mifi, int assert);
 static int __ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb,
@@ -259,10 +259,12 @@ static void __net_exit ip6mr_rules_exit(struct net *net)
 {
        struct mr6_table *mrt, *next;
 
+       rtnl_lock();
        list_for_each_entry_safe(mrt, next, &net->ipv6.mr6_tables, list) {
                list_del(&mrt->list);
                ip6mr_free_table(mrt);
        }
+       rtnl_unlock();
        fib_rules_unregister(net->ipv6.mr6_rules_ops);
 }
 #else
@@ -289,7 +291,10 @@ static int __net_init ip6mr_rules_init(struct net *net)
 
 static void __net_exit ip6mr_rules_exit(struct net *net)
 {
+       rtnl_lock();
        ip6mr_free_table(net->ipv6.mrt6);
+       net->ipv6.mrt6 = NULL;
+       rtnl_unlock();
 }
 #endif
 
@@ -2069,8 +2074,8 @@ static int ip6mr_find_vif(struct mr6_table *mrt, struct net_device *dev)
        return ct;
 }
 
-static int ip6_mr_forward(struct net *net, struct mr6_table *mrt,
-                         struct sk_buff *skb, struct mfc6_cache *cache)
+static void ip6_mr_forward(struct net *net, struct mr6_table *mrt,
+                          struct sk_buff *skb, struct mfc6_cache *cache)
 {
        int psend = -1;
        int vif, ct;
@@ -2151,12 +2156,11 @@ forward:
 last_forward:
        if (psend != -1) {
                ip6mr_forward2(net, mrt, skb, cache, psend);
-               return 0;
+               return;
        }
 
 dont_forward:
        kfree_skb(skb);
-       return 0;
 }
 
 
index 99cd65c715cdd4a41a31f6ddc1fa28d327651634..db25b8eb62bda9f7e5a0a352ca79a83a7aca00eb 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
+#include <linux/pkt_sched.h>
 #include <net/mld.h>
 
 #include <linux/netfilter.h>
@@ -1376,6 +1377,7 @@ static struct sk_buff *mld_newpack(struct inet6_dev *idev, int size)
        if (!skb)
                return NULL;
 
+       skb->priority = TC_PRIO_CONTROL;
        skb_reserve(skb, hlen);
 
        if (__ipv6_get_lladdr(idev, &addr_buf, IFA_F_TENTATIVE)) {
@@ -1769,7 +1771,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
                rcu_read_unlock();
                return;
        }
-
+       skb->priority = TC_PRIO_CONTROL;
        skb_reserve(skb, hlen);
 
        if (ipv6_get_lladdr(dev, &addr_buf, IFA_F_TENTATIVE)) {
index 24c03396e0083b751d2a924b69b2dc731f1b957f..79aa9652ed86d9cac754366c075800fbbe4aca1b 100644 (file)
@@ -1576,7 +1576,7 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event,
        switch (event) {
        case NETDEV_CHANGEADDR:
                neigh_changeaddr(&nd_tbl, dev);
-               fib6_run_gc(~0UL, net);
+               fib6_run_gc(0, net, false);
                idev = in6_dev_get(dev);
                if (!idev)
                        break;
@@ -1586,7 +1586,7 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event,
                break;
        case NETDEV_DOWN:
                neigh_ifdown(&nd_tbl, dev);
-               fib6_run_gc(~0UL, net);
+               fib6_run_gc(0, net, false);
                break;
        case NETDEV_NOTIFY_PEERS:
                ndisc_send_unsol_na(dev);
index a8c891aa24645e9a45d2f8e47712b0698a29b216..e22c4db8d07aded12104ed64bafd52e95be2b963 100644 (file)
@@ -283,9 +283,8 @@ static inline struct rt6_info *ip6_dst_alloc(struct net *net,
 
                memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst));
                rt6_init_peer(rt, table ? &table->tb6_peers : net->ipv6.peers);
-               rt->rt6i_genid = rt_genid(net);
+               rt->rt6i_genid = rt_genid_ipv6(net);
                INIT_LIST_HEAD(&rt->rt6i_siblings);
-               rt->rt6i_nsiblings = 0;
        }
        return rt;
 }
@@ -1062,7 +1061,7 @@ static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
         * DST_OBSOLETE_FORCE_CHK which forces validation calls down
         * into this function always.
         */
-       if (rt->rt6i_genid != rt_genid(dev_net(rt->dst.dev)))
+       if (rt->rt6i_genid != rt_genid_ipv6(dev_net(rt->dst.dev)))
                return NULL;
 
        if (rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie))
@@ -1311,7 +1310,6 @@ static void icmp6_clean_all(int (*func)(struct rt6_info *rt, void *arg),
 
 static int ip6_dst_gc(struct dst_ops *ops)
 {
-       unsigned long now = jiffies;
        struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops);
        int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval;
        int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size;
@@ -1321,13 +1319,12 @@ static int ip6_dst_gc(struct dst_ops *ops)
        int entries;
 
        entries = dst_entries_get_fast(ops);
-       if (time_after(rt_last_gc + rt_min_interval, now) &&
+       if (time_after(rt_last_gc + rt_min_interval, jiffies) &&
            entries <= rt_max_size)
                goto out;
 
        net->ipv6.ip6_rt_gc_expire++;
-       fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net);
-       net->ipv6.ip6_rt_last_gc = now;
+       fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net, entries > rt_max_size);
        entries = dst_entries_get_slow(ops);
        if (entries < ops->gc_thresh)
                net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
@@ -2827,7 +2824,7 @@ int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write,
        net = (struct net *)ctl->extra1;
        delay = net->ipv6.sysctl.flush_delay;
        proc_dointvec(ctl, write, buffer, lenp, ppos);
-       fib6_run_gc(delay <= 0 ? ~0UL : (unsigned long)delay, net);
+       fib6_run_gc(delay <= 0 ? 0 : (unsigned long)delay, net, delay > 0);
        return 0;
 }
 
index 6e1649d58533fd9a1b0a3f9f4373348a625bfb60..38c196ca6011a5390693c374b1b2f8e8c2203ba4 100644 (file)
@@ -963,7 +963,8 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
        if (!ipv6_unicast_destination(skb))
                goto drop;
 
-       if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
+       if ((sysctl_tcp_syncookies == 2 ||
+            inet_csk_reqsk_queue_is_full(sk)) && !isn) {
                want_cookie = tcp_syn_flood_action(sk, skb, "TCPv6");
                if (!want_cookie)
                        goto drop;
@@ -1237,8 +1238,6 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
                newtp->advmss = tcp_sk(sk)->rx_opt.user_mss;
 
        tcp_initialize_rcv_mss(newsk);
-       tcp_synack_rtt_meas(newsk, req);
-       newtp->total_retrans = req->num_retrans;
 
        newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6;
        newinet->inet_rcv_saddr = LOOPBACK4_IPV6;
@@ -1926,6 +1925,7 @@ struct proto tcpv6_prot = {
        .unhash                 = inet_unhash,
        .get_port               = inet_csk_get_port,
        .enter_memory_pressure  = tcp_enter_memory_pressure,
+       .stream_memory_free     = tcp_stream_memory_free,
        .sockets_allocated      = &tcp_sockets_allocated,
        .memory_allocated       = &tcp_memory_allocated,
        .memory_pressure        = &tcp_memory_pressure,
index ae43c62f9045ba94ced0f025a9ecacb3bf145af1..85372cfa7b9f82b690579de4533ac27cf4ad09f6 100644 (file)
@@ -75,7 +75,7 @@ static pi_minor_info_t pi_minor_call_table[] = {
        { NULL, 0 },                                             /* 0x00 */
        { irttp_param_max_sdu_size, PV_INTEGER | PV_BIG_ENDIAN } /* 0x01 */
 };
-static pi_major_info_t pi_major_call_table[] = {{ pi_minor_call_table, 2 }};
+static pi_major_info_t pi_major_call_table[] = { { pi_minor_call_table, 2 } };
 static pi_param_info_t param_info = { pi_major_call_table, 1, 0x0f, 4 };
 
 /************************ GLOBAL PROCEDURES ************************/
@@ -205,7 +205,7 @@ static void irttp_todo_expired(unsigned long data)
  */
 static void irttp_flush_queues(struct tsap_cb *self)
 {
-       struct sk_buffskb;
+       struct sk_buff *skb;
 
        IRDA_DEBUG(4, "%s()\n", __func__);
 
@@ -400,7 +400,7 @@ struct tsap_cb *irttp_open_tsap(__u8 stsap_sel, int credit, notify_t *notify)
        /* The IrLMP spec (IrLMP 1.1 p10) says that we have the right to
         * use only 0x01-0x6F. Of course, we can use LSAP_ANY as well.
         * JeanII */
-       if((stsap_sel != LSAP_ANY) &&
+       if ((stsap_sel != LSAP_ANY) &&
           ((stsap_sel < 0x01) || (stsap_sel >= 0x70))) {
                IRDA_DEBUG(0, "%s(), invalid tsap!\n", __func__);
                return NULL;
@@ -427,7 +427,7 @@ struct tsap_cb *irttp_open_tsap(__u8 stsap_sel, int credit, notify_t *notify)
        ttp_notify.data_indication = irttp_data_indication;
        ttp_notify.udata_indication = irttp_udata_indication;
        ttp_notify.flow_indication = irttp_flow_indication;
-       if(notify->status_indication != NULL)
+       if (notify->status_indication != NULL)
                ttp_notify.status_indication = irttp_status_indication;
        ttp_notify.instance = self;
        strncpy(ttp_notify.name, notify->name, NOTIFY_MAX_NAME);
@@ -639,8 +639,7 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb)
         */
        if ((self->tx_max_sdu_size != 0) &&
            (self->tx_max_sdu_size != TTP_SAR_UNBOUND) &&
-           (skb->len > self->tx_max_sdu_size))
-       {
+           (skb->len > self->tx_max_sdu_size)) {
                IRDA_ERROR("%s: SAR enabled, but data is larger than TxMaxSduSize!\n",
                           __func__);
                ret = -EMSGSIZE;
@@ -733,8 +732,7 @@ static void irttp_run_tx_queue(struct tsap_cb *self)
         * poll us through irttp_flow_indication() - Jean II */
        while ((self->send_credit > 0) &&
               (!irlmp_lap_tx_queue_full(self->lsap)) &&
-              (skb = skb_dequeue(&self->tx_queue)))
-       {
+              (skb = skb_dequeue(&self->tx_queue))) {
                /*
                 *  Since we can transmit and receive frames concurrently,
                 *  the code below is a critical region and we must assure that
@@ -798,8 +796,7 @@ static void irttp_run_tx_queue(struct tsap_cb *self)
         * where we can spend a bit of time doing stuff. - Jean II */
        if ((self->tx_sdu_busy) &&
            (skb_queue_len(&self->tx_queue) < TTP_TX_LOW_THRESHOLD) &&
-           (!self->close_pend))
-       {
+           (!self->close_pend)) {
                if (self->notify.flow_indication)
                        self->notify.flow_indication(self->notify.instance,
                                                     self, FLOW_START);
@@ -892,7 +889,7 @@ static int irttp_udata_indication(void *instance, void *sap,
        /* Just pass data to layer above */
        if (self->notify.udata_indication) {
                err = self->notify.udata_indication(self->notify.instance,
-                                                   self,skb);
+                                                   self, skb);
                /* Same comment as in irttp_do_data_indication() */
                if (!err)
                        return 0;
@@ -1057,7 +1054,7 @@ static void irttp_flow_indication(void *instance, void *sap, LOCAL_FLOW flow)
         * to do that. Jean II */
 
        /* If we need to send disconnect. try to do it now */
-       if(self->disconnect_pend)
+       if (self->disconnect_pend)
                irttp_start_todo_timer(self, 0);
 }
 
@@ -1116,7 +1113,7 @@ int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel,
        IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -EBADR;);
 
        if (self->connected) {
-               if(userdata)
+               if (userdata)
                        dev_kfree_skb(userdata);
                return -EISCONN;
        }
@@ -1137,7 +1134,7 @@ int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel,
                 *  headers
                 */
                IRDA_ASSERT(skb_headroom(userdata) >= TTP_MAX_HEADER,
-                       { dev_kfree_skb(userdata); return -1; } );
+                       { dev_kfree_skb(userdata); return -1; });
        }
 
        /* Initialize connection parameters */
@@ -1157,7 +1154,7 @@ int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel,
         *  Give away max 127 credits for now
         */
        if (n > 127) {
-               self->avail_credit=n-127;
+               self->avail_credit = n - 127;
                n = 127;
        }
 
@@ -1166,10 +1163,10 @@ int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel,
        /* SAR enabled? */
        if (max_sdu_size > 0) {
                IRDA_ASSERT(skb_headroom(tx_skb) >= (TTP_MAX_HEADER + TTP_SAR_HEADER),
-                       { dev_kfree_skb(tx_skb); return -1; } );
+                       { dev_kfree_skb(tx_skb); return -1; });
 
                /* Insert SAR parameters */
-               frame = skb_push(tx_skb, TTP_HEADER+TTP_SAR_HEADER);
+               frame = skb_push(tx_skb, TTP_HEADER + TTP_SAR_HEADER);
 
                frame[0] = TTP_PARAMETERS | n;
                frame[1] = 0x04; /* Length */
@@ -1386,7 +1383,7 @@ int irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size,
                 *  headers
                 */
                IRDA_ASSERT(skb_headroom(userdata) >= TTP_MAX_HEADER,
-                       { dev_kfree_skb(userdata); return -1; } );
+                       { dev_kfree_skb(userdata); return -1; });
        }
 
        self->avail_credit = 0;
@@ -1409,10 +1406,10 @@ int irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size,
        /* SAR enabled? */
        if (max_sdu_size > 0) {
                IRDA_ASSERT(skb_headroom(tx_skb) >= (TTP_MAX_HEADER + TTP_SAR_HEADER),
-                       { dev_kfree_skb(tx_skb); return -1; } );
+                       { dev_kfree_skb(tx_skb); return -1; });
 
                /* Insert TTP header with SAR parameters */
-               frame = skb_push(tx_skb, TTP_HEADER+TTP_SAR_HEADER);
+               frame = skb_push(tx_skb, TTP_HEADER + TTP_SAR_HEADER);
 
                frame[0] = TTP_PARAMETERS | n;
                frame[1] = 0x04; /* Length */
@@ -1522,7 +1519,7 @@ int irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *userdata,
         * function may be called from various context, like user, timer
         * for following a disconnect_indication() (i.e. net_bh).
         * Jean II */
-       if(test_and_set_bit(0, &self->disconnect_pend)) {
+       if (test_and_set_bit(0, &self->disconnect_pend)) {
                IRDA_DEBUG(0, "%s(), disconnect already pending\n",
                           __func__);
                if (userdata)
@@ -1627,7 +1624,7 @@ static void irttp_disconnect_indication(void *instance, void *sap,
         * Jean II */
 
        /* No need to notify the client if has already tried to disconnect */
-       if(self->notify.disconnect_indication)
+       if (self->notify.disconnect_indication)
                self->notify.disconnect_indication(self->notify.instance, self,
                                                   reason, skb);
        else
@@ -1738,8 +1735,7 @@ static void irttp_run_rx_queue(struct tsap_cb *self)
                 *  This is the last fragment, so time to reassemble!
                 */
                if ((self->rx_sdu_size <= self->rx_max_sdu_size) ||
-                   (self->rx_max_sdu_size == TTP_SAR_UNBOUND))
-               {
+                   (self->rx_max_sdu_size == TTP_SAR_UNBOUND)) {
                        /*
                         * A little optimizing. Only queue the fragment if
                         * there are other fragments. Since if this is the
@@ -1860,7 +1856,7 @@ static int irttp_seq_show(struct seq_file *seq, void *v)
        seq_printf(seq, "dtsap_sel: %02x\n",
                   self->dtsap_sel);
        seq_printf(seq, "  connected: %s, ",
-                  self->connected? "TRUE":"FALSE");
+                  self->connected ? "TRUE" : "FALSE");
        seq_printf(seq, "avail credit: %d, ",
                   self->avail_credit);
        seq_printf(seq, "remote credit: %d, ",
@@ -1876,9 +1872,9 @@ static int irttp_seq_show(struct seq_file *seq, void *v)
        seq_printf(seq, "rx_queue len: %u\n",
                   skb_queue_len(&self->rx_queue));
        seq_printf(seq, "  tx_sdu_busy: %s, ",
-                  self->tx_sdu_busy? "TRUE":"FALSE");
+                  self->tx_sdu_busy ? "TRUE" : "FALSE");
        seq_printf(seq, "rx_sdu_busy: %s\n",
-                  self->rx_sdu_busy? "TRUE":"FALSE");
+                  self->rx_sdu_busy ? "TRUE" : "FALSE");
        seq_printf(seq, "  max_seg_size: %u, ",
                   self->max_seg_size);
        seq_printf(seq, "tx_max_sdu_size: %u, ",
index 9da862070dd84fe596f77582c82af6eec8ad660c..d49f67681823006a23e6f19cd80867ac5841b38f 100644 (file)
@@ -45,7 +45,7 @@ struct netns_pfkey {
 static DEFINE_MUTEX(pfkey_mutex);
 
 #define DUMMY_MARK 0
-static struct xfrm_mark dummy_mark = {0, 0};
+static const struct xfrm_mark dummy_mark = {0, 0};
 struct pfkey_sock {
        /* struct sock must be the first member of struct pfkey_sock */
        struct sock     sk;
@@ -338,7 +338,7 @@ static int pfkey_error(const struct sadb_msg *orig, int err, struct sock *sk)
        return 0;
 }
 
-static u8 sadb_ext_min_len[] = {
+static const u8 sadb_ext_min_len[] = {
        [SADB_EXT_RESERVED]             = (u8) 0,
        [SADB_EXT_SA]                   = (u8) sizeof(struct sadb_sa),
        [SADB_EXT_LIFETIME_CURRENT]     = (u8) sizeof(struct sadb_lifetime),
@@ -2081,6 +2081,7 @@ static int pfkey_xfrm_policy2msg(struct sk_buff *skb, const struct xfrm_policy *
                        pol->sadb_x_policy_type = IPSEC_POLICY_NONE;
        }
        pol->sadb_x_policy_dir = dir+1;
+       pol->sadb_x_policy_reserved = 0;
        pol->sadb_x_policy_id = xp->index;
        pol->sadb_x_policy_priority = xp->priority;
 
@@ -2736,7 +2737,7 @@ static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, const struct sad
 
 typedef int (*pfkey_handler)(struct sock *sk, struct sk_buff *skb,
                             const struct sadb_msg *hdr, void * const *ext_hdrs);
-static pfkey_handler pfkey_funcs[SADB_MAX + 1] = {
+static const pfkey_handler pfkey_funcs[SADB_MAX + 1] = {
        [SADB_RESERVED]         = pfkey_reserved,
        [SADB_GETSPI]           = pfkey_getspi,
        [SADB_UPDATE]           = pfkey_add,
@@ -3137,7 +3138,9 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct
        pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
        pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC;
        pol->sadb_x_policy_dir = XFRM_POLICY_OUT + 1;
+       pol->sadb_x_policy_reserved = 0;
        pol->sadb_x_policy_id = xp->index;
+       pol->sadb_x_policy_priority = xp->priority;
 
        /* Set sadb_comb's. */
        if (x->id.proto == IPPROTO_AH)
@@ -3525,6 +3528,7 @@ static int pfkey_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
        pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
        pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC;
        pol->sadb_x_policy_dir = dir + 1;
+       pol->sadb_x_policy_reserved = 0;
        pol->sadb_x_policy_id = 0;
        pol->sadb_x_policy_priority = 0;
 
index 8184d121ff0904a285529ff234f75c3f15f522e5..973594b229f400bbae825034d32f69b07c51c9f7 100644 (file)
@@ -395,9 +395,13 @@ void sta_set_rate_info_tx(struct sta_info *sta,
                rinfo->nss = ieee80211_rate_get_vht_nss(rate);
        } else {
                struct ieee80211_supported_band *sband;
+               int shift = ieee80211_vif_get_shift(&sta->sdata->vif);
+               u16 brate;
+
                sband = sta->local->hw.wiphy->bands[
                                ieee80211_get_sdata_band(sta->sdata)];
-               rinfo->legacy = sband->bitrates[rate->idx].bitrate;
+               brate = sband->bitrates[rate->idx].bitrate;
+               rinfo->legacy = DIV_ROUND_UP(brate, 1 << shift);
        }
        if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
                rinfo->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
@@ -422,11 +426,13 @@ void sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo)
                rinfo->mcs = sta->last_rx_rate_idx;
        } else {
                struct ieee80211_supported_band *sband;
+               int shift = ieee80211_vif_get_shift(&sta->sdata->vif);
+               u16 brate;
 
                sband = sta->local->hw.wiphy->bands[
                                ieee80211_get_sdata_band(sta->sdata)];
-               rinfo->legacy =
-                       sband->bitrates[sta->last_rx_rate_idx].bitrate;
+               brate = sband->bitrates[sta->last_rx_rate_idx].bitrate;
+               rinfo->legacy = DIV_ROUND_UP(brate, 1 << shift);
        }
 
        if (sta->last_rx_rate_flag & RX_FLAG_40MHZ)
@@ -666,6 +672,8 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy,
                        if (sta->sdata->dev != dev)
                                continue;
 
+                       sinfo.filled = 0;
+                       sta_set_sinfo(sta, &sinfo);
                        i = 0;
                        ADD_STA_STATS(sta);
                }
@@ -1190,8 +1198,6 @@ static int sta_apply_parameters(struct ieee80211_local *local,
                                struct station_parameters *params)
 {
        int ret = 0;
-       u32 rates;
-       int i, j;
        struct ieee80211_supported_band *sband;
        struct ieee80211_sub_if_data *sdata = sta->sdata;
        enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
@@ -1284,16 +1290,10 @@ static int sta_apply_parameters(struct ieee80211_local *local,
                sta->listen_interval = params->listen_interval;
 
        if (params->supported_rates) {
-               rates = 0;
-
-               for (i = 0; i < params->supported_rates_len; i++) {
-                       int rate = (params->supported_rates[i] & 0x7f) * 5;
-                       for (j = 0; j < sband->n_bitrates; j++) {
-                               if (sband->bitrates[j].bitrate == rate)
-                                       rates |= BIT(j);
-                       }
-               }
-               sta->sta.supp_rates[band] = rates;
+               ieee80211_parse_bitrates(&sdata->vif.bss_conf.chandef,
+                                        sband, params->supported_rates,
+                                        params->supported_rates_len,
+                                        &sta->sta.supp_rates[band]);
        }
 
        if (params->ht_capa)
@@ -1956,18 +1956,11 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
        }
 
        if (params->basic_rates) {
-               int i, j;
-               u32 rates = 0;
-               struct ieee80211_supported_band *sband = wiphy->bands[band];
-
-               for (i = 0; i < params->basic_rates_len; i++) {
-                       int rate = (params->basic_rates[i] & 0x7f) * 5;
-                       for (j = 0; j < sband->n_bitrates; j++) {
-                               if (sband->bitrates[j].bitrate == rate)
-                                       rates |= BIT(j);
-                       }
-               }
-               sdata->vif.bss_conf.basic_rates = rates;
+               ieee80211_parse_bitrates(&sdata->vif.bss_conf.chandef,
+                                        wiphy->bands[band],
+                                        params->basic_rates,
+                                        params->basic_rates_len,
+                                        &sdata->vif.bss_conf.basic_rates);
                changed |= BSS_CHANGED_BASIC_RATES;
        }
 
index f83534f6a2eec14abcb237196e4d6a233e2f8136..529bf58bc14511beae95c4ff250ec54eff5c9710 100644 (file)
 #include "ieee80211_i.h"
 #include "rate.h"
 
-static void __check_htcap_disable(struct ieee80211_sub_if_data *sdata,
+static void __check_htcap_disable(struct ieee80211_ht_cap *ht_capa,
+                                 struct ieee80211_ht_cap *ht_capa_mask,
                                  struct ieee80211_sta_ht_cap *ht_cap,
                                  u16 flag)
 {
        __le16 le_flag = cpu_to_le16(flag);
-       if (sdata->u.mgd.ht_capa_mask.cap_info & le_flag) {
-               if (!(sdata->u.mgd.ht_capa.cap_info & le_flag))
+       if (ht_capa_mask->cap_info & le_flag) {
+               if (!(ht_capa->cap_info & le_flag))
                        ht_cap->cap &= ~flag;
        }
 }
@@ -33,13 +34,30 @@ static void __check_htcap_disable(struct ieee80211_sub_if_data *sdata,
 void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
                                     struct ieee80211_sta_ht_cap *ht_cap)
 {
-       u8 *scaps = (u8 *)(&sdata->u.mgd.ht_capa.mcs.rx_mask);
-       u8 *smask = (u8 *)(&sdata->u.mgd.ht_capa_mask.mcs.rx_mask);
+       struct ieee80211_ht_cap *ht_capa, *ht_capa_mask;
+       u8 *scaps, *smask;
        int i;
 
        if (!ht_cap->ht_supported)
                return;
 
+       switch (sdata->vif.type) {
+       case NL80211_IFTYPE_STATION:
+               ht_capa = &sdata->u.mgd.ht_capa;
+               ht_capa_mask = &sdata->u.mgd.ht_capa_mask;
+               break;
+       case NL80211_IFTYPE_ADHOC:
+               ht_capa = &sdata->u.ibss.ht_capa;
+               ht_capa_mask = &sdata->u.ibss.ht_capa_mask;
+               break;
+       default:
+               WARN_ON_ONCE(1);
+               return;
+       }
+
+       scaps = (u8 *)(&ht_capa->mcs.rx_mask);
+       smask = (u8 *)(&ht_capa_mask->mcs.rx_mask);
+
        /* NOTE:  If you add more over-rides here, update register_hw
         * ht_capa_mod_msk logic in main.c as well.
         * And, if this method can ever change ht_cap.ht_supported, fix
@@ -55,28 +73,32 @@ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
        }
 
        /* Force removal of HT-40 capabilities? */
-       __check_htcap_disable(sdata, ht_cap, IEEE80211_HT_CAP_SUP_WIDTH_20_40);
-       __check_htcap_disable(sdata, ht_cap, IEEE80211_HT_CAP_SGI_40);
+       __check_htcap_disable(ht_capa, ht_capa_mask, ht_cap,
+                             IEEE80211_HT_CAP_SUP_WIDTH_20_40);
+       __check_htcap_disable(ht_capa, ht_capa_mask, ht_cap,
+                             IEEE80211_HT_CAP_SGI_40);
 
        /* Allow user to disable SGI-20 (SGI-40 is handled above) */
-       __check_htcap_disable(sdata, ht_cap, IEEE80211_HT_CAP_SGI_20);
+       __check_htcap_disable(ht_capa, ht_capa_mask, ht_cap,
+                             IEEE80211_HT_CAP_SGI_20);
 
        /* Allow user to disable the max-AMSDU bit. */
-       __check_htcap_disable(sdata, ht_cap, IEEE80211_HT_CAP_MAX_AMSDU);
+       __check_htcap_disable(ht_capa, ht_capa_mask, ht_cap,
+                             IEEE80211_HT_CAP_MAX_AMSDU);
 
        /* Allow user to decrease AMPDU factor */
-       if (sdata->u.mgd.ht_capa_mask.ampdu_params_info &
+       if (ht_capa_mask->ampdu_params_info &
            IEEE80211_HT_AMPDU_PARM_FACTOR) {
-               u8 n = sdata->u.mgd.ht_capa.ampdu_params_info
-                       & IEEE80211_HT_AMPDU_PARM_FACTOR;
+               u8 n = ht_capa->ampdu_params_info &
+                      IEEE80211_HT_AMPDU_PARM_FACTOR;
                if (n < ht_cap->ampdu_factor)
                        ht_cap->ampdu_factor = n;
        }
 
        /* Allow the user to increase AMPDU density. */
-       if (sdata->u.mgd.ht_capa_mask.ampdu_params_info &
+       if (ht_capa_mask->ampdu_params_info &
            IEEE80211_HT_AMPDU_PARM_DENSITY) {
-               u8 n = (sdata->u.mgd.ht_capa.ampdu_params_info &
+               u8 n = (ht_capa->ampdu_params_info &
                        IEEE80211_HT_AMPDU_PARM_DENSITY)
                        >> IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT;
                if (n > ht_cap->ampdu_density)
@@ -112,7 +134,8 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
         * we advertised a restricted capability set to. Override
         * our own capabilities and then use those below.
         */
-       if (sdata->vif.type == NL80211_IFTYPE_STATION &&
+       if ((sdata->vif.type == NL80211_IFTYPE_STATION ||
+            sdata->vif.type == NL80211_IFTYPE_ADHOC) &&
            !test_sta_flag(sta, WLAN_STA_TDLS_PEER))
                ieee80211_apply_htcap_overrides(sdata, &own_cap);
 
index ea7b9c2c7e66db19a811244d82e907bdb79620f1..5e6836c3aa4c108a6e1c6fe2430a95d0ec5faba0 100644 (file)
@@ -43,16 +43,18 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 {
        struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
        struct ieee80211_local *local = sdata->local;
-       int ratesi;
+       int rates_n = 0, i, ri;
        struct ieee80211_mgmt *mgmt;
        u8 *pos;
        struct ieee80211_supported_band *sband;
        struct cfg80211_bss *bss;
-       u32 bss_change;
-       u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
+       u32 bss_change, rate_flags, rates = 0, rates_added = 0;
        struct cfg80211_chan_def chandef;
+       enum nl80211_bss_scan_width scan_width;
+       bool have_higher_than_11mbit = false;
        struct beacon_data *presp;
        int frame_len;
+       int shift;
 
        sdata_assert_lock(sdata);
 
@@ -83,6 +85,14 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 
        chandef = ifibss->chandef;
        if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) {
+               if (chandef.width == NL80211_CHAN_WIDTH_5 ||
+                   chandef.width == NL80211_CHAN_WIDTH_10 ||
+                   chandef.width == NL80211_CHAN_WIDTH_20_NOHT ||
+                   chandef.width == NL80211_CHAN_WIDTH_20) {
+                       sdata_info(sdata,
+                                  "Failed to join IBSS, beacons forbidden\n");
+                       return;
+               }
                chandef.width = NL80211_CHAN_WIDTH_20;
                chandef.center_freq1 = chan->center_freq;
        }
@@ -99,6 +109,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
        memcpy(ifibss->bssid, bssid, ETH_ALEN);
 
        sband = local->hw.wiphy->bands[chan->band];
+       shift = ieee80211_vif_get_shift(&sdata->vif);
 
        /* Build IBSS probe response */
        frame_len = sizeof(struct ieee80211_hdr_3addr) +
@@ -134,15 +145,33 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
        memcpy(pos, ifibss->ssid, ifibss->ssid_len);
        pos += ifibss->ssid_len;
 
-       rates = min_t(int, 8, sband->n_bitrates);
+       rate_flags = ieee80211_chandef_rate_flags(&chandef);
+       for (i = 0; i < sband->n_bitrates; i++) {
+               if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
+                       continue;
+               if (sband->bitrates[i].bitrate > 110)
+                       have_higher_than_11mbit = true;
+
+               rates |= BIT(i);
+               rates_n++;
+       }
+
        *pos++ = WLAN_EID_SUPP_RATES;
-       *pos++ = rates;
-       for (i = 0; i < rates; i++) {
-               int rate = sband->bitrates[i].bitrate;
+       *pos++ = min_t(int, 8, rates_n);
+       for (ri = 0; ri < sband->n_bitrates; ri++) {
+               int rate = DIV_ROUND_UP(sband->bitrates[ri].bitrate,
+                                       5 * (1 << shift));
                u8 basic = 0;
-               if (basic_rates & BIT(i))
+               if (!(rates & BIT(ri)))
+                       continue;
+
+               if (basic_rates & BIT(ri))
                        basic = 0x80;
-               *pos++ = basic | (u8) (rate / 5);
+               *pos++ = basic | (u8) rate;
+               if (++rates_added == 8) {
+                       ri++; /* continue at next rate for EXT_SUPP_RATES */
+                       break;
+               }
        }
 
        if (sband->band == IEEE80211_BAND_2GHZ) {
@@ -157,15 +186,20 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
        *pos++ = 0;
        *pos++ = 0;
 
-       if (sband->n_bitrates > 8) {
+       /* put the remaining rates in WLAN_EID_EXT_SUPP_RATES */
+       if (rates_n > 8) {
                *pos++ = WLAN_EID_EXT_SUPP_RATES;
-               *pos++ = sband->n_bitrates - 8;
-               for (i = 8; i < sband->n_bitrates; i++) {
-                       int rate = sband->bitrates[i].bitrate;
+               *pos++ = rates_n - 8;
+               for (; ri < sband->n_bitrates; ri++) {
+                       int rate = DIV_ROUND_UP(sband->bitrates[ri].bitrate,
+                                               5 * (1 << shift));
                        u8 basic = 0;
-                       if (basic_rates & BIT(i))
+                       if (!(rates & BIT(ri)))
+                               continue;
+
+                       if (basic_rates & BIT(ri))
                                basic = 0x80;
-                       *pos++ = basic | (u8) (rate / 5);
+                       *pos++ = basic | (u8) rate;
                }
        }
 
@@ -179,8 +213,12 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
            chandef.width != NL80211_CHAN_WIDTH_5 &&
            chandef.width != NL80211_CHAN_WIDTH_10 &&
            sband->ht_cap.ht_supported) {
-               pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap,
-                                               sband->ht_cap.cap);
+               struct ieee80211_sta_ht_cap ht_cap;
+
+               memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap));
+               ieee80211_apply_htcap_overrides(sdata, &ht_cap);
+
+               pos = ieee80211_ie_build_ht_cap(pos, &ht_cap, ht_cap.cap);
                /*
                 * Note: According to 802.11n-2009 9.13.3.1, HT Protection
                 * field and RIFS Mode are reserved in IBSS mode, therefore
@@ -236,18 +274,26 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
        sdata->vif.bss_conf.use_short_slot = chan->band == IEEE80211_BAND_5GHZ;
        bss_change |= BSS_CHANGED_ERP_SLOT;
 
+       /* cf. IEEE 802.11 9.2.12 */
+       if (chan->band == IEEE80211_BAND_2GHZ && have_higher_than_11mbit)
+               sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
+       else
+               sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
+
        sdata->vif.bss_conf.ibss_joined = true;
        sdata->vif.bss_conf.ibss_creator = creator;
        ieee80211_bss_info_change_notify(sdata, bss_change);
 
-       ieee80211_sta_def_wmm_params(sdata, sband->n_bitrates, supp_rates);
+       ieee80211_set_wmm_default(sdata, true);
 
        ifibss->state = IEEE80211_IBSS_MLME_JOINED;
        mod_timer(&ifibss->timer,
                  round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL));
 
-       bss = cfg80211_inform_bss_frame(local->hw.wiphy, chan,
-                                       mgmt, presp->head_len, 0, GFP_KERNEL);
+       scan_width = cfg80211_chandef_to_scan_width(&chandef);
+       bss = cfg80211_inform_bss_width_frame(local->hw.wiphy, chan,
+                                             scan_width, mgmt,
+                                             presp->head_len, 0, GFP_KERNEL);
        cfg80211_put_bss(local->hw.wiphy, bss);
        netif_carrier_on(sdata->dev);
        cfg80211_ibss_joined(sdata->dev, ifibss->bssid, GFP_KERNEL);
@@ -264,6 +310,8 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
        u16 beacon_int = cbss->beacon_interval;
        const struct cfg80211_bss_ies *ies;
        u64 tsf;
+       u32 rate_flags;
+       int shift;
 
        sdata_assert_lock(sdata);
 
@@ -271,15 +319,24 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
                beacon_int = 10;
 
        sband = sdata->local->hw.wiphy->bands[cbss->channel->band];
+       rate_flags = ieee80211_chandef_rate_flags(&sdata->u.ibss.chandef);
+       shift = ieee80211_vif_get_shift(&sdata->vif);
 
        basic_rates = 0;
 
        for (i = 0; i < bss->supp_rates_len; i++) {
-               int rate = (bss->supp_rates[i] & 0x7f) * 5;
+               int rate = bss->supp_rates[i] & 0x7f;
                bool is_basic = !!(bss->supp_rates[i] & 0x80);
 
                for (j = 0; j < sband->n_bitrates; j++) {
-                       if (sband->bitrates[j].bitrate == rate) {
+                       int brate;
+                       if ((rate_flags & sband->bitrates[j].flags)
+                           != rate_flags)
+                               continue;
+
+                       brate = DIV_ROUND_UP(sband->bitrates[j].bitrate,
+                                            5 * (1 << shift));
+                       if (brate == rate) {
                                if (is_basic)
                                        basic_rates |= BIT(j);
                                break;
@@ -335,6 +392,7 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, const u8 *bssid,
        struct sta_info *sta;
        struct ieee80211_chanctx_conf *chanctx_conf;
        struct ieee80211_supported_band *sband;
+       enum nl80211_bss_scan_width scan_width;
        int band;
 
        /*
@@ -363,6 +421,7 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, const u8 *bssid,
        if (WARN_ON_ONCE(!chanctx_conf))
                return NULL;
        band = chanctx_conf->def.chan->band;
+       scan_width = cfg80211_chandef_to_scan_width(&chanctx_conf->def);
        rcu_read_unlock();
 
        sta = sta_info_alloc(sdata, addr, GFP_KERNEL);
@@ -376,7 +435,7 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, const u8 *bssid,
        /* make sure mandatory rates are always added */
        sband = local->hw.wiphy->bands[band];
        sta->sta.supp_rates[band] = supp_rates |
-                       ieee80211_mandatory_rates(sband);
+                       ieee80211_mandatory_rates(sband, scan_width);
 
        return ieee80211_ibss_finish_sta(sta);
 }
@@ -440,6 +499,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
        u64 beacon_timestamp, rx_timestamp;
        u32 supp_rates = 0;
        enum ieee80211_band band = rx_status->band;
+       enum nl80211_bss_scan_width scan_width;
        struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
        bool rates_updated = false;
 
@@ -461,16 +521,22 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                sta = sta_info_get(sdata, mgmt->sa);
 
                if (elems->supp_rates) {
-                       supp_rates = ieee80211_sta_get_rates(local, elems,
+                       supp_rates = ieee80211_sta_get_rates(sdata, elems,
                                                             band, NULL);
                        if (sta) {
                                u32 prev_rates;
 
                                prev_rates = sta->sta.supp_rates[band];
                                /* make sure mandatory rates are always added */
-                               sta->sta.supp_rates[band] = supp_rates |
-                                       ieee80211_mandatory_rates(sband);
+                               scan_width = NL80211_BSS_CHAN_WIDTH_20;
+                               if (rx_status->flag & RX_FLAG_5MHZ)
+                                       scan_width = NL80211_BSS_CHAN_WIDTH_5;
+                               if (rx_status->flag & RX_FLAG_10MHZ)
+                                       scan_width = NL80211_BSS_CHAN_WIDTH_10;
 
+                               sta->sta.supp_rates[band] = supp_rates |
+                                       ieee80211_mandatory_rates(sband,
+                                                                 scan_width);
                                if (sta->sta.supp_rates[band] != prev_rates) {
                                        ibss_dbg(sdata,
                                                 "updated supp_rates set for %pM based on beacon/probe_resp (0x%x -> 0x%x)\n",
@@ -585,7 +651,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                         "beacon TSF higher than local TSF - IBSS merge with BSSID %pM\n",
                         mgmt->bssid);
                ieee80211_sta_join_ibss(sdata, bss);
-               supp_rates = ieee80211_sta_get_rates(local, elems, band, NULL);
+               supp_rates = ieee80211_sta_get_rates(sdata, elems, band, NULL);
                ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa,
                                       supp_rates);
                rcu_read_unlock();
@@ -604,6 +670,7 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata,
        struct sta_info *sta;
        struct ieee80211_chanctx_conf *chanctx_conf;
        struct ieee80211_supported_band *sband;
+       enum nl80211_bss_scan_width scan_width;
        int band;
 
        /*
@@ -629,6 +696,7 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata,
                return;
        }
        band = chanctx_conf->def.chan->band;
+       scan_width = cfg80211_chandef_to_scan_width(&chanctx_conf->def);
        rcu_read_unlock();
 
        sta = sta_info_alloc(sdata, addr, GFP_ATOMIC);
@@ -640,7 +708,7 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata,
        /* make sure mandatory rates are always added */
        sband = local->hw.wiphy->bands[band];
        sta->sta.supp_rates[band] = supp_rates |
-                       ieee80211_mandatory_rates(sband);
+                       ieee80211_mandatory_rates(sband, scan_width);
 
        spin_lock(&ifibss->incomplete_lock);
        list_add(&sta->list, &ifibss->incomplete_stations);
@@ -679,6 +747,7 @@ static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata)
 static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+       enum nl80211_bss_scan_width scan_width;
 
        sdata_assert_lock(sdata);
 
@@ -700,8 +769,9 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata)
        sdata_info(sdata,
                   "No active IBSS STAs - trying to scan for other IBSS networks with same SSID (merge)\n");
 
+       scan_width = cfg80211_chandef_to_scan_width(&ifibss->chandef);
        ieee80211_request_ibss_scan(sdata, ifibss->ssid, ifibss->ssid_len,
-                                   NULL);
+                                   NULL, scan_width);
 }
 
 static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
@@ -751,6 +821,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
        struct cfg80211_bss *cbss;
        struct ieee80211_channel *chan = NULL;
        const u8 *bssid = NULL;
+       enum nl80211_bss_scan_width scan_width;
        int active_ibss;
        u16 capability;
 
@@ -799,8 +870,10 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
                                        IEEE80211_SCAN_INTERVAL)) {
                sdata_info(sdata, "Trigger new scan to find an IBSS to join\n");
 
+               scan_width = cfg80211_chandef_to_scan_width(&ifibss->chandef);
                ieee80211_request_ibss_scan(sdata, ifibss->ssid,
-                                           ifibss->ssid_len, chan);
+                                           ifibss->ssid_len, chan,
+                                           scan_width);
        } else {
                int interval = IEEE80211_SCAN_INTERVAL;
 
@@ -1020,6 +1093,9 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
                        struct cfg80211_ibss_params *params)
 {
        u32 changed = 0;
+       u32 rate_flags;
+       struct ieee80211_supported_band *sband;
+       int i;
 
        if (params->bssid) {
                memcpy(sdata->u.ibss.bssid, params->bssid, ETH_ALEN);
@@ -1030,6 +1106,14 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
        sdata->u.ibss.privacy = params->privacy;
        sdata->u.ibss.control_port = params->control_port;
        sdata->u.ibss.basic_rates = params->basic_rates;
+
+       /* fix basic_rates if channel does not support these rates */
+       rate_flags = ieee80211_chandef_rate_flags(&params->chandef);
+       sband = sdata->local->hw.wiphy->bands[params->chandef.chan->band];
+       for (i = 0; i < sband->n_bitrates; i++) {
+               if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
+                       sdata->u.ibss.basic_rates &= ~BIT(i);
+       }
        memcpy(sdata->vif.bss_conf.mcast_rate, params->mcast_rate,
               sizeof(params->mcast_rate));
 
@@ -1051,6 +1135,11 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
        memcpy(sdata->u.ibss.ssid, params->ssid, params->ssid_len);
        sdata->u.ibss.ssid_len = params->ssid_len;
 
+       memcpy(&sdata->u.ibss.ht_capa, &params->ht_capa,
+              sizeof(sdata->u.ibss.ht_capa));
+       memcpy(&sdata->u.ibss.ht_capa_mask, &params->ht_capa_mask,
+              sizeof(sdata->u.ibss.ht_capa_mask));
+
        /*
         * 802.11n-2009 9.13.3.1: In an IBSS, the HT Protection field is
         * reserved, but an HT STA shall protect HT transmissions as though
@@ -1131,6 +1220,11 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
        presp = rcu_dereference_protected(ifibss->presp,
                                          lockdep_is_held(&sdata->wdev.mtx));
        RCU_INIT_POINTER(sdata->u.ibss.presp, NULL);
+
+       /* on the next join, re-program HT parameters */
+       memset(&ifibss->ht_capa, 0, sizeof(ifibss->ht_capa));
+       memset(&ifibss->ht_capa_mask, 0, sizeof(ifibss->ht_capa_mask));
+
        sdata->vif.bss_conf.ibss_joined = false;
        sdata->vif.bss_conf.ibss_creator = false;
        sdata->vif.bss_conf.enable_beacon = false;
index 8412a303993a647eed61e6b0794e91e49b27dd29..3d32df1fbc6de92a5eb1e02ba532ba39b5533573 100644 (file)
@@ -509,6 +509,9 @@ struct ieee80211_if_ibss {
        /* probe response/beacon for IBSS */
        struct beacon_data __rcu *presp;
 
+       struct ieee80211_ht_cap ht_capa; /* configured ht-cap over-rides */
+       struct ieee80211_ht_cap ht_capa_mask; /* Valid parts of ht_capa */
+
        spinlock_t incomplete_lock;
        struct list_head incomplete_stations;
 
@@ -809,6 +812,34 @@ ieee80211_get_sdata_band(struct ieee80211_sub_if_data *sdata)
        return band;
 }
 
+static inline int
+ieee80211_chandef_get_shift(struct cfg80211_chan_def *chandef)
+{
+       switch (chandef->width) {
+       case NL80211_CHAN_WIDTH_5:
+               return 2;
+       case NL80211_CHAN_WIDTH_10:
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+static inline int
+ieee80211_vif_get_shift(struct ieee80211_vif *vif)
+{
+       struct ieee80211_chanctx_conf *chanctx_conf;
+       int shift = 0;
+
+       rcu_read_lock();
+       chanctx_conf = rcu_dereference(vif->chanctx_conf);
+       if (chanctx_conf)
+               shift = ieee80211_chandef_get_shift(&chanctx_conf->def);
+       rcu_read_unlock();
+
+       return shift;
+}
+
 enum sdata_queue_type {
        IEEE80211_SDATA_QUEUE_TYPE_FRAME        = 0,
        IEEE80211_SDATA_QUEUE_AGG_START         = 1,
@@ -1026,7 +1057,7 @@ struct ieee80211_local {
        struct cfg80211_ssid scan_ssid;
        struct cfg80211_scan_request *int_scan_req;
        struct cfg80211_scan_request *scan_req, *hw_scan_req;
-       struct ieee80211_channel *scan_channel;
+       struct cfg80211_chan_def scan_chandef;
        enum ieee80211_band hw_scan_band;
        int scan_channel_idx;
        int scan_ies_len;
@@ -1306,7 +1337,8 @@ void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
 void ieee80211_scan_work(struct work_struct *work);
 int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata,
                                const u8 *ssid, u8 ssid_len,
-                               struct ieee80211_channel *chan);
+                               struct ieee80211_channel *chan,
+                               enum nl80211_bss_scan_width scan_width);
 int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
                           struct cfg80211_scan_request *req);
 void ieee80211_scan_cancel(struct ieee80211_local *local);
@@ -1465,7 +1497,8 @@ extern void *mac80211_wiphy_privid; /* for wiphy privid */
 u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
                        enum nl80211_iftype type);
 int ieee80211_frame_duration(enum ieee80211_band band, size_t len,
-                            int rate, int erp, int short_preamble);
+                            int rate, int erp, int short_preamble,
+                            int shift);
 void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int keyidx,
                                     struct ieee80211_hdr *hdr, const u8 *tsc,
                                     gfp_t gfp);
@@ -1569,7 +1602,7 @@ void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
 int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
                             size_t buffer_len, const u8 *ie, size_t ie_len,
                             enum ieee80211_band band, u32 rate_mask,
-                            u8 channel);
+                            struct cfg80211_chan_def *chandef);
 struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
                                          u8 *dst, u32 ratemask,
                                          struct ieee80211_channel *chan,
@@ -1582,10 +1615,7 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
                              u32 ratemask, bool directed, u32 tx_flags,
                              struct ieee80211_channel *channel, bool scan);
 
-void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
-                                 const size_t supp_rates_len,
-                                 const u8 *supp_rates);
-u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
+u32 ieee80211_sta_get_rates(struct ieee80211_sub_if_data *sdata,
                            struct ieee802_11_elems *elems,
                            enum ieee80211_band band, u32 *basic_rates);
 int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
@@ -1602,6 +1632,9 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
                               u16 prot_mode);
 u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
                               u32 cap);
+int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef,
+                            const struct ieee80211_supported_band *sband,
+                            const u8 *srates, int srates_len, u32 *rates);
 int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata,
                            struct sk_buff *skb, bool need_basic,
                            enum ieee80211_band band);
index cc117591f678463c2cd9a3eb4060af5e01bf51ca..4c41c11958c8a9de28fcae05465f44bc6712ca45 100644 (file)
@@ -54,7 +54,7 @@ bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata)
                return false;
        }
 
-       power = chanctx_conf->def.chan->max_power;
+       power = ieee80211_chandef_max_power(&chanctx_conf->def);
        rcu_read_unlock();
 
        if (sdata->user_power_level != IEEE80211_UNSET_POWER_LEVEL)
index 091088ac7890a9c7f873f623f7789cffb9e12def..25eb35b01938e9e91d5dfd75adcee8acb030036c 100644 (file)
@@ -102,17 +102,8 @@ static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local)
 
        offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL;
 
-       if (local->scan_channel) {
-               chandef.chan = local->scan_channel;
-               /* If scanning on oper channel, use whatever channel-type
-                * is currently in use.
-                */
-               if (chandef.chan == local->_oper_chandef.chan) {
-                       chandef = local->_oper_chandef;
-               } else {
-                       chandef.width = NL80211_CHAN_WIDTH_20_NOHT;
-                       chandef.center_freq1 = chandef.chan->center_freq;
-               }
+       if (local->scan_chandef.chan) {
+               chandef = local->scan_chandef;
        } else if (local->tmp_channel) {
                chandef.chan = local->tmp_channel;
                chandef.width = NL80211_CHAN_WIDTH_20_NOHT;
@@ -151,7 +142,7 @@ static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local)
                changed |= IEEE80211_CONF_CHANGE_SMPS;
        }
 
-       power = chandef.chan->max_power;
+       power = ieee80211_chandef_max_power(&chandef);
 
        rcu_read_lock();
        list_for_each_entry_rcu(sdata, &local->interfaces, list) {
index 447f41bbe744d79b570eb4c85dd4cdb8ffb72e70..885a5f6e2c219b5c4e17b6574bd32e4231ed39b1 100644 (file)
@@ -62,7 +62,6 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
                        struct ieee802_11_elems *ie)
 {
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
-       struct ieee80211_local *local = sdata->local;
        u32 basic_rates = 0;
        struct cfg80211_chan_def sta_chan_def;
 
@@ -85,7 +84,7 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
             (ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth)))
                return false;
 
-       ieee80211_sta_get_rates(local, ie, ieee80211_get_sdata_band(sdata),
+       ieee80211_sta_get_rates(sdata, ie, ieee80211_get_sdata_band(sdata),
                                &basic_rates);
 
        if (sdata->vif.bss_conf.basic_rates != basic_rates)
@@ -274,7 +273,9 @@ int mesh_add_meshconf_ie(struct ieee80211_sub_if_data *sdata,
        neighbors = min_t(int, neighbors, IEEE80211_MAX_MESH_PEERINGS);
        *pos++ = neighbors << 1;
        /* Mesh capability */
-       *pos = IEEE80211_MESHCONF_CAPAB_FORWARDING;
+       *pos = 0x00;
+       *pos |= ifmsh->mshcfg.dot11MeshForwarding ?
+                       IEEE80211_MESHCONF_CAPAB_FORWARDING : 0x00;
        *pos |= ifmsh->accepting_plinks ?
                        IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
        /* Mesh PS mode. See IEEE802.11-2012 8.4.2.100.8 */
index 02c05fa15c203b9a51dc576579f7455979fe0376..6b65d5055f5bf7572d29712c6345c88dd11b33a5 100644 (file)
@@ -379,7 +379,7 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata,
        u32 rates, basic_rates = 0, changed = 0;
 
        sband = local->hw.wiphy->bands[band];
-       rates = ieee80211_sta_get_rates(local, elems, band, &basic_rates);
+       rates = ieee80211_sta_get_rates(sdata, elems, band, &basic_rates);
 
        spin_lock_bh(&sta->lock);
        sta->last_rx = jiffies;
index 3b7bfc01ee36e922927958be79e1ec7414c8a3d6..22290a929b94595445865baecdb692aff5e0be9c 100644 (file)
@@ -229,6 +229,10 @@ void ieee80211_mps_sta_status_update(struct sta_info *sta)
        enum nl80211_mesh_power_mode pm;
        bool do_buffer;
 
+       /* For non-assoc STA, prevent buffering or frame transmission */
+       if (sta->sta_state < IEEE80211_STA_ASSOC)
+               return;
+
        /*
         * use peer-specific power mode if peering is established and the
         * peer's power mode is known
index ae31968d42d3b855eebe05dcf0e660b4d367ff8f..211246b4681927d74967ee9234076e436c9e7f8b 100644 (file)
@@ -478,27 +478,6 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
 
 /* frame sending functions */
 
-static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len,
-                                     struct ieee80211_supported_band *sband,
-                                     u32 *rates)
-{
-       int i, j, count;
-       *rates = 0;
-       count = 0;
-       for (i = 0; i < supp_rates_len; i++) {
-               int rate = (supp_rates[i] & 0x7F) * 5;
-
-               for (j = 0; j < sband->n_bitrates; j++)
-                       if (sband->bitrates[j].bitrate == rate) {
-                               *rates |= BIT(j);
-                               count++;
-                               break;
-                       }
-       }
-
-       return count;
-}
-
 static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata,
                                struct sk_buff *skb, u8 ap_ht_param,
                                struct ieee80211_supported_band *sband,
@@ -617,12 +596,12 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
        struct ieee80211_mgmt *mgmt;
        u8 *pos, qos_info;
        size_t offset = 0, noffset;
-       int i, count, rates_len, supp_rates_len;
+       int i, count, rates_len, supp_rates_len, shift;
        u16 capab;
        struct ieee80211_supported_band *sband;
        struct ieee80211_chanctx_conf *chanctx_conf;
        struct ieee80211_channel *chan;
-       u32 rates = 0;
+       u32 rate_flags, rates = 0;
 
        sdata_assert_lock(sdata);
 
@@ -633,8 +612,10 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
                return;
        }
        chan = chanctx_conf->def.chan;
+       rate_flags = ieee80211_chandef_rate_flags(&chanctx_conf->def);
        rcu_read_unlock();
        sband = local->hw.wiphy->bands[chan->band];
+       shift = ieee80211_vif_get_shift(&sdata->vif);
 
        if (assoc_data->supp_rates_len) {
                /*
@@ -643,17 +624,24 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
                 * in the association request (e.g. D-Link DAP 1353 in
                 * b-only mode)...
                 */
-               rates_len = ieee80211_compatible_rates(assoc_data->supp_rates,
-                                                      assoc_data->supp_rates_len,
-                                                      sband, &rates);
+               rates_len = ieee80211_parse_bitrates(&chanctx_conf->def, sband,
+                                                    assoc_data->supp_rates,
+                                                    assoc_data->supp_rates_len,
+                                                    &rates);
        } else {
                /*
                 * In case AP not provide any supported rates information
                 * before association, we send information element(s) with
                 * all rates that we support.
                 */
-               rates = ~0;
-               rates_len = sband->n_bitrates;
+               rates_len = 0;
+               for (i = 0; i < sband->n_bitrates; i++) {
+                       if ((rate_flags & sband->bitrates[i].flags)
+                           != rate_flags)
+                               continue;
+                       rates |= BIT(i);
+                       rates_len++;
+               }
        }
 
        skb = alloc_skb(local->hw.extra_tx_headroom +
@@ -730,8 +718,9 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
        count = 0;
        for (i = 0; i < sband->n_bitrates; i++) {
                if (BIT(i) & rates) {
-                       int rate = sband->bitrates[i].bitrate;
-                       *pos++ = (u8) (rate / 5);
+                       int rate = DIV_ROUND_UP(sband->bitrates[i].bitrate,
+                                               5 * (1 << shift));
+                       *pos++ = (u8) rate;
                        if (++count == 8)
                                break;
                }
@@ -744,8 +733,10 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
 
                for (i++; i < sband->n_bitrates; i++) {
                        if (BIT(i) & rates) {
-                               int rate = sband->bitrates[i].bitrate;
-                               *pos++ = (u8) (rate / 5);
+                               int rate;
+                               rate = DIV_ROUND_UP(sband->bitrates[i].bitrate,
+                                                   5 * (1 << shift));
+                               *pos++ = (u8) rate;
                        }
                }
        }
@@ -756,7 +747,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
                *pos++ = WLAN_EID_PWR_CAPABILITY;
                *pos++ = 2;
                *pos++ = 0; /* min tx power */
-               *pos++ = chan->max_power; /* max tx power */
+                /* max tx power */
+               *pos++ = ieee80211_chandef_max_power(&chanctx_conf->def);
 
                /* 2. supported channels */
                /* TODO: get this in reg domain format */
@@ -2432,15 +2424,16 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
                                u8 *supp_rates, unsigned int supp_rates_len,
                                u32 *rates, u32 *basic_rates,
                                bool *have_higher_than_11mbit,
-                               int *min_rate, int *min_rate_index)
+                               int *min_rate, int *min_rate_index,
+                               int shift, u32 rate_flags)
 {
        int i, j;
 
        for (i = 0; i < supp_rates_len; i++) {
-               int rate = (supp_rates[i] & 0x7f) * 5;
+               int rate = supp_rates[i] & 0x7f;
                bool is_basic = !!(supp_rates[i] & 0x80);
 
-               if (rate > 110)
+               if ((rate * 5 * (1 << shift)) > 110)
                        *have_higher_than_11mbit = true;
 
                /*
@@ -2456,12 +2449,20 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
                        continue;
 
                for (j = 0; j < sband->n_bitrates; j++) {
-                       if (sband->bitrates[j].bitrate == rate) {
+                       struct ieee80211_rate *br;
+                       int brate;
+
+                       br = &sband->bitrates[j];
+                       if ((rate_flags & br->flags) != rate_flags)
+                               continue;
+
+                       brate = DIV_ROUND_UP(br->bitrate, (1 << shift) * 5);
+                       if (brate == rate) {
                                *rates |= BIT(j);
                                if (is_basic)
                                        *basic_rates |= BIT(j);
-                               if (rate < *min_rate) {
-                                       *min_rate = rate;
+                               if ((rate * 5) < *min_rate) {
+                                       *min_rate = rate * 5;
                                        *min_rate_index = j;
                                }
                                break;
@@ -3884,27 +3885,40 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
                if (!new_sta)
                        return -ENOMEM;
        }
-
        if (new_sta) {
                u32 rates = 0, basic_rates = 0;
                bool have_higher_than_11mbit;
                int min_rate = INT_MAX, min_rate_index = -1;
+               struct ieee80211_chanctx_conf *chanctx_conf;
                struct ieee80211_supported_band *sband;
                const struct cfg80211_bss_ies *ies;
+               int shift;
+               u32 rate_flags;
 
                sband = local->hw.wiphy->bands[cbss->channel->band];
 
                err = ieee80211_prep_channel(sdata, cbss);
                if (err) {
                        sta_info_free(local, new_sta);
-                       return err;
+                       return -EINVAL;
                }
+               shift = ieee80211_vif_get_shift(&sdata->vif);
+
+               rcu_read_lock();
+               chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+               if (WARN_ON(!chanctx_conf)) {
+                       rcu_read_unlock();
+                       return -EINVAL;
+               }
+               rate_flags = ieee80211_chandef_rate_flags(&chanctx_conf->def);
+               rcu_read_unlock();
 
                ieee80211_get_rates(sband, bss->supp_rates,
                                    bss->supp_rates_len,
                                    &rates, &basic_rates,
                                    &have_higher_than_11mbit,
-                                   &min_rate, &min_rate_index);
+                                   &min_rate, &min_rate_index,
+                                   shift, rate_flags);
 
                /*
                 * This used to be a workaround for basic rates missing
index 7fc5d0d8149a53f2a20377499841657dd9a97c7c..340126204343a063902bb205675cc14bea743a4c 100644 (file)
@@ -99,10 +99,13 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
        }
        mutex_unlock(&local->sta_mtx);
 
-       /* remove all interfaces */
+       /* remove all interfaces that were created in the driver */
        list_for_each_entry(sdata, &local->interfaces, list) {
-               if (!ieee80211_sdata_running(sdata))
+               if (!ieee80211_sdata_running(sdata) ||
+                   sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+                   sdata->vif.type == NL80211_IFTYPE_MONITOR)
                        continue;
+
                drv_remove_interface(local, sdata);
        }
 
index 30d58d2d13e26a667024a3a2fca655b6fce1bd34..ba63ac851c2ba6769d2017c6622387331d9da5a1 100644 (file)
@@ -232,37 +232,28 @@ static void rc_send_low_broadcast(s8 *idx, u32 basic_rates,
        /* could not find a basic rate; use original selection */
 }
 
-static inline s8
-rate_lowest_non_cck_index(struct ieee80211_supported_band *sband,
-                         struct ieee80211_sta *sta)
+static void __rate_control_send_low(struct ieee80211_hw *hw,
+                                   struct ieee80211_supported_band *sband,
+                                   struct ieee80211_sta *sta,
+                                   struct ieee80211_tx_info *info)
 {
        int i;
+       u32 rate_flags =
+               ieee80211_chandef_rate_flags(&hw->conf.chandef);
 
+       if ((sband->band == IEEE80211_BAND_2GHZ) &&
+           (info->flags & IEEE80211_TX_CTL_NO_CCK_RATE))
+               rate_flags |= IEEE80211_RATE_ERP_G;
+
+       info->control.rates[0].idx = 0;
        for (i = 0; i < sband->n_bitrates; i++) {
-               struct ieee80211_rate *srate = &sband->bitrates[i];
-               if ((srate->bitrate == 10) || (srate->bitrate == 20) ||
-                   (srate->bitrate == 55) || (srate->bitrate == 110))
+               if (!rate_supported(sta, sband->band, i))
                        continue;
 
-               if (rate_supported(sta, sband->band, i))
-                       return i;
+               info->control.rates[0].idx = i;
+               break;
        }
-
-       /* No matching rate found */
-       return 0;
-}
-
-static void __rate_control_send_low(struct ieee80211_hw *hw,
-                                   struct ieee80211_supported_band *sband,
-                                   struct ieee80211_sta *sta,
-                                   struct ieee80211_tx_info *info)
-{
-       if ((sband->band != IEEE80211_BAND_2GHZ) ||
-           !(info->flags & IEEE80211_TX_CTL_NO_CCK_RATE))
-               info->control.rates[0].idx = rate_lowest_index(sband, sta);
-       else
-               info->control.rates[0].idx =
-                       rate_lowest_non_cck_index(sband, sta);
+       WARN_ON_ONCE(i == sband->n_bitrates);
 
        info->control.rates[0].count =
                (info->flags & IEEE80211_TX_CTL_NO_ACK) ?
@@ -585,6 +576,7 @@ static void rate_control_apply_mask(struct ieee80211_sub_if_data *sdata,
        u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN];
        bool has_mcs_mask;
        u32 mask;
+       u32 rate_flags;
        int i;
 
        /*
@@ -594,6 +586,12 @@ static void rate_control_apply_mask(struct ieee80211_sub_if_data *sdata,
         */
        mask = sdata->rc_rateidx_mask[info->band];
        has_mcs_mask = sdata->rc_has_mcs_mask[info->band];
+       rate_flags =
+               ieee80211_chandef_rate_flags(&sdata->vif.bss_conf.chandef);
+       for (i = 0; i < sband->n_bitrates; i++)
+               if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
+                       mask &= ~BIT(i);
+
        if (mask == (1 << sband->n_bitrates) - 1 && !has_mcs_mask)
                return;
 
index d35a5dd3fb13d3f6d742cdc2ccbbeb823365ed63..5dedc56c94dbe91a1b9bd6c959094ab3b494be86 100644 (file)
@@ -66,11 +66,12 @@ static inline void rate_control_rate_init(struct sta_info *sta)
        }
 
        sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band];
-       rcu_read_unlock();
 
        ieee80211_sta_set_rx_nss(sta);
 
-       ref->ops->rate_init(ref->priv, sband, ista, priv_sta);
+       ref->ops->rate_init(ref->priv, sband, &chanctx_conf->def, ista,
+                           priv_sta);
+       rcu_read_unlock();
        set_sta_flag(sta, WLAN_STA_RATE_CONTROL);
 }
 
@@ -81,10 +82,21 @@ static inline void rate_control_rate_update(struct ieee80211_local *local,
        struct rate_control_ref *ref = local->rate_ctrl;
        struct ieee80211_sta *ista = &sta->sta;
        void *priv_sta = sta->rate_ctrl_priv;
+       struct ieee80211_chanctx_conf *chanctx_conf;
+
+       if (ref && ref->ops->rate_update) {
+               rcu_read_lock();
 
-       if (ref && ref->ops->rate_update)
-               ref->ops->rate_update(ref->priv, sband, ista,
-                                     priv_sta, changed);
+               chanctx_conf = rcu_dereference(sta->sdata->vif.chanctx_conf);
+               if (WARN_ON(!chanctx_conf)) {
+                       rcu_read_unlock();
+                       return;
+               }
+
+               ref->ops->rate_update(ref->priv, sband, &chanctx_conf->def,
+                                     ista, priv_sta, changed);
+               rcu_read_unlock();
+       }
        drv_sta_rc_update(local, sta->sdata, &sta->sta, changed);
 }
 
index ac7ef5414bdede030d289a81946eaabc7b5d7a88..8b5f7ef7c0c9f14db5dba3baf8ab82247500c1c3 100644 (file)
@@ -290,7 +290,7 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
        struct minstrel_rate *msr, *mr;
        unsigned int ndx;
        bool mrr_capable;
-       bool prev_sample = mi->prev_sample;
+       bool prev_sample;
        int delta;
        int sampling_ratio;
 
@@ -314,6 +314,7 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
                        (mi->sample_count + mi->sample_deferred / 2);
 
        /* delta < 0: no sampling required */
+       prev_sample = mi->prev_sample;
        mi->prev_sample = false;
        if (delta < 0 || (!mrr_capable && prev_sample))
                return;
@@ -382,14 +383,18 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
 static void
 calc_rate_durations(enum ieee80211_band band,
                    struct minstrel_rate *d,
-                   struct ieee80211_rate *rate)
+                   struct ieee80211_rate *rate,
+                   struct cfg80211_chan_def *chandef)
 {
        int erp = !!(rate->flags & IEEE80211_RATE_ERP_G);
+       int shift = ieee80211_chandef_get_shift(chandef);
 
        d->perfect_tx_time = ieee80211_frame_duration(band, 1200,
-                       rate->bitrate, erp, 1);
+                       DIV_ROUND_UP(rate->bitrate, 1 << shift), erp, 1,
+                       shift);
        d->ack_time = ieee80211_frame_duration(band, 10,
-                       rate->bitrate, erp, 1);
+                       DIV_ROUND_UP(rate->bitrate, 1 << shift), erp, 1,
+                       shift);
 }
 
 static void
@@ -417,21 +422,25 @@ init_sample_table(struct minstrel_sta_info *mi)
 
 static void
 minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband,
-               struct ieee80211_sta *sta, void *priv_sta)
+                  struct cfg80211_chan_def *chandef,
+                  struct ieee80211_sta *sta, void *priv_sta)
 {
        struct minstrel_sta_info *mi = priv_sta;
        struct minstrel_priv *mp = priv;
        struct ieee80211_rate *ctl_rate;
        unsigned int i, n = 0;
        unsigned int t_slot = 9; /* FIXME: get real slot time */
+       u32 rate_flags;
 
        mi->sta = sta;
        mi->lowest_rix = rate_lowest_index(sband, sta);
        ctl_rate = &sband->bitrates[mi->lowest_rix];
        mi->sp_ack_dur = ieee80211_frame_duration(sband->band, 10,
                                ctl_rate->bitrate,
-                               !!(ctl_rate->flags & IEEE80211_RATE_ERP_G), 1);
+                               !!(ctl_rate->flags & IEEE80211_RATE_ERP_G), 1,
+                               ieee80211_chandef_get_shift(chandef));
 
+       rate_flags = ieee80211_chandef_rate_flags(&mp->hw->conf.chandef);
        memset(mi->max_tp_rate, 0, sizeof(mi->max_tp_rate));
        mi->max_prob_rate = 0;
 
@@ -440,15 +449,22 @@ minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband,
                unsigned int tx_time = 0, tx_time_cts = 0, tx_time_rtscts = 0;
                unsigned int tx_time_single;
                unsigned int cw = mp->cw_min;
+               int shift;
 
                if (!rate_supported(sta, sband->band, i))
                        continue;
+               if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
+                       continue;
+
                n++;
                memset(mr, 0, sizeof(*mr));
 
                mr->rix = i;
-               mr->bitrate = sband->bitrates[i].bitrate / 5;
-               calc_rate_durations(sband->band, mr, &sband->bitrates[i]);
+               shift = ieee80211_chandef_get_shift(chandef);
+               mr->bitrate = DIV_ROUND_UP(sband->bitrates[i].bitrate,
+                                          (1 << shift) * 5);
+               calc_rate_durations(sband->band, mr, &sband->bitrates[i],
+                                   chandef);
 
                /* calculate maximum number of retransmissions before
                 * fallback (based on maximum segment size) */
@@ -546,6 +562,7 @@ minstrel_init_cck_rates(struct minstrel_priv *mp)
 {
        static const int bitrates[4] = { 10, 20, 55, 110 };
        struct ieee80211_supported_band *sband;
+       u32 rate_flags = ieee80211_chandef_rate_flags(&mp->hw->conf.chandef);
        int i, j;
 
        sband = mp->hw->wiphy->bands[IEEE80211_BAND_2GHZ];
@@ -558,6 +575,9 @@ minstrel_init_cck_rates(struct minstrel_priv *mp)
                if (rate->flags & IEEE80211_RATE_ERP_G)
                        continue;
 
+               if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
+                       continue;
+
                for (j = 0; j < ARRAY_SIZE(bitrates); j++) {
                        if (rate->bitrate != bitrates[j])
                                continue;
index 5b2d3012b9830aef8d9101c26ba761402993b382..61569425b7236e2b45d61bb888cb6823afe7cbdf 100644 (file)
@@ -804,10 +804,18 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
 
        sample_group = &minstrel_mcs_groups[sample_idx / MCS_GROUP_RATES];
        info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
+       rate->count = 1;
+
+       if (sample_idx / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) {
+               int idx = sample_idx % ARRAY_SIZE(mp->cck_rates);
+               rate->idx = mp->cck_rates[idx];
+               rate->flags = 0;
+               return;
+       }
+
        rate->idx = sample_idx % MCS_GROUP_RATES +
                    (sample_group->streams - 1) * MCS_GROUP_RATES;
        rate->flags = IEEE80211_TX_RC_MCS | sample_group->flags;
-       rate->count = 1;
 }
 
 static void
@@ -836,6 +844,7 @@ minstrel_ht_update_cck(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
 
 static void
 minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
+                       struct cfg80211_chan_def *chandef,
                         struct ieee80211_sta *sta, void *priv_sta)
 {
        struct minstrel_priv *mp = priv;
@@ -861,8 +870,9 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
        mi->sta = sta;
        mi->stats_update = jiffies;
 
-       ack_dur = ieee80211_frame_duration(sband->band, 10, 60, 1, 1);
-       mi->overhead = ieee80211_frame_duration(sband->band, 0, 60, 1, 1) + ack_dur;
+       ack_dur = ieee80211_frame_duration(sband->band, 10, 60, 1, 1, 0);
+       mi->overhead = ieee80211_frame_duration(sband->band, 0, 60, 1, 1, 0);
+       mi->overhead += ack_dur;
        mi->overhead_rtscts = mi->overhead + 2 * ack_dur;
 
        mi->avg_ampdu_len = MINSTREL_FRAC(1, 1);
@@ -931,22 +941,25 @@ use_legacy:
        memset(&msp->legacy, 0, sizeof(msp->legacy));
        msp->legacy.r = msp->ratelist;
        msp->legacy.sample_table = msp->sample_table;
-       return mac80211_minstrel.rate_init(priv, sband, sta, &msp->legacy);
+       return mac80211_minstrel.rate_init(priv, sband, chandef, sta,
+                                          &msp->legacy);
 }
 
 static void
 minstrel_ht_rate_init(void *priv, struct ieee80211_supported_band *sband,
+                     struct cfg80211_chan_def *chandef,
                       struct ieee80211_sta *sta, void *priv_sta)
 {
-       minstrel_ht_update_caps(priv, sband, sta, priv_sta);
+       minstrel_ht_update_caps(priv, sband, chandef, sta, priv_sta);
 }
 
 static void
 minstrel_ht_rate_update(void *priv, struct ieee80211_supported_band *sband,
+                       struct cfg80211_chan_def *chandef,
                         struct ieee80211_sta *sta, void *priv_sta,
                         u32 changed)
 {
-       minstrel_ht_update_caps(priv, sband, sta, priv_sta);
+       minstrel_ht_update_caps(priv, sband, chandef, sta, priv_sta);
 }
 
 static void *
index 502d3ecc4a797b4004128604e5324d0cfc198bfe..958fad07b54cf64856e3600bd6299f4ca9abd72a 100644 (file)
@@ -293,6 +293,7 @@ rate_control_pid_get_rate(void *priv, struct ieee80211_sta *sta,
 
 static void
 rate_control_pid_rate_init(void *priv, struct ieee80211_supported_band *sband,
+                          struct cfg80211_chan_def *chandef,
                           struct ieee80211_sta *sta, void *priv_sta)
 {
        struct rc_pid_sta_info *spinfo = priv_sta;
index 23dbcfc69b3b7f09ffc35c81d03dddc38d36da5a..6b85f95b9ba16ed010d6f8a87b2829dae3dd7ca9 100644 (file)
@@ -87,11 +87,13 @@ ieee80211_rx_radiotap_space(struct ieee80211_local *local,
        int len;
 
        /* always present fields */
-       len = sizeof(struct ieee80211_radiotap_header) + 9;
+       len = sizeof(struct ieee80211_radiotap_header) + 8;
 
-       /* allocate extra bitmap */
+       /* allocate extra bitmaps */
        if (status->vendor_radiotap_len)
                len += 4;
+       if (status->chains)
+               len += 4 * hweight8(status->chains);
 
        if (ieee80211_have_rx_timestamp(status)) {
                len = ALIGN(len, 8);
@@ -100,6 +102,10 @@ ieee80211_rx_radiotap_space(struct ieee80211_local *local,
        if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
                len += 1;
 
+       /* antenna field, if we don't have per-chain info */
+       if (!status->chains)
+               len += 1;
+
        /* padding for RX_FLAGS if necessary */
        len = ALIGN(len, 2);
 
@@ -116,6 +122,11 @@ ieee80211_rx_radiotap_space(struct ieee80211_local *local,
                len += 12;
        }
 
+       if (status->chains) {
+               /* antenna and antenna signal fields */
+               len += 2 * hweight8(status->chains);
+       }
+
        if (status->vendor_radiotap_len) {
                if (WARN_ON_ONCE(status->vendor_radiotap_align == 0))
                        status->vendor_radiotap_align = 1;
@@ -145,8 +156,12 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
        struct ieee80211_radiotap_header *rthdr;
        unsigned char *pos;
+       __le32 *it_present;
+       u32 it_present_val;
        u16 rx_flags = 0;
-       int mpdulen;
+       u16 channel_flags = 0;
+       int mpdulen, chain;
+       unsigned long chains = status->chains;
 
        mpdulen = skb->len;
        if (!(has_fcs && (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)))
@@ -154,25 +169,39 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
 
        rthdr = (struct ieee80211_radiotap_header *)skb_push(skb, rtap_len);
        memset(rthdr, 0, rtap_len);
+       it_present = &rthdr->it_present;
 
        /* radiotap header, set always present flags */
-       rthdr->it_present =
-               cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
-                           (1 << IEEE80211_RADIOTAP_CHANNEL) |
-                           (1 << IEEE80211_RADIOTAP_ANTENNA) |
-                           (1 << IEEE80211_RADIOTAP_RX_FLAGS));
        rthdr->it_len = cpu_to_le16(rtap_len + status->vendor_radiotap_len);
+       it_present_val = BIT(IEEE80211_RADIOTAP_FLAGS) |
+                        BIT(IEEE80211_RADIOTAP_CHANNEL) |
+                        BIT(IEEE80211_RADIOTAP_RX_FLAGS);
 
-       pos = (unsigned char *)(rthdr + 1);
+       if (!status->chains)
+               it_present_val |= BIT(IEEE80211_RADIOTAP_ANTENNA);
+
+       for_each_set_bit(chain, &chains, IEEE80211_MAX_CHAINS) {
+               it_present_val |=
+                       BIT(IEEE80211_RADIOTAP_EXT) |
+                       BIT(IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE);
+               put_unaligned_le32(it_present_val, it_present);
+               it_present++;
+               it_present_val = BIT(IEEE80211_RADIOTAP_ANTENNA) |
+                                BIT(IEEE80211_RADIOTAP_DBM_ANTSIGNAL);
+       }
 
        if (status->vendor_radiotap_len) {
-               rthdr->it_present |=
-                       cpu_to_le32(BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE)) |
-                       cpu_to_le32(BIT(IEEE80211_RADIOTAP_EXT));
-               put_unaligned_le32(status->vendor_radiotap_bitmap, pos);
-               pos += 4;
+               it_present_val |= BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE) |
+                                 BIT(IEEE80211_RADIOTAP_EXT);
+               put_unaligned_le32(it_present_val, it_present);
+               it_present++;
+               it_present_val = status->vendor_radiotap_bitmap;
        }
 
+       put_unaligned_le32(it_present_val, it_present);
+
+       pos = (void *)(it_present + 1);
+
        /* the order of the following fields is important */
 
        /* IEEE80211_RADIOTAP_TSFT */
@@ -207,28 +236,35 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
                 */
                *pos = 0;
        } else {
+               int shift = 0;
                rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_RATE);
-               *pos = rate->bitrate / 5;
+               if (status->flag & RX_FLAG_10MHZ)
+                       shift = 1;
+               else if (status->flag & RX_FLAG_5MHZ)
+                       shift = 2;
+               *pos = DIV_ROUND_UP(rate->bitrate, 5 * (1 << shift));
        }
        pos++;
 
        /* IEEE80211_RADIOTAP_CHANNEL */
        put_unaligned_le16(status->freq, pos);
        pos += 2;
+       if (status->flag & RX_FLAG_10MHZ)
+               channel_flags |= IEEE80211_CHAN_HALF;
+       else if (status->flag & RX_FLAG_5MHZ)
+               channel_flags |= IEEE80211_CHAN_QUARTER;
+
        if (status->band == IEEE80211_BAND_5GHZ)
-               put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ,
-                                  pos);
+               channel_flags |= IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ;
        else if (status->flag & (RX_FLAG_HT | RX_FLAG_VHT))
-               put_unaligned_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ,
-                                  pos);
+               channel_flags |= IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
        else if (rate && rate->flags & IEEE80211_RATE_ERP_G)
-               put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ,
-                                  pos);
+               channel_flags |= IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ;
        else if (rate)
-               put_unaligned_le16(IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ,
-                                  pos);
+               channel_flags |= IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ;
        else
-               put_unaligned_le16(IEEE80211_CHAN_2GHZ, pos);
+               channel_flags |= IEEE80211_CHAN_2GHZ;
+       put_unaligned_le16(channel_flags, pos);
        pos += 2;
 
        /* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */
@@ -242,9 +278,11 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
 
        /* IEEE80211_RADIOTAP_LOCK_QUALITY is missing */
 
-       /* IEEE80211_RADIOTAP_ANTENNA */
-       *pos = status->antenna;
-       pos++;
+       if (!status->chains) {
+               /* IEEE80211_RADIOTAP_ANTENNA */
+               *pos = status->antenna;
+               pos++;
+       }
 
        /* IEEE80211_RADIOTAP_DB_ANTNOISE is not used */
 
@@ -341,6 +379,11 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
                pos += 2;
        }
 
+       for_each_set_bit(chain, &chains, IEEE80211_MAX_CHAINS) {
+               *pos++ = status->chain_signal[chain];
+               *pos++ = chain;
+       }
+
        if (status->vendor_radiotap_len) {
                /* ensure 2 byte alignment for the vendor field as required */
                if ((pos - (u8 *)rthdr) & 1)
@@ -936,8 +979,14 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
 
-       /* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */
-       if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) {
+       /*
+        * Drop duplicate 802.11 retransmissions
+        * (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery")
+        */
+       if (rx->skb->len >= 24 && rx->sta &&
+           !ieee80211_is_ctl(hdr->frame_control) &&
+           !ieee80211_is_qos_nullfunc(hdr->frame_control) &&
+           !is_multicast_ether_addr(hdr->addr1)) {
                if (unlikely(ieee80211_has_retry(hdr->frame_control) &&
                             rx->sta->last_seq_ctrl[rx->seqno_idx] ==
                             hdr->seq_ctrl)) {
index 1b122a79b0d8369a4118a6f238dc6d69db9e072c..08afe74b98f4b6cbdda21ed3d8ff68b9a95fa64b 100644 (file)
@@ -66,6 +66,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
        struct cfg80211_bss *cbss;
        struct ieee80211_bss *bss;
        int clen, srlen;
+       enum nl80211_bss_scan_width scan_width;
        s32 signal = 0;
 
        if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
@@ -73,8 +74,15 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
        else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)
                signal = (rx_status->signal * 100) / local->hw.max_signal;
 
-       cbss = cfg80211_inform_bss_frame(local->hw.wiphy, channel,
-                                        mgmt, len, signal, GFP_ATOMIC);
+       scan_width = NL80211_BSS_CHAN_WIDTH_20;
+       if (rx_status->flag & RX_FLAG_5MHZ)
+               scan_width = NL80211_BSS_CHAN_WIDTH_5;
+       if (rx_status->flag & RX_FLAG_10MHZ)
+               scan_width = NL80211_BSS_CHAN_WIDTH_10;
+
+       cbss = cfg80211_inform_bss_width_frame(local->hw.wiphy, channel,
+                                              scan_width, mgmt, len, signal,
+                                              GFP_ATOMIC);
        if (!cbss)
                return NULL;
 
@@ -204,10 +212,29 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
                ieee80211_rx_bss_put(local, bss);
 }
 
+static void
+ieee80211_prepare_scan_chandef(struct cfg80211_chan_def *chandef,
+                              enum nl80211_bss_scan_width scan_width)
+{
+       memset(chandef, 0, sizeof(*chandef));
+       switch (scan_width) {
+       case NL80211_BSS_CHAN_WIDTH_5:
+               chandef->width = NL80211_CHAN_WIDTH_5;
+               break;
+       case NL80211_BSS_CHAN_WIDTH_10:
+               chandef->width = NL80211_CHAN_WIDTH_10;
+               break;
+       default:
+               chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
+               break;
+       }
+}
+
 /* return false if no more work */
 static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
 {
        struct cfg80211_scan_request *req = local->scan_req;
+       struct cfg80211_chan_def chandef;
        enum ieee80211_band band;
        int i, ielen, n_chans;
 
@@ -229,11 +256,12 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
        } while (!n_chans);
 
        local->hw_scan_req->n_channels = n_chans;
+       ieee80211_prepare_scan_chandef(&chandef, req->scan_width);
 
        ielen = ieee80211_build_preq_ies(local, (u8 *)local->hw_scan_req->ie,
                                         local->hw_scan_ies_bufsize,
                                         req->ie, req->ie_len, band,
-                                        req->rates[band], 0);
+                                        req->rates[band], &chandef);
        local->hw_scan_req->ie_len = ielen;
        local->hw_scan_req->no_cck = req->no_cck;
 
@@ -280,7 +308,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
        rcu_assign_pointer(local->scan_sdata, NULL);
 
        local->scanning = 0;
-       local->scan_channel = NULL;
+       local->scan_chandef.chan = NULL;
 
        /* Set power back to normal operating levels. */
        ieee80211_hw_config(local, 0);
@@ -615,11 +643,34 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
 {
        int skip;
        struct ieee80211_channel *chan;
+       enum nl80211_bss_scan_width oper_scan_width;
 
        skip = 0;
        chan = local->scan_req->channels[local->scan_channel_idx];
 
-       local->scan_channel = chan;
+       local->scan_chandef.chan = chan;
+       local->scan_chandef.center_freq1 = chan->center_freq;
+       local->scan_chandef.center_freq2 = 0;
+       switch (local->scan_req->scan_width) {
+       case NL80211_BSS_CHAN_WIDTH_5:
+               local->scan_chandef.width = NL80211_CHAN_WIDTH_5;
+               break;
+       case NL80211_BSS_CHAN_WIDTH_10:
+               local->scan_chandef.width = NL80211_CHAN_WIDTH_10;
+               break;
+       case NL80211_BSS_CHAN_WIDTH_20:
+               /* If scanning on oper channel, use whatever channel-type
+                * is currently in use.
+                */
+               oper_scan_width = cfg80211_chandef_to_scan_width(
+                                       &local->_oper_chandef);
+               if (chan == local->_oper_chandef.chan &&
+                   oper_scan_width == local->scan_req->scan_width)
+                       local->scan_chandef = local->_oper_chandef;
+               else
+                       local->scan_chandef.width = NL80211_CHAN_WIDTH_20_NOHT;
+               break;
+       }
 
        if (ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL))
                skip = 1;
@@ -659,7 +710,7 @@ static void ieee80211_scan_state_suspend(struct ieee80211_local *local,
                                         unsigned long *next_delay)
 {
        /* switch back to the operating channel */
-       local->scan_channel = NULL;
+       local->scan_chandef.chan = NULL;
        ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
 
        /* disable PS */
@@ -801,7 +852,8 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
 
 int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata,
                                const u8 *ssid, u8 ssid_len,
-                               struct ieee80211_channel *chan)
+                               struct ieee80211_channel *chan,
+                               enum nl80211_bss_scan_width scan_width)
 {
        struct ieee80211_local *local = sdata->local;
        int ret = -EBUSY;
@@ -851,6 +903,7 @@ int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata,
 
        local->int_scan_req->ssids = &local->scan_ssid;
        local->int_scan_req->n_ssids = 1;
+       local->int_scan_req->scan_width = scan_width;
        memcpy(local->int_scan_req->ssids[0].ssid, ssid, IEEE80211_MAX_SSID_LEN);
        local->int_scan_req->ssids[0].ssid_len = ssid_len;
 
@@ -912,6 +965,7 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_sched_scan_ies sched_scan_ies = {};
+       struct cfg80211_chan_def chandef;
        int ret, i, iebufsz;
 
        iebufsz = 2 + IEEE80211_MAX_SSID_LEN +
@@ -939,10 +993,12 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
                        goto out_free;
                }
 
+               ieee80211_prepare_scan_chandef(&chandef, req->scan_width);
+
                sched_scan_ies.len[i] =
                        ieee80211_build_preq_ies(local, sched_scan_ies.ie[i],
                                                 iebufsz, req->ie, req->ie_len,
-                                                i, (u32) -1, 0);
+                                                i, (u32) -1, &chandef);
        }
 
        ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies);
index 43439203f4e4cf2262092a9e391e7d048f10ef9a..6ad4c14385ef420bf039660ccce5b1a8672dd500 100644 (file)
@@ -252,9 +252,10 @@ static int ieee80211_tx_radiotap_len(struct ieee80211_tx_info *info)
        return len;
 }
 
-static void ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band
-                                            *sband, struct sk_buff *skb,
-                                            int retry_count, int rtap_len)
+static void
+ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band *sband,
+                                struct sk_buff *skb, int retry_count,
+                                int rtap_len, int shift)
 {
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
@@ -280,8 +281,11 @@ static void ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band
        /* IEEE80211_RADIOTAP_RATE */
        if (info->status.rates[0].idx >= 0 &&
            !(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) {
+               u16 rate;
+
                rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_RATE);
-               *pos = sband->bitrates[info->status.rates[0].idx].bitrate / 5;
+               rate = sband->bitrates[info->status.rates[0].idx].bitrate;
+               *pos = DIV_ROUND_UP(rate, 5 * (1 << shift));
                /* padding for tx flags */
                pos += 2;
        }
@@ -424,6 +428,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
        bool acked;
        struct ieee80211_bar *bar;
        int rtap_len;
+       int shift = 0;
 
        for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
                if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
@@ -458,6 +463,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                if (!ether_addr_equal(hdr->addr2, sta->sdata->vif.addr))
                        continue;
 
+               shift = ieee80211_vif_get_shift(&sta->sdata->vif);
+
                if (info->flags & IEEE80211_TX_STATUS_EOSP)
                        clear_sta_flag(sta, WLAN_STA_SP);
 
@@ -624,7 +631,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                dev_kfree_skb(skb);
                return;
        }
-       ieee80211_add_tx_radiotap_header(sband, skb, retry_count, rtap_len);
+       ieee80211_add_tx_radiotap_header(sband, skb, retry_count, rtap_len,
+                                        shift);
 
        /* XXX: is this sufficient for BPF? */
        skb_set_mac_header(skb, 0);
index 4105d0ca963e25dfdd558e30c48274277e5ad2df..be4d3caf4879b5eb09d6a49d524cb4faa81c2752 100644 (file)
@@ -40,12 +40,22 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,
                                 struct sk_buff *skb, int group_addr,
                                 int next_frag_len)
 {
-       int rate, mrate, erp, dur, i;
+       int rate, mrate, erp, dur, i, shift = 0;
        struct ieee80211_rate *txrate;
        struct ieee80211_local *local = tx->local;
        struct ieee80211_supported_band *sband;
        struct ieee80211_hdr *hdr;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_chanctx_conf *chanctx_conf;
+       u32 rate_flags = 0;
+
+       rcu_read_lock();
+       chanctx_conf = rcu_dereference(tx->sdata->vif.chanctx_conf);
+       if (chanctx_conf) {
+               shift = ieee80211_chandef_get_shift(&chanctx_conf->def);
+               rate_flags = ieee80211_chandef_rate_flags(&chanctx_conf->def);
+       }
+       rcu_read_unlock();
 
        /* assume HW handles this */
        if (tx->rate.flags & IEEE80211_TX_RC_MCS)
@@ -122,8 +132,11 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,
                if (r->bitrate > txrate->bitrate)
                        break;
 
+               if ((rate_flags & r->flags) != rate_flags)
+                       continue;
+
                if (tx->sdata->vif.bss_conf.basic_rates & BIT(i))
-                       rate = r->bitrate;
+                       rate = DIV_ROUND_UP(r->bitrate, 1 << shift);
 
                switch (sband->band) {
                case IEEE80211_BAND_2GHZ: {
@@ -150,7 +163,7 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,
        if (rate == -1) {
                /* No matching basic rate found; use highest suitable mandatory
                 * PHY rate */
-               rate = mrate;
+               rate = DIV_ROUND_UP(mrate, 1 << shift);
        }
 
        /* Don't calculate ACKs for QoS Frames with NoAck Policy set */
@@ -162,7 +175,8 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,
                 * (10 bytes + 4-byte FCS = 112 bits) plus SIFS; rounded up
                 * to closest integer */
                dur = ieee80211_frame_duration(sband->band, 10, rate, erp,
-                               tx->sdata->vif.bss_conf.use_short_preamble);
+                               tx->sdata->vif.bss_conf.use_short_preamble,
+                               shift);
 
        if (next_frag_len) {
                /* Frame is fragmented: duration increases with time needed to
@@ -171,7 +185,8 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,
                /* next fragment */
                dur += ieee80211_frame_duration(sband->band, next_frag_len,
                                txrate->bitrate, erp,
-                               tx->sdata->vif.bss_conf.use_short_preamble);
+                               tx->sdata->vif.bss_conf.use_short_preamble,
+                               shift);
        }
 
        return cpu_to_le16(dur);
@@ -1257,6 +1272,10 @@ static bool __ieee80211_tx(struct ieee80211_local *local,
 
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_MONITOR:
+               if (sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE) {
+                       vif = &sdata->vif;
+                       break;
+               }
                sdata = rcu_dereference(local->monitor_sdata);
                if (sdata) {
                        vif = &sdata->vif;
index 22654452a56157b44835f97efacdf2e8960ee5bc..d23c5a705a6846db93596958c64139780a9874b4 100644 (file)
@@ -107,7 +107,8 @@ void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx)
 }
 
 int ieee80211_frame_duration(enum ieee80211_band band, size_t len,
-                            int rate, int erp, int short_preamble)
+                            int rate, int erp, int short_preamble,
+                            int shift)
 {
        int dur;
 
@@ -118,6 +119,9 @@ int ieee80211_frame_duration(enum ieee80211_band band, size_t len,
         *
         * rate is in 100 kbps, so divident is multiplied by 10 in the
         * DIV_ROUND_UP() operations.
+        *
+        * shift may be 2 for 5 MHz channels or 1 for 10 MHz channels, and
+        * is assumed to be 0 otherwise.
         */
 
        if (band == IEEE80211_BAND_5GHZ || erp) {
@@ -130,13 +134,23 @@ int ieee80211_frame_duration(enum ieee80211_band band, size_t len,
                 * TXTIME = T_PREAMBLE + T_SIGNAL + T_SYM x N_SYM + Signal Ext
                 *
                 * T_SYM = 4 usec
-                * 802.11a - 17.5.2: aSIFSTime = 16 usec
+                * 802.11a - 18.5.2: aSIFSTime = 16 usec
                 * 802.11g - 19.8.4: aSIFSTime = 10 usec +
                 *      signal ext = 6 usec
                 */
                dur = 16; /* SIFS + signal ext */
-               dur += 16; /* 17.3.2.3: T_PREAMBLE = 16 usec */
-               dur += 4; /* 17.3.2.3: T_SIGNAL = 4 usec */
+               dur += 16; /* IEEE 802.11-2012 18.3.2.4: T_PREAMBLE = 16 usec */
+               dur += 4; /* IEEE 802.11-2012 18.3.2.4: T_SIGNAL = 4 usec */
+
+               /* IEEE 802.11-2012 18.3.2.4: all values above are:
+                *  * times 4 for 5 MHz
+                *  * times 2 for 10 MHz
+                */
+               dur *= 1 << shift;
+
+               /* rates should already consider the channel bandwidth,
+                * don't apply divisor again.
+                */
                dur += 4 * DIV_ROUND_UP((16 + 8 * (len + 4) + 6) * 10,
                                        4 * rate); /* T_SYM x N_SYM */
        } else {
@@ -168,7 +182,7 @@ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
 {
        struct ieee80211_sub_if_data *sdata;
        u16 dur;
-       int erp;
+       int erp, shift = 0;
        bool short_preamble = false;
 
        erp = 0;
@@ -177,10 +191,11 @@ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
                short_preamble = sdata->vif.bss_conf.use_short_preamble;
                if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
                        erp = rate->flags & IEEE80211_RATE_ERP_G;
+               shift = ieee80211_vif_get_shift(vif);
        }
 
        dur = ieee80211_frame_duration(band, frame_len, rate->bitrate, erp,
-                                      short_preamble);
+                                      short_preamble, shift);
 
        return cpu_to_le16(dur);
 }
@@ -194,7 +209,7 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
        struct ieee80211_rate *rate;
        struct ieee80211_sub_if_data *sdata;
        bool short_preamble;
-       int erp;
+       int erp, shift = 0, bitrate;
        u16 dur;
        struct ieee80211_supported_band *sband;
 
@@ -210,17 +225,20 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
                short_preamble = sdata->vif.bss_conf.use_short_preamble;
                if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
                        erp = rate->flags & IEEE80211_RATE_ERP_G;
+               shift = ieee80211_vif_get_shift(vif);
        }
 
+       bitrate = DIV_ROUND_UP(rate->bitrate, 1 << shift);
+
        /* CTS duration */
-       dur = ieee80211_frame_duration(sband->band, 10, rate->bitrate,
-                                      erp, short_preamble);
+       dur = ieee80211_frame_duration(sband->band, 10, bitrate,
+                                      erp, short_preamble, shift);
        /* Data frame duration */
-       dur += ieee80211_frame_duration(sband->band, frame_len, rate->bitrate,
-                                       erp, short_preamble);
+       dur += ieee80211_frame_duration(sband->band, frame_len, bitrate,
+                                       erp, short_preamble, shift);
        /* ACK duration */
-       dur += ieee80211_frame_duration(sband->band, 10, rate->bitrate,
-                                       erp, short_preamble);
+       dur += ieee80211_frame_duration(sband->band, 10, bitrate,
+                                       erp, short_preamble, shift);
 
        return cpu_to_le16(dur);
 }
@@ -235,7 +253,7 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
        struct ieee80211_rate *rate;
        struct ieee80211_sub_if_data *sdata;
        bool short_preamble;
-       int erp;
+       int erp, shift = 0, bitrate;
        u16 dur;
        struct ieee80211_supported_band *sband;
 
@@ -250,15 +268,18 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
                short_preamble = sdata->vif.bss_conf.use_short_preamble;
                if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
                        erp = rate->flags & IEEE80211_RATE_ERP_G;
+               shift = ieee80211_vif_get_shift(vif);
        }
 
+       bitrate = DIV_ROUND_UP(rate->bitrate, 1 << shift);
+
        /* Data frame duration */
-       dur = ieee80211_frame_duration(sband->band, frame_len, rate->bitrate,
-                                      erp, short_preamble);
+       dur = ieee80211_frame_duration(sband->band, frame_len, bitrate,
+                                      erp, short_preamble, shift);
        if (!(frame_txctl->flags & IEEE80211_TX_CTL_NO_ACK)) {
                /* ACK duration */
-               dur += ieee80211_frame_duration(sband->band, 10, rate->bitrate,
-                                               erp, short_preamble);
+               dur += ieee80211_frame_duration(sband->band, 10, bitrate,
+                                               erp, short_preamble, shift);
        }
 
        return cpu_to_le16(dur);
@@ -1052,32 +1073,6 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
        }
 }
 
-void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
-                                 const size_t supp_rates_len,
-                                 const u8 *supp_rates)
-{
-       struct ieee80211_chanctx_conf *chanctx_conf;
-       int i, have_higher_than_11mbit = 0;
-
-       /* cf. IEEE 802.11 9.2.12 */
-       for (i = 0; i < supp_rates_len; i++)
-               if ((supp_rates[i] & 0x7f) * 5 > 110)
-                       have_higher_than_11mbit = 1;
-
-       rcu_read_lock();
-       chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
-
-       if (chanctx_conf &&
-           chanctx_conf->def.chan->band == IEEE80211_BAND_2GHZ &&
-           have_higher_than_11mbit)
-               sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
-       else
-               sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
-       rcu_read_unlock();
-
-       ieee80211_set_wmm_default(sdata, true);
-}
-
 void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
                         u16 transaction, u16 auth_alg, u16 status,
                         const u8 *extra, size_t extra_len, const u8 *da,
@@ -1162,7 +1157,7 @@ void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
 int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
                             size_t buffer_len, const u8 *ie, size_t ie_len,
                             enum ieee80211_band band, u32 rate_mask,
-                            u8 channel)
+                            struct cfg80211_chan_def *chandef)
 {
        struct ieee80211_supported_band *sband;
        u8 *pos = buffer, *end = buffer + buffer_len;
@@ -1171,16 +1166,26 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
        u8 rates[32];
        int num_rates;
        int ext_rates_len;
+       int shift;
+       u32 rate_flags;
 
        sband = local->hw.wiphy->bands[band];
        if (WARN_ON_ONCE(!sband))
                return 0;
 
+       rate_flags = ieee80211_chandef_rate_flags(chandef);
+       shift = ieee80211_chandef_get_shift(chandef);
+
        num_rates = 0;
        for (i = 0; i < sband->n_bitrates; i++) {
                if ((BIT(i) & rate_mask) == 0)
                        continue; /* skip rate */
-               rates[num_rates++] = (u8) (sband->bitrates[i].bitrate / 5);
+               if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
+                       continue;
+
+               rates[num_rates++] =
+                       (u8) DIV_ROUND_UP(sband->bitrates[i].bitrate,
+                                         (1 << shift) * 5);
        }
 
        supp_rates_len = min_t(int, num_rates, 8);
@@ -1220,12 +1225,13 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
                pos += ext_rates_len;
        }
 
-       if (channel && sband->band == IEEE80211_BAND_2GHZ) {
+       if (chandef->chan && sband->band == IEEE80211_BAND_2GHZ) {
                if (end - pos < 3)
                        goto out_err;
                *pos++ = WLAN_EID_DS_PARAMS;
                *pos++ = 1;
-               *pos++ = channel;
+               *pos++ = ieee80211_frequency_to_channel(
+                               chandef->chan->center_freq);
        }
 
        /* insert custom IEs that go before HT */
@@ -1290,9 +1296,9 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
                                          bool directed)
 {
        struct ieee80211_local *local = sdata->local;
+       struct cfg80211_chan_def chandef;
        struct sk_buff *skb;
        struct ieee80211_mgmt *mgmt;
-       u8 chan_no;
        int ies_len;
 
        /*
@@ -1300,10 +1306,11 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
         * in order to maximize the chance that we get a response.  Some
         * badly-behaved APs don't respond when this parameter is included.
         */
+       chandef.width = sdata->vif.bss_conf.chandef.width;
        if (directed)
-               chan_no = 0;
+               chandef.chan = NULL;
        else
-               chan_no = ieee80211_frequency_to_channel(chan->center_freq);
+               chandef.chan = chan;
 
        skb = ieee80211_probereq_get(&local->hw, &sdata->vif,
                                     ssid, ssid_len, 100 + ie_len);
@@ -1313,7 +1320,7 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
        ies_len = ieee80211_build_preq_ies(local, skb_tail_pointer(skb),
                                           skb_tailroom(skb),
                                           ie, ie_len, chan->band,
-                                          ratemask, chan_no);
+                                          ratemask, &chandef);
        skb_put(skb, ies_len);
 
        if (dst) {
@@ -1347,16 +1354,19 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
        }
 }
 
-u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
+u32 ieee80211_sta_get_rates(struct ieee80211_sub_if_data *sdata,
                            struct ieee802_11_elems *elems,
                            enum ieee80211_band band, u32 *basic_rates)
 {
        struct ieee80211_supported_band *sband;
        struct ieee80211_rate *bitrates;
        size_t num_rates;
-       u32 supp_rates;
-       int i, j;
-       sband = local->hw.wiphy->bands[band];
+       u32 supp_rates, rate_flags;
+       int i, j, shift;
+       sband = sdata->local->hw.wiphy->bands[band];
+
+       rate_flags = ieee80211_chandef_rate_flags(&sdata->vif.bss_conf.chandef);
+       shift = ieee80211_vif_get_shift(&sdata->vif);
 
        if (WARN_ON(!sband))
                return 1;
@@ -1381,7 +1391,15 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
                        continue;
 
                for (j = 0; j < num_rates; j++) {
-                       if (bitrates[j].bitrate == own_rate) {
+                       int brate;
+                       if ((rate_flags & sband->bitrates[j].flags)
+                           != rate_flags)
+                               continue;
+
+                       brate = DIV_ROUND_UP(sband->bitrates[j].bitrate,
+                                            1 << shift);
+
+                       if (brate == own_rate) {
                                supp_rates |= BIT(j);
                                if (basic_rates && is_basic)
                                        *basic_rates |= BIT(j);
@@ -2004,18 +2022,56 @@ void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan,
        cfg80211_chandef_create(chandef, control_chan, channel_type);
 }
 
+int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef,
+                            const struct ieee80211_supported_band *sband,
+                            const u8 *srates, int srates_len, u32 *rates)
+{
+       u32 rate_flags = ieee80211_chandef_rate_flags(chandef);
+       int shift = ieee80211_chandef_get_shift(chandef);
+       struct ieee80211_rate *br;
+       int brate, rate, i, j, count = 0;
+
+       *rates = 0;
+
+       for (i = 0; i < srates_len; i++) {
+               rate = srates[i] & 0x7f;
+
+               for (j = 0; j < sband->n_bitrates; j++) {
+                       br = &sband->bitrates[j];
+                       if ((rate_flags & br->flags) != rate_flags)
+                               continue;
+
+                       brate = DIV_ROUND_UP(br->bitrate, (1 << shift) * 5);
+                       if (brate == rate) {
+                               *rates |= BIT(j);
+                               count++;
+                               break;
+                       }
+               }
+       }
+       return count;
+}
+
 int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata,
                            struct sk_buff *skb, bool need_basic,
                            enum ieee80211_band band)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_supported_band *sband;
-       int rate;
+       int rate, shift;
        u8 i, rates, *pos;
        u32 basic_rates = sdata->vif.bss_conf.basic_rates;
+       u32 rate_flags;
 
+       shift = ieee80211_vif_get_shift(&sdata->vif);
+       rate_flags = ieee80211_chandef_rate_flags(&sdata->vif.bss_conf.chandef);
        sband = local->hw.wiphy->bands[band];
-       rates = sband->n_bitrates;
+       rates = 0;
+       for (i = 0; i < sband->n_bitrates; i++) {
+               if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
+                       continue;
+               rates++;
+       }
        if (rates > 8)
                rates = 8;
 
@@ -2027,10 +2083,15 @@ int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata,
        *pos++ = rates;
        for (i = 0; i < rates; i++) {
                u8 basic = 0;
+               if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
+                       continue;
+
                if (need_basic && basic_rates & BIT(i))
                        basic = 0x80;
                rate = sband->bitrates[i].bitrate;
-               *pos++ = basic | (u8) (rate / 5);
+               rate = DIV_ROUND_UP(sband->bitrates[i].bitrate,
+                                   5 * (1 << shift));
+               *pos++ = basic | (u8) rate;
        }
 
        return 0;
@@ -2042,12 +2103,22 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata,
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_supported_band *sband;
-       int rate;
+       int rate, skip, shift;
        u8 i, exrates, *pos;
        u32 basic_rates = sdata->vif.bss_conf.basic_rates;
+       u32 rate_flags;
+
+       rate_flags = ieee80211_chandef_rate_flags(&sdata->vif.bss_conf.chandef);
+       shift = ieee80211_vif_get_shift(&sdata->vif);
 
        sband = local->hw.wiphy->bands[band];
-       exrates = sband->n_bitrates;
+       exrates = 0;
+       for (i = 0; i < sband->n_bitrates; i++) {
+               if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
+                       continue;
+               exrates++;
+       }
+
        if (exrates > 8)
                exrates -= 8;
        else
@@ -2060,12 +2131,19 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata,
                pos = skb_put(skb, exrates + 2);
                *pos++ = WLAN_EID_EXT_SUPP_RATES;
                *pos++ = exrates;
+               skip = 0;
                for (i = 8; i < sband->n_bitrates; i++) {
                        u8 basic = 0;
+                       if ((rate_flags & sband->bitrates[i].flags)
+                           != rate_flags)
+                               continue;
+                       if (skip++ < 8)
+                               continue;
                        if (need_basic && basic_rates & BIT(i))
                                basic = 0x80;
-                       rate = sband->bitrates[i].bitrate;
-                       *pos++ = basic | (u8) (rate / 5);
+                       rate = DIV_ROUND_UP(sband->bitrates[i].bitrate,
+                                           5 * (1 << shift));
+                       *pos++ = basic | (u8) rate;
                }
        }
        return 0;
@@ -2149,9 +2227,17 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
                        ri.flags |= RATE_INFO_FLAGS_SHORT_GI;
        } else {
                struct ieee80211_supported_band *sband;
+               int shift = 0;
+               int bitrate;
+
+               if (status->flag & RX_FLAG_10MHZ)
+                       shift = 1;
+               if (status->flag & RX_FLAG_5MHZ)
+                       shift = 2;
 
                sband = local->hw.wiphy->bands[status->band];
-               ri.legacy = sband->bitrates[status->rate_idx].bitrate;
+               bitrate = sband->bitrates[status->rate_idx].bitrate;
+               ri.legacy = DIV_ROUND_UP(bitrate, (1 << shift));
        }
 
        rate = cfg80211_calculate_bitrate(&ri);
index 3c0da8728036346a6a9ba235821779b49931b311..23e596e438b3fb4e51a97782c4cf00ad7d33af68 100644 (file)
@@ -66,15 +66,7 @@ sctp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,
 static void sctp_nat_csum(struct sk_buff *skb, sctp_sctphdr_t *sctph,
                          unsigned int sctphoff)
 {
-       __u32 crc32;
-       struct sk_buff *iter;
-
-       crc32 = sctp_start_cksum((__u8 *)sctph, skb_headlen(skb) - sctphoff);
-       skb_walk_frags(skb, iter)
-               crc32 = sctp_update_cksum((u8 *) iter->data,
-                                         skb_headlen(iter), crc32);
-       sctph->checksum = sctp_end_cksum(crc32);
-
+       sctph->checksum = sctp_compute_cksum(skb, sctphoff);
        skb->ip_summed = CHECKSUM_UNNECESSARY;
 }
 
@@ -151,10 +143,7 @@ sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
 {
        unsigned int sctphoff;
        struct sctphdr *sh, _sctph;
-       struct sk_buff *iter;
-       __le32 cmp;
-       __le32 val;
-       __u32 tmp;
+       __le32 cmp, val;
 
 #ifdef CONFIG_IP_VS_IPV6
        if (af == AF_INET6)
@@ -168,13 +157,7 @@ sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
                return 0;
 
        cmp = sh->checksum;
-
-       tmp = sctp_start_cksum((__u8 *) sh, skb_headlen(skb));
-       skb_walk_frags(skb, iter)
-               tmp = sctp_update_cksum((__u8 *) iter->data,
-                                       skb_headlen(iter), tmp);
-
-       val = sctp_end_cksum(tmp);
+       val = sctp_compute_cksum(skb, sctphoff);
 
        if (val != cmp) {
                /* CRC failure, dump it. */
index c63b618cd619eb01d0fe99413162a84edd09ac3c..4fd1ca94fd4a140b374385ded878af60b503b529 100644 (file)
@@ -293,6 +293,11 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
                       sizeof(exp->tuple.dst.u3) - len);
 
        exp->tuple.dst.u.all = *dst;
+
+#ifdef CONFIG_NF_NAT_NEEDED
+       memset(&exp->saved_addr, 0, sizeof(exp->saved_addr));
+       memset(&exp->saved_proto, 0, sizeof(exp->saved_proto));
+#endif
 }
 EXPORT_SYMBOL_GPL(nf_ct_expect_init);
 
index 396e55d46f90c77ea25a88cc1e94decc76f81050..754536f2c67488acd4345cdcec3740916ab24fea 100644 (file)
@@ -34,9 +34,7 @@ sctp_manip_pkt(struct sk_buff *skb,
               const struct nf_conntrack_tuple *tuple,
               enum nf_nat_manip_type maniptype)
 {
-       struct sk_buff *frag;
        sctp_sctphdr_t *hdr;
-       __u32 crc32;
 
        if (!skb_make_writable(skb, hdroff + sizeof(*hdr)))
                return false;
@@ -51,11 +49,7 @@ sctp_manip_pkt(struct sk_buff *skb,
                hdr->dest = tuple->dst.u.sctp.port;
        }
 
-       crc32 = sctp_start_cksum((u8 *)hdr, skb_headlen(skb) - hdroff);
-       skb_walk_frags(skb, frag)
-               crc32 = sctp_update_cksum((u8 *)frag->data, skb_headlen(frag),
-                                         crc32);
-       hdr->checksum = sctp_end_cksum(crc32);
+       hdr->checksum = sctp_compute_cksum(skb, hdroff);
 
        return true;
 }
index f8b71911037ab172f3df8f6a82cb8d22191ab1d6..20b15916f40363ff789d2d7312dd5fe4dedf69ab 100644 (file)
@@ -172,7 +172,7 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par,
 
                /* Ignore non-transparent sockets,
                   if XT_SOCKET_TRANSPARENT is used */
-               if (info && info->flags & XT_SOCKET_TRANSPARENT)
+               if (info->flags & XT_SOCKET_TRANSPARENT)
                        transparent = ((sk->sk_state != TCP_TIME_WAIT &&
                                        inet_sk(sk)->transparent) ||
                                       (sk->sk_state == TCP_TIME_WAIT &&
@@ -196,7 +196,11 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par,
 static bool
 socket_mt4_v0(const struct sk_buff *skb, struct xt_action_param *par)
 {
-       return socket_match(skb, par, NULL);
+       static struct xt_socket_mtinfo1 xt_info_v0 = {
+               .flags = 0,
+       };
+
+       return socket_match(skb, par, &xt_info_v0);
 }
 
 static bool
@@ -314,7 +318,7 @@ socket_mt6_v1_v2(const struct sk_buff *skb, struct xt_action_param *par)
 
                /* Ignore non-transparent sockets,
                   if XT_SOCKET_TRANSPARENT is used */
-               if (info && info->flags & XT_SOCKET_TRANSPARENT)
+               if (info->flags & XT_SOCKET_TRANSPARENT)
                        transparent = ((sk->sk_state != TCP_TIME_WAIT &&
                                        inet_sk(sk)->transparent) ||
                                       (sk->sk_state == TCP_TIME_WAIT &&
index 2fd6dbea327a8b39d2ec0ed10b927d74bcdab408..512718adb0d59df5120e047c69c973556d1c6fb6 100644 (file)
@@ -571,7 +571,7 @@ static int genl_family_rcv_msg(struct genl_family *family,
            !capable(CAP_NET_ADMIN))
                return -EPERM;
 
-       if (nlh->nlmsg_flags & NLM_F_DUMP) {
+       if ((nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP) {
                struct netlink_dump_control c = {
                        .dump = ops->dumpit,
                        .done = ops->done,
@@ -877,8 +877,10 @@ static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info)
 #ifdef CONFIG_MODULES
                if (res == NULL) {
                        genl_unlock();
+                       up_read(&cb_lock);
                        request_module("net-pf-%d-proto-%d-family-%s",
                                       PF_NETLINK, NETLINK_GENERIC, name);
+                       down_read(&cb_lock);
                        genl_lock();
                        res = genl_family_find_byname(name);
                }
index dc96a83aa6abb6659311e11ef13f97dc81c3b494..1d074dd1650ff2fd326dd141eedb828d812a12e6 100644 (file)
@@ -44,7 +44,7 @@ DEFINE_MUTEX(nfc_devlist_mutex);
 /* NFC device ID bitmap */
 static DEFINE_IDA(nfc_index_ida);
 
-int nfc_fw_upload(struct nfc_dev *dev, const char *firmware_name)
+int nfc_fw_download(struct nfc_dev *dev, const char *firmware_name)
 {
        int rc = 0;
 
@@ -62,28 +62,28 @@ int nfc_fw_upload(struct nfc_dev *dev, const char *firmware_name)
                goto error;
        }
 
-       if (!dev->ops->fw_upload) {
+       if (!dev->ops->fw_download) {
                rc = -EOPNOTSUPP;
                goto error;
        }
 
-       dev->fw_upload_in_progress = true;
-       rc = dev->ops->fw_upload(dev, firmware_name);
+       dev->fw_download_in_progress = true;
+       rc = dev->ops->fw_download(dev, firmware_name);
        if (rc)
-               dev->fw_upload_in_progress = false;
+               dev->fw_download_in_progress = false;
 
 error:
        device_unlock(&dev->dev);
        return rc;
 }
 
-int nfc_fw_upload_done(struct nfc_dev *dev, const char *firmware_name)
+int nfc_fw_download_done(struct nfc_dev *dev, const char *firmware_name)
 {
-       dev->fw_upload_in_progress = false;
+       dev->fw_download_in_progress = false;
 
-       return nfc_genl_fw_upload_done(dev, firmware_name);
+       return nfc_genl_fw_download_done(dev, firmware_name);
 }
-EXPORT_SYMBOL(nfc_fw_upload_done);
+EXPORT_SYMBOL(nfc_fw_download_done);
 
 /**
  * nfc_dev_up - turn on the NFC device
@@ -110,7 +110,7 @@ int nfc_dev_up(struct nfc_dev *dev)
                goto error;
        }
 
-       if (dev->fw_upload_in_progress) {
+       if (dev->fw_download_in_progress) {
                rc = -EBUSY;
                goto error;
        }
index 7b1c186736ebf924977ed8eb9040357ab88f3c3c..fe66908401f55ed5f608a75b559e5fad1ff15548 100644 (file)
@@ -809,14 +809,14 @@ static void nfc_hci_recv_from_llc(struct nfc_hci_dev *hdev, struct sk_buff *skb)
        }
 }
 
-static int hci_fw_upload(struct nfc_dev *nfc_dev, const char *firmware_name)
+static int hci_fw_download(struct nfc_dev *nfc_dev, const char *firmware_name)
 {
        struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev);
 
-       if (!hdev->ops->fw_upload)
+       if (!hdev->ops->fw_download)
                return -ENOTSUPP;
 
-       return hdev->ops->fw_upload(hdev, firmware_name);
+       return hdev->ops->fw_download(hdev, firmware_name);
 }
 
 static struct nfc_ops hci_nfc_ops = {
@@ -831,7 +831,7 @@ static struct nfc_ops hci_nfc_ops = {
        .im_transceive = hci_transceive,
        .tm_send = hci_tm_send,
        .check_presence = hci_check_presence,
-       .fw_upload = hci_fw_upload,
+       .fw_download = hci_fw_download,
        .discover_se = hci_discover_se,
        .enable_se = hci_enable_se,
        .disable_se = hci_disable_se,
index 2a2416080b4fbfcf2127a4cab2abc755b5188c06..a4f1e42e34818c91eeb2b527c7b547a718454459 100644 (file)
@@ -11,6 +11,7 @@ config NFC_NCI
 
 config NFC_NCI_SPI
        depends on NFC_NCI && SPI
+       select CRC_CCITT
        bool "NCI over SPI protocol support"
        default n
        help
index b05ad909778fe5978677f3f81a31360220f98eb7..f16fd59d41607d80aeeae916ae3d43153a0a5b4e 100644 (file)
@@ -1089,7 +1089,7 @@ exit:
        return rc;
 }
 
-static int nfc_genl_fw_upload(struct sk_buff *skb, struct genl_info *info)
+static int nfc_genl_fw_download(struct sk_buff *skb, struct genl_info *info)
 {
        struct nfc_dev *dev;
        int rc;
@@ -1108,13 +1108,13 @@ static int nfc_genl_fw_upload(struct sk_buff *skb, struct genl_info *info)
        nla_strlcpy(firmware_name, info->attrs[NFC_ATTR_FIRMWARE_NAME],
                    sizeof(firmware_name));
 
-       rc = nfc_fw_upload(dev, firmware_name);
+       rc = nfc_fw_download(dev, firmware_name);
 
        nfc_put_device(dev);
        return rc;
 }
 
-int nfc_genl_fw_upload_done(struct nfc_dev *dev, const char *firmware_name)
+int nfc_genl_fw_download_done(struct nfc_dev *dev, const char *firmware_name)
 {
        struct sk_buff *msg;
        void *hdr;
@@ -1124,7 +1124,7 @@ int nfc_genl_fw_upload_done(struct nfc_dev *dev, const char *firmware_name)
                return -ENOMEM;
 
        hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
-                         NFC_CMD_FW_UPLOAD);
+                         NFC_CMD_FW_DOWNLOAD);
        if (!hdr)
                goto free_msg;
 
@@ -1251,8 +1251,8 @@ static struct genl_ops nfc_genl_ops[] = {
                .policy = nfc_genl_policy,
        },
        {
-               .cmd = NFC_CMD_FW_UPLOAD,
-               .doit = nfc_genl_fw_upload,
+               .cmd = NFC_CMD_FW_DOWNLOAD,
+               .doit = nfc_genl_fw_download,
                .policy = nfc_genl_policy,
        },
        {
index ee85a1fc1b2443d88982ca6985574936b0359292..820a7850c36ac7e49012869a88472a96358e2220 100644 (file)
@@ -123,10 +123,10 @@ static inline void nfc_device_iter_exit(struct class_dev_iter *iter)
        class_dev_iter_exit(iter);
 }
 
-int nfc_fw_upload(struct nfc_dev *dev, const char *firmware_name);
-int nfc_genl_fw_upload_done(struct nfc_dev *dev, const char *firmware_name);
+int nfc_fw_download(struct nfc_dev *dev, const char *firmware_name);
+int nfc_genl_fw_download_done(struct nfc_dev *dev, const char *firmware_name);
 
-int nfc_fw_upload_done(struct nfc_dev *dev, const char *firmware_name);
+int nfc_fw_download_done(struct nfc_dev *dev, const char *firmware_name);
 
 int nfc_dev_up(struct nfc_dev *dev);
 
index 4b66c752eae5d99b2bfe5fa7832a1301d20519ef..4cb28a7f639bcc824ae2f462314d264515f68aa0 100644 (file)
@@ -2638,51 +2638,6 @@ out:
        return err;
 }
 
-static int packet_recv_error(struct sock *sk, struct msghdr *msg, int len)
-{
-       struct sock_exterr_skb *serr;
-       struct sk_buff *skb, *skb2;
-       int copied, err;
-
-       err = -EAGAIN;
-       skb = skb_dequeue(&sk->sk_error_queue);
-       if (skb == NULL)
-               goto out;
-
-       copied = skb->len;
-       if (copied > len) {
-               msg->msg_flags |= MSG_TRUNC;
-               copied = len;
-       }
-       err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
-       if (err)
-               goto out_free_skb;
-
-       sock_recv_timestamp(msg, sk, skb);
-
-       serr = SKB_EXT_ERR(skb);
-       put_cmsg(msg, SOL_PACKET, PACKET_TX_TIMESTAMP,
-                sizeof(serr->ee), &serr->ee);
-
-       msg->msg_flags |= MSG_ERRQUEUE;
-       err = copied;
-
-       /* Reset and regenerate socket error */
-       spin_lock_bh(&sk->sk_error_queue.lock);
-       sk->sk_err = 0;
-       if ((skb2 = skb_peek(&sk->sk_error_queue)) != NULL) {
-               sk->sk_err = SKB_EXT_ERR(skb2)->ee.ee_errno;
-               spin_unlock_bh(&sk->sk_error_queue.lock);
-               sk->sk_error_report(sk);
-       } else
-               spin_unlock_bh(&sk->sk_error_queue.lock);
-
-out_free_skb:
-       kfree_skb(skb);
-out:
-       return err;
-}
-
 /*
  *     Pull a packet from our receive queue and hand it to the user.
  *     If necessary we block.
@@ -2708,7 +2663,8 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
 #endif
 
        if (flags & MSG_ERRQUEUE) {
-               err = packet_recv_error(sk, msg, len);
+               err = sock_recv_errqueue(sk, msg, len,
+                                        SOL_PACKET, PACKET_TX_TIMESTAMP);
                goto out;
        }
 
index ca8e0a57d945dabeb51147f338cef363672040d5..1f9c31411f1998dec927fccf05362f09408558b4 100644 (file)
@@ -605,6 +605,7 @@ static int atm_tc_dump_class(struct Qdisc *sch, unsigned long cl,
                struct sockaddr_atmpvc pvc;
                int state;
 
+               memset(&pvc, 0, sizeof(pvc));
                pvc.sap_family = AF_ATMPVC;
                pvc.sap_addr.itf = flow->vcc->dev ? flow->vcc->dev->number : -1;
                pvc.sap_addr.vpi = flow->vcc->vpi;
index 71a568862557c26cb9fd97bfbd26531b55ad4283..7a42c81a19ebe55f0b6a137f89c55b46314f8cd7 100644 (file)
@@ -1465,6 +1465,7 @@ static int cbq_dump_wrr(struct sk_buff *skb, struct cbq_class *cl)
        unsigned char *b = skb_tail_pointer(skb);
        struct tc_cbq_wrropt opt;
 
+       memset(&opt, 0, sizeof(opt));
        opt.flags = 0;
        opt.allot = cl->allot;
        opt.priority = cl->priority + 1;
index 82f6016d89abac391a8f0c03fdda7be6db2372b7..a6d788d45216a6f286e5aaea0cdb0587cd0f7848 100644 (file)
@@ -412,12 +412,9 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 
        /* If a delay is expected, orphan the skb. (orphaning usually takes
         * place at TX completion time, so _before_ the link transit delay)
-        * Ideally, this orphaning should be done after the rate limiting
-        * module, because this breaks TCP Small Queue, and other mechanisms
-        * based on socket sk_wmem_alloc.
         */
        if (q->latency || q->jitter)
-               skb_orphan(skb);
+               skb_orphan_partial(skb);
 
        /*
         * If we need to duplicate packet, then re-insert at top of the
index bce5b79662a62b8bdc5e7c895a6ea4bcd147ed86..e425ba0bd79e03f25dcaa10e3d59884986bc0be7 100644 (file)
@@ -28,7 +28,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email address(es):
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
index ba1dfc3f8def25701bca3546c883677b03088f5f..3aab967081be5a15ec86496201033925612a4c14 100644 (file)
@@ -22,7 +22,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email address(es):
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
index 64977ea0f9c55e02988377ef6e2de73693607dea..f34ce8bc13950885d0aa1bbc4293c49bf3ee9746 100644 (file)
@@ -27,7 +27,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email address(es):
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
index 5780565f5b7d0c885faacf86d96a742e1ebbdae5..b50b90c16a861a55d25766f96942543d7b0192c9 100644 (file)
@@ -24,7 +24,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email address(es):
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
index c0044019db9eca2b84eaa9b11f28500bf0fb4086..f4bebdadf007c2d09d59ff7fbca939b1a688ec00 100644 (file)
@@ -25,7 +25,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email address(es):
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
index f4998780d6df1171f4f1e616fc328dd92431c030..44aa4e7543a9f2d8d8ff6582f4f3f661e8bc5887 100644 (file)
@@ -28,7 +28,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email address(es):
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
index 9e3d257de0e0814274cf852ae883835bb4c72eac..825b7543a43638ac4d5fa2c30266d4560c5f8407 100644 (file)
@@ -29,7 +29,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email address(es):
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
index 3fa4d858c35a508b56cf56bce9a3c0078c6379c0..fa91aff0238874ae21682c87abc27a640cf19401 100644 (file)
@@ -29,7 +29,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email address(es):
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
@@ -87,15 +87,7 @@ static inline int sctp_rcv_checksum(struct net *net, struct sk_buff *skb)
 {
        struct sctphdr *sh = sctp_hdr(skb);
        __le32 cmp = sh->checksum;
-       struct sk_buff *list;
-       __le32 val;
-       __u32 tmp = sctp_start_cksum((__u8 *)sh, skb_headlen(skb));
-
-       skb_walk_frags(skb, list)
-               tmp = sctp_update_cksum((__u8 *)list->data, skb_headlen(list),
-                                       tmp);
-
-       val = sctp_end_cksum(tmp);
+       __le32 val = sctp_compute_cksum(skb, 0);
 
        if (val != cmp) {
                /* CRC failure, dump it. */
index cb25f040fed03d85d7bf7b9b7248678655e1a716..e70f60ae92efb00f95aba528a4159ab3d82cba42 100644 (file)
@@ -30,7 +30,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email address(es):
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
index 09ffcc912d236426b5c5f7724d7145db31b061bf..85d688f59e6ae295fb4316b74be36a70ef3a3b92 100644 (file)
@@ -27,7 +27,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email address(es):
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
index fe012c44f8dff15e4882165e2718b11f919cf260..aec346cbed6726001d2d40d35fcb44f9d5945f7f 100644 (file)
@@ -26,7 +26,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email address(es):
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
index a46d1eb41762801e2d95011bf3af8327c57ebac2..5a55c55d71ad53245f91120a84df0c2e7661c38b 100644 (file)
@@ -26,7 +26,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email address(es):
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
index ef9e2bbc0f2f8d1dc497166b16bb6ea1d96c1124..51313233e6353037df84c8884852561fd4518a94 100644 (file)
@@ -28,7 +28,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email address(es):
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
index 794bb14decdea60ec58e68a59bc5a6b2feda4a01..31fa437da117026fc442ed0513e2c05f52282831 100644 (file)
@@ -29,7 +29,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email address(es):
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
index 62526c4770505e0f741123bd009e91a90781f587..aff0cac45b644add097033483a23072a40d6440f 100644 (file)
@@ -22,7 +22,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email address(es):
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
index 4a17494d736c4b6a50f0e838971204e1e901de43..b52ec251010155793c11e49f88ff7dbf4f94c95e 100644 (file)
@@ -29,7 +29,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email address(es):
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
@@ -1547,7 +1547,7 @@ module_exit(sctp_exit);
  */
 MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-132");
 MODULE_ALIAS("net-pf-" __stringify(PF_INET6) "-proto-132");
-MODULE_AUTHOR("Linux Kernel SCTP developers <lksctp-developers@lists.sourceforge.net>");
+MODULE_AUTHOR("Linux Kernel SCTP developers <linux-sctp@vger.kernel.org>");
 MODULE_DESCRIPTION("Support for the SCTP protocol (RFC2960)");
 module_param_named(no_checksums, sctp_checksum_disable, bool, 0644);
 MODULE_PARM_DESC(no_checksums, "Disable checksums computing and verification");
index 362ae6e2fd93a6e145fefb15e5f6e5cf4579204b..780a2d4b98a2390a11773fb1d698417ca59fec40 100644 (file)
@@ -29,7 +29,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email address(es):
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
index 9da68852ee94fbf0a7dcb02b61ba90700d18f77c..f1f3aac3f3bb24131db8480dabdad975991be8a2 100644 (file)
@@ -28,7 +28,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email address(es):
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
index f6b7109195a629563b7a49a06e32847fd3b23984..93271f0966c619e7029766d27bc575ae1a167f7a 100644 (file)
@@ -28,7 +28,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email address(es):
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
index 84d98d8a5a7417bd92ea919c56e0f8033073a6c4..64ea5fd87eb294c47228d62f1135e4380084a4fe 100644 (file)
@@ -28,7 +28,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email address(es):
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
index c6670d2e3f8d1bfa7c7fd0cef617de4944ca95e0..02457123bdee9a03b7addf30ef1bc09d1a25cb6f 100644 (file)
@@ -34,7 +34,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email address(es):
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
index da860352380872ad1964af228906178bf8b56531..72b5939101bb889b25adbb15fa6ee14a7f7ce8a5 100644 (file)
@@ -24,7 +24,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email address(es):
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
index 9a5c4c9eddafa0e4f91cabb56847c8c80bf8b59b..190674702b202c885c8c9a3d7e7304e8f3871216 100644 (file)
@@ -25,7 +25,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email address(es):
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
index bdbbc3fd7c14e9fa2c31d4faf7de9b7b64540292..9602c52aa61716df1f6bfcfacd34701aaf6c4ba2 100644 (file)
@@ -30,7 +30,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email address(es):
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
index b46019568a86d15c71dc805c8d1b3e560866d726..0eff8667d4c7f83f128339454fc99ddcb9c5803f 100644 (file)
@@ -27,7 +27,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email address(es):
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
index 44a45dbee4df37e835b258cb551e333aeb7582b9..c07624fca7e5e6680f51770d9e47cc193482749e 100644 (file)
@@ -28,7 +28,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email address(es):
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
index 04e3d470f877e51cc3238a3939595c1d90b83b37..2cdb3010f50f4f9cea6fd39f3dbf45abf06eb20e 100644 (file)
@@ -27,7 +27,7 @@
  *
  * Please send any bug reports or fixes you make to the
  * email address(es):
- *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *    lksctp developers <linux-sctp@vger.kernel.org>
  *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
index 829b460acb87e61e88928f596589b51b0947411d..b2d7c629eeb9f2de785600ed189080af9be02a3e 100644 (file)
 #include <linux/atalk.h>
 #include <net/busy_poll.h>
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
 unsigned int sysctl_net_busy_read __read_mostly;
 unsigned int sysctl_net_busy_poll __read_mostly;
 #endif
index 406859cc68aa90073ef237e91e0aa67116adcf33..017aedc8a7a1e9fe6d5e012342754e25c8a74260 100644 (file)
@@ -480,23 +480,6 @@ static const struct dentry_operations rpc_dentry_operations = {
        .d_delete = rpc_delete_dentry,
 };
 
-/*
- * Lookup the data. This is trivial - if the dentry didn't already
- * exist, we know it is negative.
- */
-static struct dentry *
-rpc_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
-{
-       if (dentry->d_name.len > NAME_MAX)
-               return ERR_PTR(-ENAMETOOLONG);
-       d_add(dentry, NULL);
-       return NULL;
-}
-
-static const struct inode_operations rpc_dir_inode_operations = {
-       .lookup         = rpc_lookup,
-};
-
 static struct inode *
 rpc_get_inode(struct super_block *sb, umode_t mode)
 {
@@ -509,7 +492,7 @@ rpc_get_inode(struct super_block *sb, umode_t mode)
        switch (mode & S_IFMT) {
        case S_IFDIR:
                inode->i_fop = &simple_dir_operations;
-               inode->i_op = &rpc_dir_inode_operations;
+               inode->i_op = &simple_dir_inode_operations;
                inc_nlink(inode);
        default:
                break;
index 305374d4fb985ec4942040447f91e8d8277ea10d..0da6785ec15a7474b318b6eff48f14c0f437b192 100644 (file)
@@ -442,7 +442,7 @@ static void svc_tcp_write_space(struct sock *sk)
 {
        struct socket *sock = sk->sk_socket;
 
-       if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk) && sock)
+       if (sk_stream_is_writeable(sk) && sock)
                clear_bit(SOCK_NOSPACE, &sock->flags);
        svc_write_space(sk);
 }
index ddf0602603bdef4ac0a6ad29a9815bae56f04626..d6656d7768f4e689e94aca67189a0634bd950fad 100644 (file)
@@ -1602,7 +1602,7 @@ static void xs_tcp_write_space(struct sock *sk)
        read_lock_bh(&sk->sk_callback_lock);
 
        /* from net/core/stream.c:sk_stream_write_space */
-       if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk))
+       if (sk_stream_is_writeable(sk))
                xs_write_space(sk);
 
        read_unlock_bh(&sk->sk_callback_lock);
index 19da5abe0fa6fb1ebcf185357bd46489310d9dc7..fd3fa57a410e18393aa6cc20136fcaa28c0f7e22 100644 (file)
@@ -355,8 +355,12 @@ static int tipc_open_listening_sock(struct tipc_server *s)
                return PTR_ERR(con);
 
        sock = tipc_create_listen_sock(con);
-       if (!sock)
+       if (!sock) {
+               idr_remove(&s->conn_idr, con->conid);
+               s->idr_in_use--;
+               kfree(con);
                return -EINVAL;
+       }
 
        tipc_register_callbacks(sock, con);
        return 0;
@@ -563,9 +567,14 @@ int tipc_server_start(struct tipc_server *s)
                kmem_cache_destroy(s->rcvbuf_cache);
                return ret;
        }
+       ret = tipc_open_listening_sock(s);
+       if (ret < 0) {
+               tipc_work_stop(s);
+               kmem_cache_destroy(s->rcvbuf_cache);
+               return ret;
+       }
        s->enabled = 1;
-
-       return tipc_open_listening_sock(s);
+       return ret;
 }
 
 void tipc_server_stop(struct tipc_server *s)
index 593071dabd1cc7477169b24bc31979d8590465b6..57896eee1c254b2ffb6b46aa35f5ace714a1d15c 100644 (file)
@@ -96,8 +96,7 @@
 #include <linux/wait.h>
 #include <linux/workqueue.h>
 #include <net/sock.h>
-
-#include "af_vsock.h"
+#include <net/af_vsock.h>
 
 static int __vsock_bind(struct sock *sk, struct sockaddr_vm *addr);
 static void vsock_sk_destruct(struct sock *sk);
index ffc11df02af22cf90c03df730110ea2a96f033cb..9d6986634e0bfaf1a4431cc8f6fc015f212e7042 100644 (file)
@@ -34,8 +34,8 @@
 #include <linux/wait.h>
 #include <linux/workqueue.h>
 #include <net/sock.h>
+#include <net/af_vsock.h>
 
-#include "af_vsock.h"
 #include "vmci_transport_notify.h"
 
 static int vmci_transport_recv_dgram_cb(void *data, struct vmci_datagram *dg);
index fd88ea8924e4dd89d8f0dc7939e5ccc75e39a747..ce6c9623d5f069029ce58294bcc7de9bc3728fcd 100644 (file)
@@ -19,8 +19,8 @@
 #include <linux/vmw_vmci_defs.h>
 #include <linux/vmw_vmci_api.h>
 
-#include "vsock_addr.h"
-#include "af_vsock.h"
+#include <net/vsock_addr.h>
+#include <net/af_vsock.h>
 
 /* If the packet format changes in a release then this should change too. */
 #define VMCI_TRANSPORT_PACKET_VERSION 1
index ec2611b4ea0ee4fc073926c9a33347ace8de9e4f..82486ee55eaca4cc4f4b1cb414cc848c1239ec46 100644 (file)
@@ -17,8 +17,7 @@
 #include <linux/socket.h>
 #include <linux/stddef.h>
 #include <net/sock.h>
-
-#include "vsock_addr.h"
+#include <net/vsock_addr.h>
 
 void vsock_addr_init(struct sockaddr_vm *addr, u32 cid, u32 port)
 {
index 4f9f216665e9d4d6753172f3c14d7bbdd3f53154..389a3f2ee4640105f6e76c6e6075154c56183df8 100644 (file)
@@ -462,6 +462,14 @@ int wiphy_register(struct wiphy *wiphy)
                return -EINVAL;
 #endif
 
+       if (WARN_ON(wiphy->coalesce &&
+                   (!wiphy->coalesce->n_rules ||
+                    !wiphy->coalesce->n_patterns) &&
+                   (!wiphy->coalesce->pattern_min_len ||
+                    wiphy->coalesce->pattern_min_len >
+                       wiphy->coalesce->pattern_max_len)))
+               return -EINVAL;
+
        if (WARN_ON(wiphy->ap_sme_capa &&
                    !(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME)))
                return -EINVAL;
@@ -668,6 +676,7 @@ void wiphy_unregister(struct wiphy *wiphy)
                rdev_set_wakeup(rdev, false);
 #endif
        cfg80211_rdev_free_wowlan(rdev);
+       cfg80211_rdev_free_coalesce(rdev);
 }
 EXPORT_SYMBOL(wiphy_unregister);
 
index a6b45bf00f3357292a1ad6e3cc5a08fd6faf9a7a..9ad43c619c54830f915193daa60eadef92b5bda5 100644 (file)
@@ -79,6 +79,8 @@ struct cfg80211_registered_device {
        /* netlink port which started critical protocol (0 means not started) */
        u32 crit_proto_nlportid;
 
+       struct cfg80211_coalesce *coalesce;
+
        /* must be last because of the way we do wiphy_priv(),
         * and it should at least be aligned to NETDEV_ALIGN */
        struct wiphy wiphy __aligned(NETDEV_ALIGN);
index 30c49202ee4d12804b78bf4cc26e2766c4cc029e..0553fd4d85aeb4b9338d2661ba020448105a68e9 100644 (file)
@@ -167,9 +167,12 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
         * basic rates
         */
        if (!setup->basic_rates) {
+               enum nl80211_bss_scan_width scan_width;
                struct ieee80211_supported_band *sband =
                                rdev->wiphy.bands[setup->chandef.chan->band];
-               setup->basic_rates = ieee80211_mandatory_rates(sband);
+               scan_width = cfg80211_chandef_to_scan_width(&setup->chandef);
+               setup->basic_rates = ieee80211_mandatory_rates(sband,
+                                                              scan_width);
        }
 
        if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef))
index 1cc47aca7f05baee3e7ffdf18a4e002b2d62279d..160c1f7c6091260ffcb3a495179060e1521de92b 100644 (file)
@@ -403,6 +403,14 @@ nl80211_wowlan_tcp_policy[NUM_NL80211_WOWLAN_TCP] = {
        [NL80211_WOWLAN_TCP_WAKE_MASK] = { .len = 1 },
 };
 
+/* policy for coalesce rule attributes */
+static const struct nla_policy
+nl80211_coalesce_policy[NUM_NL80211_ATTR_COALESCE_RULE] = {
+       [NL80211_ATTR_COALESCE_RULE_DELAY] = { .type = NLA_U32 },
+       [NL80211_ATTR_COALESCE_RULE_CONDITION] = { .type = NLA_U32 },
+       [NL80211_ATTR_COALESCE_RULE_PKT_PATTERN] = { .type = NLA_NESTED },
+};
+
 /* policy for GTK rekey offload attributes */
 static const struct nla_policy
 nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = {
@@ -974,7 +982,7 @@ static int nl80211_send_wowlan(struct sk_buff *msg,
                return -ENOBUFS;
 
        if (dev->wiphy.wowlan->n_patterns) {
-               struct nl80211_wowlan_pattern_support pat = {
+               struct nl80211_pattern_support pat = {
                        .max_patterns = dev->wiphy.wowlan->n_patterns,
                        .min_pattern_len = dev->wiphy.wowlan->pattern_min_len,
                        .max_pattern_len = dev->wiphy.wowlan->pattern_max_len,
@@ -995,6 +1003,27 @@ static int nl80211_send_wowlan(struct sk_buff *msg,
 }
 #endif
 
+static int nl80211_send_coalesce(struct sk_buff *msg,
+                                struct cfg80211_registered_device *dev)
+{
+       struct nl80211_coalesce_rule_support rule;
+
+       if (!dev->wiphy.coalesce)
+               return 0;
+
+       rule.max_rules = dev->wiphy.coalesce->n_rules;
+       rule.max_delay = dev->wiphy.coalesce->max_delay;
+       rule.pat.max_patterns = dev->wiphy.coalesce->n_patterns;
+       rule.pat.min_pattern_len = dev->wiphy.coalesce->pattern_min_len;
+       rule.pat.max_pattern_len = dev->wiphy.coalesce->pattern_max_len;
+       rule.pat.max_pkt_offset = dev->wiphy.coalesce->max_pkt_offset;
+
+       if (nla_put(msg, NL80211_ATTR_COALESCE_RULE, sizeof(rule), &rule))
+               return -ENOBUFS;
+
+       return 0;
+}
+
 static int nl80211_send_band_rateinfo(struct sk_buff *msg,
                                      struct ieee80211_supported_band *sband)
 {
@@ -1513,6 +1542,12 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
                            dev->wiphy.vht_capa_mod_mask))
                        goto nla_put_failure;
 
+               state->split_start++;
+               break;
+       case 10:
+               if (nl80211_send_coalesce(msg, dev))
+                       goto nla_put_failure;
+
                /* done */
                state->split_start = 0;
                break;
@@ -4770,9 +4805,9 @@ do {                                                                          \
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding, 0, 1,
                                  mask, NL80211_MESHCONF_FORWARDING,
                                  nla_get_u8);
-       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, 1, 255,
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, -255, 0,
                                  mask, NL80211_MESHCONF_RSSI_THRESHOLD,
-                                 nla_get_u32);
+                                 nla_get_s32);
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg, ht_opmode, 0, 16,
                                  mask, NL80211_MESHCONF_HT_OPMODE,
                                  nla_get_u16);
@@ -5639,6 +5674,7 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
                goto nla_put_failure;
        if (nla_put_u16(msg, NL80211_BSS_CAPABILITY, res->capability) ||
            nla_put_u32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq) ||
+           nla_put_u32(msg, NL80211_BSS_CHAN_WIDTH, res->scan_width) ||
            nla_put_u32(msg, NL80211_BSS_SEEN_MS_AGO,
                        jiffies_to_msecs(jiffies - intbss->ts)))
                goto nla_put_failure;
@@ -6319,6 +6355,8 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
                return -EINVAL;
 
        switch (ibss.chandef.width) {
+       case NL80211_CHAN_WIDTH_5:
+       case NL80211_CHAN_WIDTH_10:
        case NL80211_CHAN_WIDTH_20_NOHT:
                break;
        case NL80211_CHAN_WIDTH_20:
@@ -6346,6 +6384,19 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
                        return err;
        }
 
+       if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
+               memcpy(&ibss.ht_capa_mask,
+                      nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
+                      sizeof(ibss.ht_capa_mask));
+
+       if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
+               if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
+                       return -EINVAL;
+               memcpy(&ibss.ht_capa,
+                      nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
+                      sizeof(ibss.ht_capa));
+       }
+
        if (info->attrs[NL80211_ATTR_MCAST_RATE] &&
            !nl80211_parse_mcast_rate(rdev, ibss.mcast_rate,
                        nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE])))
@@ -6613,12 +6664,14 @@ EXPORT_SYMBOL(cfg80211_testmode_alloc_event_skb);
 
 void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
 {
+       struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
        void *hdr = ((void **)skb->cb)[1];
        struct nlattr *data = ((void **)skb->cb)[2];
 
        nla_nest_end(skb, data);
        genlmsg_end(skb, hdr);
-       genlmsg_multicast(skb, 0, nl80211_testmode_mcgrp.id, gfp);
+       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), skb, 0,
+                               nl80211_testmode_mcgrp.id, gfp);
 }
 EXPORT_SYMBOL(cfg80211_testmode_event);
 #endif
@@ -7591,12 +7644,11 @@ static int nl80211_send_wowlan_patterns(struct sk_buff *msg,
                if (!nl_pat)
                        return -ENOBUFS;
                pat_len = wowlan->patterns[i].pattern_len;
-               if (nla_put(msg, NL80211_WOWLAN_PKTPAT_MASK,
-                           DIV_ROUND_UP(pat_len, 8),
+               if (nla_put(msg, NL80211_PKTPAT_MASK, DIV_ROUND_UP(pat_len, 8),
                            wowlan->patterns[i].mask) ||
-                   nla_put(msg, NL80211_WOWLAN_PKTPAT_PATTERN,
-                           pat_len, wowlan->patterns[i].pattern) ||
-                   nla_put_u32(msg, NL80211_WOWLAN_PKTPAT_OFFSET,
+                   nla_put(msg, NL80211_PKTPAT_PATTERN, pat_len,
+                           wowlan->patterns[i].pattern) ||
+                   nla_put_u32(msg, NL80211_PKTPAT_OFFSET,
                                wowlan->patterns[i].pkt_offset))
                        return -ENOBUFS;
                nla_nest_end(msg, nl_pat);
@@ -7937,7 +7989,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
                struct nlattr *pat;
                int n_patterns = 0;
                int rem, pat_len, mask_len, pkt_offset;
-               struct nlattr *pat_tb[NUM_NL80211_WOWLAN_PKTPAT];
+               struct nlattr *pat_tb[NUM_NL80211_PKTPAT];
 
                nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
                                    rem)
@@ -7956,26 +8008,25 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
 
                nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
                                    rem) {
-                       nla_parse(pat_tb, MAX_NL80211_WOWLAN_PKTPAT,
-                                 nla_data(pat), nla_len(pat), NULL);
+                       nla_parse(pat_tb, MAX_NL80211_PKTPAT, nla_data(pat),
+                                 nla_len(pat), NULL);
                        err = -EINVAL;
-                       if (!pat_tb[NL80211_WOWLAN_PKTPAT_MASK] ||
-                           !pat_tb[NL80211_WOWLAN_PKTPAT_PATTERN])
+                       if (!pat_tb[NL80211_PKTPAT_MASK] ||
+                           !pat_tb[NL80211_PKTPAT_PATTERN])
                                goto error;
-                       pat_len = nla_len(pat_tb[NL80211_WOWLAN_PKTPAT_PATTERN]);
+                       pat_len = nla_len(pat_tb[NL80211_PKTPAT_PATTERN]);
                        mask_len = DIV_ROUND_UP(pat_len, 8);
-                       if (nla_len(pat_tb[NL80211_WOWLAN_PKTPAT_MASK]) !=
-                           mask_len)
+                       if (nla_len(pat_tb[NL80211_PKTPAT_MASK]) != mask_len)
                                goto error;
                        if (pat_len > wowlan->pattern_max_len ||
                            pat_len < wowlan->pattern_min_len)
                                goto error;
 
-                       if (!pat_tb[NL80211_WOWLAN_PKTPAT_OFFSET])
+                       if (!pat_tb[NL80211_PKTPAT_OFFSET])
                                pkt_offset = 0;
                        else
                                pkt_offset = nla_get_u32(
-                                       pat_tb[NL80211_WOWLAN_PKTPAT_OFFSET]);
+                                       pat_tb[NL80211_PKTPAT_OFFSET]);
                        if (pkt_offset > wowlan->max_pkt_offset)
                                goto error;
                        new_triggers.patterns[i].pkt_offset = pkt_offset;
@@ -7989,11 +8040,11 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
                        new_triggers.patterns[i].pattern =
                                new_triggers.patterns[i].mask + mask_len;
                        memcpy(new_triggers.patterns[i].mask,
-                              nla_data(pat_tb[NL80211_WOWLAN_PKTPAT_MASK]),
+                              nla_data(pat_tb[NL80211_PKTPAT_MASK]),
                               mask_len);
                        new_triggers.patterns[i].pattern_len = pat_len;
                        memcpy(new_triggers.patterns[i].pattern,
-                              nla_data(pat_tb[NL80211_WOWLAN_PKTPAT_PATTERN]),
+                              nla_data(pat_tb[NL80211_PKTPAT_PATTERN]),
                               pat_len);
                        i++;
                }
@@ -8032,6 +8083,264 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
 }
 #endif
 
+static int nl80211_send_coalesce_rules(struct sk_buff *msg,
+                                      struct cfg80211_registered_device *rdev)
+{
+       struct nlattr *nl_pats, *nl_pat, *nl_rule, *nl_rules;
+       int i, j, pat_len;
+       struct cfg80211_coalesce_rules *rule;
+
+       if (!rdev->coalesce->n_rules)
+               return 0;
+
+       nl_rules = nla_nest_start(msg, NL80211_ATTR_COALESCE_RULE);
+       if (!nl_rules)
+               return -ENOBUFS;
+
+       for (i = 0; i < rdev->coalesce->n_rules; i++) {
+               nl_rule = nla_nest_start(msg, i + 1);
+               if (!nl_rule)
+                       return -ENOBUFS;
+
+               rule = &rdev->coalesce->rules[i];
+               if (nla_put_u32(msg, NL80211_ATTR_COALESCE_RULE_DELAY,
+                               rule->delay))
+                       return -ENOBUFS;
+
+               if (nla_put_u32(msg, NL80211_ATTR_COALESCE_RULE_CONDITION,
+                               rule->condition))
+                       return -ENOBUFS;
+
+               nl_pats = nla_nest_start(msg,
+                               NL80211_ATTR_COALESCE_RULE_PKT_PATTERN);
+               if (!nl_pats)
+                       return -ENOBUFS;
+
+               for (j = 0; j < rule->n_patterns; j++) {
+                       nl_pat = nla_nest_start(msg, j + 1);
+                       if (!nl_pat)
+                               return -ENOBUFS;
+                       pat_len = rule->patterns[j].pattern_len;
+                       if (nla_put(msg, NL80211_PKTPAT_MASK,
+                                   DIV_ROUND_UP(pat_len, 8),
+                                   rule->patterns[j].mask) ||
+                           nla_put(msg, NL80211_PKTPAT_PATTERN, pat_len,
+                                   rule->patterns[j].pattern) ||
+                           nla_put_u32(msg, NL80211_PKTPAT_OFFSET,
+                                       rule->patterns[j].pkt_offset))
+                               return -ENOBUFS;
+                       nla_nest_end(msg, nl_pat);
+               }
+               nla_nest_end(msg, nl_pats);
+               nla_nest_end(msg, nl_rule);
+       }
+       nla_nest_end(msg, nl_rules);
+
+       return 0;
+}
+
+static int nl80211_get_coalesce(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct sk_buff *msg;
+       void *hdr;
+
+       if (!rdev->wiphy.coalesce)
+               return -EOPNOTSUPP;
+
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
+       hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
+                            NL80211_CMD_GET_COALESCE);
+       if (!hdr)
+               goto nla_put_failure;
+
+       if (rdev->coalesce && nl80211_send_coalesce_rules(msg, rdev))
+               goto nla_put_failure;
+
+       genlmsg_end(msg, hdr);
+       return genlmsg_reply(msg, info);
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return -ENOBUFS;
+}
+
+void cfg80211_rdev_free_coalesce(struct cfg80211_registered_device *rdev)
+{
+       struct cfg80211_coalesce *coalesce = rdev->coalesce;
+       int i, j;
+       struct cfg80211_coalesce_rules *rule;
+
+       if (!coalesce)
+               return;
+
+       for (i = 0; i < coalesce->n_rules; i++) {
+               rule = &coalesce->rules[i];
+               for (j = 0; j < rule->n_patterns; j++)
+                       kfree(rule->patterns[j].mask);
+               kfree(rule->patterns);
+       }
+       kfree(coalesce->rules);
+       kfree(coalesce);
+       rdev->coalesce = NULL;
+}
+
+static int nl80211_parse_coalesce_rule(struct cfg80211_registered_device *rdev,
+                                      struct nlattr *rule,
+                                      struct cfg80211_coalesce_rules *new_rule)
+{
+       int err, i;
+       const struct wiphy_coalesce_support *coalesce = rdev->wiphy.coalesce;
+       struct nlattr *tb[NUM_NL80211_ATTR_COALESCE_RULE], *pat;
+       int rem, pat_len, mask_len, pkt_offset, n_patterns = 0;
+       struct nlattr *pat_tb[NUM_NL80211_PKTPAT];
+
+       err = nla_parse(tb, NL80211_ATTR_COALESCE_RULE_MAX, nla_data(rule),
+                       nla_len(rule), nl80211_coalesce_policy);
+       if (err)
+               return err;
+
+       if (tb[NL80211_ATTR_COALESCE_RULE_DELAY])
+               new_rule->delay =
+                       nla_get_u32(tb[NL80211_ATTR_COALESCE_RULE_DELAY]);
+       if (new_rule->delay > coalesce->max_delay)
+               return -EINVAL;
+
+       if (tb[NL80211_ATTR_COALESCE_RULE_CONDITION])
+               new_rule->condition =
+                       nla_get_u32(tb[NL80211_ATTR_COALESCE_RULE_CONDITION]);
+       if (new_rule->condition != NL80211_COALESCE_CONDITION_MATCH &&
+           new_rule->condition != NL80211_COALESCE_CONDITION_NO_MATCH)
+               return -EINVAL;
+
+       if (!tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN])
+               return -EINVAL;
+
+       nla_for_each_nested(pat, tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN],
+                           rem)
+               n_patterns++;
+       if (n_patterns > coalesce->n_patterns)
+               return -EINVAL;
+
+       new_rule->patterns = kcalloc(n_patterns, sizeof(new_rule->patterns[0]),
+                                    GFP_KERNEL);
+       if (!new_rule->patterns)
+               return -ENOMEM;
+
+       new_rule->n_patterns = n_patterns;
+       i = 0;
+
+       nla_for_each_nested(pat, tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN],
+                           rem) {
+               nla_parse(pat_tb, MAX_NL80211_PKTPAT, nla_data(pat),
+                         nla_len(pat), NULL);
+               if (!pat_tb[NL80211_PKTPAT_MASK] ||
+                   !pat_tb[NL80211_PKTPAT_PATTERN])
+                       return -EINVAL;
+               pat_len = nla_len(pat_tb[NL80211_PKTPAT_PATTERN]);
+               mask_len = DIV_ROUND_UP(pat_len, 8);
+               if (nla_len(pat_tb[NL80211_PKTPAT_MASK]) != mask_len)
+                       return -EINVAL;
+               if (pat_len > coalesce->pattern_max_len ||
+                   pat_len < coalesce->pattern_min_len)
+                       return -EINVAL;
+
+               if (!pat_tb[NL80211_PKTPAT_OFFSET])
+                       pkt_offset = 0;
+               else
+                       pkt_offset = nla_get_u32(pat_tb[NL80211_PKTPAT_OFFSET]);
+               if (pkt_offset > coalesce->max_pkt_offset)
+                       return -EINVAL;
+               new_rule->patterns[i].pkt_offset = pkt_offset;
+
+               new_rule->patterns[i].mask =
+                       kmalloc(mask_len + pat_len, GFP_KERNEL);
+               if (!new_rule->patterns[i].mask)
+                       return -ENOMEM;
+               new_rule->patterns[i].pattern =
+                       new_rule->patterns[i].mask + mask_len;
+               memcpy(new_rule->patterns[i].mask,
+                      nla_data(pat_tb[NL80211_PKTPAT_MASK]), mask_len);
+               new_rule->patterns[i].pattern_len = pat_len;
+               memcpy(new_rule->patterns[i].pattern,
+                      nla_data(pat_tb[NL80211_PKTPAT_PATTERN]), pat_len);
+               i++;
+       }
+
+       return 0;
+}
+
+static int nl80211_set_coalesce(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       const struct wiphy_coalesce_support *coalesce = rdev->wiphy.coalesce;
+       struct cfg80211_coalesce new_coalesce = {};
+       struct cfg80211_coalesce *n_coalesce;
+       int err, rem_rule, n_rules = 0, i, j;
+       struct nlattr *rule;
+       struct cfg80211_coalesce_rules *tmp_rule;
+
+       if (!rdev->wiphy.coalesce || !rdev->ops->set_coalesce)
+               return -EOPNOTSUPP;
+
+       if (!info->attrs[NL80211_ATTR_COALESCE_RULE]) {
+               cfg80211_rdev_free_coalesce(rdev);
+               rdev->ops->set_coalesce(&rdev->wiphy, NULL);
+               return 0;
+       }
+
+       nla_for_each_nested(rule, info->attrs[NL80211_ATTR_COALESCE_RULE],
+                           rem_rule)
+               n_rules++;
+       if (n_rules > coalesce->n_rules)
+               return -EINVAL;
+
+       new_coalesce.rules = kcalloc(n_rules, sizeof(new_coalesce.rules[0]),
+                                    GFP_KERNEL);
+       if (!new_coalesce.rules)
+               return -ENOMEM;
+
+       new_coalesce.n_rules = n_rules;
+       i = 0;
+
+       nla_for_each_nested(rule, info->attrs[NL80211_ATTR_COALESCE_RULE],
+                           rem_rule) {
+               err = nl80211_parse_coalesce_rule(rdev, rule,
+                                                 &new_coalesce.rules[i]);
+               if (err)
+                       goto error;
+
+               i++;
+       }
+
+       err = rdev->ops->set_coalesce(&rdev->wiphy, &new_coalesce);
+       if (err)
+               goto error;
+
+       n_coalesce = kmemdup(&new_coalesce, sizeof(new_coalesce), GFP_KERNEL);
+       if (!n_coalesce) {
+               err = -ENOMEM;
+               goto error;
+       }
+       cfg80211_rdev_free_coalesce(rdev);
+       rdev->coalesce = n_coalesce;
+
+       return 0;
+error:
+       for (i = 0; i < new_coalesce.n_rules; i++) {
+               tmp_rule = &new_coalesce.rules[i];
+               for (j = 0; j < tmp_rule->n_patterns; j++)
+                       kfree(tmp_rule->patterns[j].mask);
+               kfree(tmp_rule->patterns);
+       }
+       kfree(new_coalesce.rules);
+
+       return err;
+}
+
 static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -9039,6 +9348,21 @@ static struct genl_ops nl80211_ops[] = {
                .flags = GENL_ADMIN_PERM,
                .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
                                  NL80211_FLAG_NEED_RTNL,
+       },
+       {
+               .cmd = NL80211_CMD_GET_COALESCE,
+               .doit = nl80211_get_coalesce,
+               .policy = nl80211_policy,
+               .internal_flags = NL80211_FLAG_NEED_WIPHY |
+                                 NL80211_FLAG_NEED_RTNL,
+       },
+       {
+               .cmd = NL80211_CMD_SET_COALESCE,
+               .doit = nl80211_set_coalesce,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_WIPHY |
+                                 NL80211_FLAG_NEED_RTNL,
        }
 };
 
@@ -10064,7 +10388,8 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
 
        genlmsg_end(msg, hdr);
 
-       genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp);
+       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+                               nl80211_mlme_mcgrp.id, gfp);
        return;
 
  nla_put_failure:
index a4073e808c13c24bca525617d4de3cba8b18874e..44341bf53cfc98767f41899dd73479557fdc26aa 100644 (file)
@@ -74,4 +74,6 @@ nl80211_radar_notify(struct cfg80211_registered_device *rdev,
                     enum nl80211_radar_event event,
                     struct net_device *netdev, gfp_t gfp);
 
+void cfg80211_rdev_free_coalesce(struct cfg80211_registered_device *rdev);
+
 #endif /* __NET_WIRELESS_NL80211_H */
index 5a24c986f34be27e61613f0deb421a35efc61533..de06d5d1287f97b6f6c8a1fd6b3e59371d80ae3e 100644 (file)
@@ -2247,10 +2247,13 @@ int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env)
 
 void wiphy_regulatory_register(struct wiphy *wiphy)
 {
+       struct regulatory_request *lr;
+
        if (!reg_dev_ignore_cell_hint(wiphy))
                reg_num_devs_support_basehint++;
 
-       wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE);
+       lr = get_last_request();
+       wiphy_update_regulatory(wiphy, lr->initiator);
 }
 
 void wiphy_regulatory_deregister(struct wiphy *wiphy)
@@ -2279,7 +2282,9 @@ void wiphy_regulatory_deregister(struct wiphy *wiphy)
 static void reg_timeout_work(struct work_struct *work)
 {
        REG_DBG_PRINT("Timeout while waiting for CRDA to reply, restoring regulatory settings\n");
+       rtnl_lock();
        restore_regulatory_settings(true);
+       rtnl_unlock();
 }
 
 int __init regulatory_init(void)
index ae8c186b50d68510f88e758b959ad663e911a5de..ad1e4068ce06644218e6e005acdc129a1610ae56 100644 (file)
@@ -651,6 +651,8 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *dev,
                        continue;
                if (bss->pub.channel != new->pub.channel)
                        continue;
+               if (bss->pub.scan_width != new->pub.scan_width)
+                       continue;
                if (rcu_access_pointer(bss->pub.beacon_ies))
                        continue;
                ies = rcu_access_pointer(bss->pub.ies);
@@ -870,11 +872,12 @@ cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen,
 
 /* Returned bss is reference counted and must be cleaned up appropriately. */
 struct cfg80211_bss*
-cfg80211_inform_bss(struct wiphy *wiphy,
-                   struct ieee80211_channel *channel,
-                   const u8 *bssid, u64 tsf, u16 capability,
-                   u16 beacon_interval, const u8 *ie, size_t ielen,
-                   s32 signal, gfp_t gfp)
+cfg80211_inform_bss_width(struct wiphy *wiphy,
+                         struct ieee80211_channel *channel,
+                         enum nl80211_bss_scan_width scan_width,
+                         const u8 *bssid, u64 tsf, u16 capability,
+                         u16 beacon_interval, const u8 *ie, size_t ielen,
+                         s32 signal, gfp_t gfp)
 {
        struct cfg80211_bss_ies *ies;
        struct cfg80211_internal_bss tmp = {}, *res;
@@ -892,6 +895,7 @@ cfg80211_inform_bss(struct wiphy *wiphy,
 
        memcpy(tmp.pub.bssid, bssid, ETH_ALEN);
        tmp.pub.channel = channel;
+       tmp.pub.scan_width = scan_width;
        tmp.pub.signal = signal;
        tmp.pub.beacon_interval = beacon_interval;
        tmp.pub.capability = capability;
@@ -924,14 +928,15 @@ cfg80211_inform_bss(struct wiphy *wiphy,
        /* cfg80211_bss_update gives us a referenced result */
        return &res->pub;
 }
-EXPORT_SYMBOL(cfg80211_inform_bss);
+EXPORT_SYMBOL(cfg80211_inform_bss_width);
 
 /* Returned bss is reference counted and must be cleaned up appropriately. */
 struct cfg80211_bss *
-cfg80211_inform_bss_frame(struct wiphy *wiphy,
-                         struct ieee80211_channel *channel,
-                         struct ieee80211_mgmt *mgmt, size_t len,
-                         s32 signal, gfp_t gfp)
+cfg80211_inform_bss_width_frame(struct wiphy *wiphy,
+                               struct ieee80211_channel *channel,
+                               enum nl80211_bss_scan_width scan_width,
+                               struct ieee80211_mgmt *mgmt, size_t len,
+                               s32 signal, gfp_t gfp)
 {
        struct cfg80211_internal_bss tmp = {}, *res;
        struct cfg80211_bss_ies *ies;
@@ -941,7 +946,8 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
        BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) !=
                        offsetof(struct ieee80211_mgmt, u.beacon.variable));
 
-       trace_cfg80211_inform_bss_frame(wiphy, channel, mgmt, len, signal);
+       trace_cfg80211_inform_bss_width_frame(wiphy, channel, scan_width, mgmt,
+                                             len, signal);
 
        if (WARN_ON(!mgmt))
                return NULL;
@@ -976,6 +982,7 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
        
        memcpy(tmp.pub.bssid, mgmt->bssid, ETH_ALEN);
        tmp.pub.channel = channel;
+       tmp.pub.scan_width = scan_width;
        tmp.pub.signal = signal;
        tmp.pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
        tmp.pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
@@ -991,7 +998,7 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
        /* cfg80211_bss_update gives us a referenced result */
        return &res->pub;
 }
-EXPORT_SYMBOL(cfg80211_inform_bss_frame);
+EXPORT_SYMBOL(cfg80211_inform_bss_width_frame);
 
 void cfg80211_ref_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
 {
index 1d3cfb1a3f28b3a74a32c1c629ddbcba7fb30def..81c8a10d743c04fb76981498b42588f9b821f33f 100644 (file)
@@ -34,8 +34,10 @@ struct cfg80211_conn {
                CFG80211_CONN_SCAN_AGAIN,
                CFG80211_CONN_AUTHENTICATE_NEXT,
                CFG80211_CONN_AUTHENTICATING,
+               CFG80211_CONN_AUTH_FAILED,
                CFG80211_CONN_ASSOCIATE_NEXT,
                CFG80211_CONN_ASSOCIATING,
+               CFG80211_CONN_ASSOC_FAILED,
                CFG80211_CONN_DEAUTH,
                CFG80211_CONN_CONNECTED,
        } state;
@@ -164,6 +166,8 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
                                          NULL, 0,
                                          params->key, params->key_len,
                                          params->key_idx, NULL, 0);
+       case CFG80211_CONN_AUTH_FAILED:
+               return -ENOTCONN;
        case CFG80211_CONN_ASSOCIATE_NEXT:
                BUG_ON(!rdev->ops->assoc);
                wdev->conn->state = CFG80211_CONN_ASSOCIATING;
@@ -188,10 +192,17 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
                                             WLAN_REASON_DEAUTH_LEAVING,
                                             false);
                return err;
+       case CFG80211_CONN_ASSOC_FAILED:
+               cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
+                                    NULL, 0,
+                                    WLAN_REASON_DEAUTH_LEAVING, false);
+               return -ENOTCONN;
        case CFG80211_CONN_DEAUTH:
                cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
                                     NULL, 0,
                                     WLAN_REASON_DEAUTH_LEAVING, false);
+               /* free directly, disconnected event already sent */
+               cfg80211_sme_free(wdev);
                return 0;
        default:
                return 0;
@@ -371,7 +382,7 @@ bool cfg80211_sme_rx_assoc_resp(struct wireless_dev *wdev, u16 status)
                return true;
        }
 
-       wdev->conn->state = CFG80211_CONN_DEAUTH;
+       wdev->conn->state = CFG80211_CONN_ASSOC_FAILED;
        schedule_work(&rdev->conn_work);
        return false;
 }
@@ -383,7 +394,13 @@ void cfg80211_sme_deauth(struct wireless_dev *wdev)
 
 void cfg80211_sme_auth_timeout(struct wireless_dev *wdev)
 {
-       cfg80211_sme_free(wdev);
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+
+       if (!wdev->conn)
+               return;
+
+       wdev->conn->state = CFG80211_CONN_AUTH_FAILED;
+       schedule_work(&rdev->conn_work);
 }
 
 void cfg80211_sme_disassoc(struct wireless_dev *wdev)
@@ -399,7 +416,13 @@ void cfg80211_sme_disassoc(struct wireless_dev *wdev)
 
 void cfg80211_sme_assoc_timeout(struct wireless_dev *wdev)
 {
-       cfg80211_sme_disassoc(wdev);
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+
+       if (!wdev->conn)
+               return;
+
+       wdev->conn->state = CFG80211_CONN_ASSOC_FAILED;
+       schedule_work(&rdev->conn_work);
 }
 
 static int cfg80211_sme_connect(struct wireless_dev *wdev,
index e1534baf2ebbe5d0fdc41d4e2d6ceb42fd9630f3..09af6eb426a80fcbda096eaaeef4af9522d63099 100644 (file)
@@ -2391,26 +2391,30 @@ TRACE_EVENT(cfg80211_get_bss,
                  __entry->capa_mask, __entry->capa_val)
 );
 
-TRACE_EVENT(cfg80211_inform_bss_frame,
+TRACE_EVENT(cfg80211_inform_bss_width_frame,
        TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *channel,
+                enum nl80211_bss_scan_width scan_width,
                 struct ieee80211_mgmt *mgmt, size_t len,
                 s32 signal),
-       TP_ARGS(wiphy, channel, mgmt, len, signal),
+       TP_ARGS(wiphy, channel, scan_width, mgmt, len, signal),
        TP_STRUCT__entry(
                WIPHY_ENTRY
                CHAN_ENTRY
+               __field(enum nl80211_bss_scan_width, scan_width)
                __dynamic_array(u8, mgmt, len)
                __field(s32, signal)
        ),
        TP_fast_assign(
                WIPHY_ASSIGN;
                CHAN_ASSIGN(channel);
+               __entry->scan_width = scan_width;
                if (mgmt)
                        memcpy(__get_dynamic_array(mgmt), mgmt, len);
                __entry->signal = signal;
        ),
-       TP_printk(WIPHY_PR_FMT ", " CHAN_PR_FMT "signal: %d",
-                 WIPHY_PR_ARG, CHAN_PR_ARG, __entry->signal)
+       TP_printk(WIPHY_PR_FMT ", " CHAN_PR_FMT "(scan_width: %d) signal: %d",
+                 WIPHY_PR_ARG, CHAN_PR_ARG, __entry->scan_width,
+                 __entry->signal)
 );
 
 DECLARE_EVENT_CLASS(cfg80211_bss_evt,
index 74458b7f61eb8bcd00eadd0cd4c24a380c589fb1..ce090c1c5e4fdb36459c4f6fde6b5af241a75f0e 100644 (file)
@@ -33,7 +33,8 @@ ieee80211_get_response_rate(struct ieee80211_supported_band *sband,
 }
 EXPORT_SYMBOL(ieee80211_get_response_rate);
 
-u32 ieee80211_mandatory_rates(struct ieee80211_supported_band *sband)
+u32 ieee80211_mandatory_rates(struct ieee80211_supported_band *sband,
+                             enum nl80211_bss_scan_width scan_width)
 {
        struct ieee80211_rate *bitrates;
        u32 mandatory_rates = 0;
@@ -43,10 +44,15 @@ u32 ieee80211_mandatory_rates(struct ieee80211_supported_band *sband)
        if (WARN_ON(!sband))
                return 1;
 
-       if (sband->band == IEEE80211_BAND_2GHZ)
-               mandatory_flag = IEEE80211_RATE_MANDATORY_B;
-       else
+       if (sband->band == IEEE80211_BAND_2GHZ) {
+               if (scan_width == NL80211_BSS_CHAN_WIDTH_5 ||
+                   scan_width == NL80211_BSS_CHAN_WIDTH_10)
+                       mandatory_flag = IEEE80211_RATE_MANDATORY_G;
+               else
+                       mandatory_flag = IEEE80211_RATE_MANDATORY_B;
+       } else {
                mandatory_flag = IEEE80211_RATE_MANDATORY_A;
+       }
 
        bitrates = sband->bitrates;
        for (i = 0; i < sband->n_bitrates; i++)
index e52cab3591dd78c373274bb64420f87383775e8c..d8da6b8c6ba8b980c12564476c06f29d51f21ea0 100644 (file)
@@ -660,7 +660,13 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
        xfrm_pol_hold(policy);
        net->xfrm.policy_count[dir]++;
        atomic_inc(&flow_cache_genid);
-       rt_genid_bump(net);
+
+       /* After previous checking, family can either be AF_INET or AF_INET6 */
+       if (policy->family == AF_INET)
+               rt_genid_bump_ipv4(net);
+       else
+               rt_genid_bump_ipv6(net);
+
        if (delpol) {
                xfrm_policy_requeue(delpol, policy);
                __xfrm_policy_unlink(delpol, dir);
index 78f66fa92449c92865dfa8314020854ed704744f..b2cd806c0be344e0f94b55a64cdc172ae605b87c 100644 (file)
@@ -990,11 +990,13 @@ void xfrm_state_insert(struct xfrm_state *x)
 EXPORT_SYMBOL(xfrm_state_insert);
 
 /* xfrm_state_lock is held */
-static struct xfrm_state *__find_acq_core(struct net *net, struct xfrm_mark *m,
+static struct xfrm_state *__find_acq_core(struct net *net,
+                                         const struct xfrm_mark *m,
                                          unsigned short family, u8 mode,
                                          u32 reqid, u8 proto,
                                          const xfrm_address_t *daddr,
-                                         const xfrm_address_t *saddr, int create)
+                                         const xfrm_address_t *saddr,
+                                         int create)
 {
        unsigned int h = xfrm_dst_hash(net, daddr, saddr, reqid, family);
        struct xfrm_state *x;
@@ -1399,9 +1401,9 @@ xfrm_state_lookup_byaddr(struct net *net, u32 mark,
 EXPORT_SYMBOL(xfrm_state_lookup_byaddr);
 
 struct xfrm_state *
-xfrm_find_acq(struct net *net, struct xfrm_mark *mark, u8 mode, u32 reqid, u8 proto,
-             const xfrm_address_t *daddr, const xfrm_address_t *saddr,
-             int create, unsigned short family)
+xfrm_find_acq(struct net *net, const struct xfrm_mark *mark, u8 mode, u32 reqid,
+             u8 proto, const xfrm_address_t *daddr,
+             const xfrm_address_t *saddr, int create, unsigned short family)
 {
        struct xfrm_state *x;
 
index 6c9c45f9fbbac432a877112f4243f483ed01e9e3..2c3963165a0d83f45b2d180361e12e4542588302 100644 (file)
@@ -401,8 +401,8 @@ static void search_conf(void)
        struct subtitle_part stpart;
 
        title = str_new();
-       str_printf( &title, _("Enter %s (sub)string or regexp to search for "
-                             "(with or without \"%s\")"), CONFIG_, CONFIG_);
+       str_printf( &title, _("Enter (sub)string or regexp to search for "
+                             "(with or without \"%s\")"), CONFIG_);
 
 again:
        dialog_clear();
index 7975d8d258c3f6cb8848a137a3f263a4f16f1d20..4fbecd2473bc51904629056eaa8bacb7b42fb660 100644 (file)
@@ -695,8 +695,8 @@ static void search_conf(void)
        int dres;
 
        title = str_new();
-       str_printf( &title, _("Enter %s (sub)string or regexp to search for "
-                             "(with or without \"%s\")"), CONFIG_, CONFIG_);
+       str_printf( &title, _("Enter (sub)string or regexp to search for "
+                             "(with or without \"%s\")"), CONFIG_);
 
 again:
        dres = dialog_inputbox(main_window,
index d550300ec00c34e5b1748478c6381341e9412e0b..a76b8fd1db4f17d3b8252a5a82b77b4122e460a7 100644 (file)
@@ -963,11 +963,11 @@ struct sym_match {
  * - first, symbols that match exactly
  * - then, alphabetical sort
  */
-static int sym_rel_comp( const void *sym1, const void *sym2 )
+static int sym_rel_comp(const void *sym1, const void *sym2)
 {
-       struct sym_match *s1 = *(struct sym_match **)sym1;
-       struct sym_match *s2 = *(struct sym_match **)sym2;
-       int l1, l2;
+       const struct sym_match *s1 = sym1;
+       const struct sym_match *s2 = sym2;
+       int exact1, exact2;
 
        /* Exact match:
         * - if matched length on symbol s1 is the length of that symbol,
@@ -978,11 +978,11 @@ static int sym_rel_comp( const void *sym1, const void *sym2 )
         * exactly; if this is the case, we can't decide which comes first,
         * and we fallback to sorting alphabetically.
         */
-       l1 = s1->eo - s1->so;
-       l2 = s2->eo - s2->so;
-       if (l1 == strlen(s1->sym->name) && l2 != strlen(s2->sym->name))
+       exact1 = (s1->eo - s1->so) == strlen(s1->sym->name);
+       exact2 = (s2->eo - s2->so) == strlen(s2->sym->name);
+       if (exact1 && !exact2)
                return -1;
-       if (l1 != strlen(s1->sym->name) && l2 == strlen(s2->sym->name))
+       if (!exact1 && exact2)
                return 1;
 
        /* As a fallback, sort symbols alphabetically */
@@ -992,7 +992,7 @@ static int sym_rel_comp( const void *sym1, const void *sym2 )
 struct symbol **sym_re_search(const char *pattern)
 {
        struct symbol *sym, **sym_arr = NULL;
-       struct sym_match **sym_match_arr = NULL;
+       struct sym_match *sym_match_arr = NULL;
        int i, cnt, size;
        regex_t re;
        regmatch_t match[1];
@@ -1005,47 +1005,38 @@ struct symbol **sym_re_search(const char *pattern)
                return NULL;
 
        for_all_symbols(i, sym) {
-               struct sym_match *tmp_sym_match;
                if (sym->flags & SYMBOL_CONST || !sym->name)
                        continue;
                if (regexec(&re, sym->name, 1, match, 0))
                        continue;
-               if (cnt + 1 >= size) {
+               if (cnt >= size) {
                        void *tmp;
                        size += 16;
-                       tmp = realloc(sym_match_arr, size * sizeof(struct sym_match *));
-                       if (!tmp) {
+                       tmp = realloc(sym_match_arr, size * sizeof(struct sym_match));
+                       if (!tmp)
                                goto sym_re_search_free;
-                       }
                        sym_match_arr = tmp;
                }
                sym_calc_value(sym);
-               tmp_sym_match = (struct sym_match*)malloc(sizeof(struct sym_match));
-               if (!tmp_sym_match)
-                       goto sym_re_search_free;
-               tmp_sym_match->sym = sym;
-               /* As regexec return 0, we know we have a match, so
+               /* As regexec returned 0, we know we have a match, so
                 * we can use match[0].rm_[se]o without further checks
                 */
-               tmp_sym_match->so = match[0].rm_so;
-               tmp_sym_match->eo = match[0].rm_eo;
-               sym_match_arr[cnt++] = tmp_sym_match;
+               sym_match_arr[cnt].so = match[0].rm_so;
+               sym_match_arr[cnt].eo = match[0].rm_eo;
+               sym_match_arr[cnt++].sym = sym;
        }
        if (sym_match_arr) {
-               qsort(sym_match_arr, cnt, sizeof(struct sym_match*), sym_rel_comp);
+               qsort(sym_match_arr, cnt, sizeof(struct sym_match), sym_rel_comp);
                sym_arr = malloc((cnt+1) * sizeof(struct symbol));
                if (!sym_arr)
                        goto sym_re_search_free;
                for (i = 0; i < cnt; i++)
-                       sym_arr[i] = sym_match_arr[i]->sym;
+                       sym_arr[i] = sym_match_arr[i].sym;
                sym_arr[cnt] = NULL;
        }
 sym_re_search_free:
-       if (sym_match_arr) {
-               for (i = 0; i < cnt; i++)
-                       free(sym_match_arr[i]);
-               free(sym_match_arr);
-       }
+       /* sym_match_arr can be NULL if no match, but free(NULL) is OK */
+       free(sym_match_arr);
        regfree(&re);
 
        return sym_arr;
index acb86507828aaba1304594588959fbfc2804c528..de899238f34a6c8ebcbb26234d7953e107986a9c 100644 (file)
@@ -41,9 +41,9 @@ create_package() {
        parisc*)
                debarch=hppa ;;
        mips*)
-               debarch=mips$(grep -q CPU_LITTLE_ENDIAN=y .config && echo el) ;;
+               debarch=mips$(grep -q CPU_LITTLE_ENDIAN=y $KCONFIG_CONFIG && echo el) ;;
        arm*)
-               debarch=arm$(grep -q CONFIG_AEABI=y .config && echo el) ;;
+               debarch=arm$(grep -q CONFIG_AEABI=y $KCONFIG_CONFIG && echo el) ;;
        *)
                echo "" >&2
                echo "** ** **  WARNING  ** ** **" >&2
@@ -78,17 +78,35 @@ tmpdir="$objtree/debian/tmp"
 fwdir="$objtree/debian/fwtmp"
 kernel_headers_dir="$objtree/debian/hdrtmp"
 libc_headers_dir="$objtree/debian/headertmp"
+dbg_dir="$objtree/debian/dbgtmp"
 packagename=linux-image-$version
 fwpackagename=linux-firmware-image
 kernel_headers_packagename=linux-headers-$version
 libc_headers_packagename=linux-libc-dev
+dbg_packagename=$packagename-dbg
 
 if [ "$ARCH" = "um" ] ; then
        packagename=user-mode-linux-$version
 fi
 
+# Not all arches have the same installed path in debian
+# XXX: have each arch Makefile export a variable of the canonical image install
+# path instead
+case $ARCH in
+um)
+       installed_image_path="usr/bin/linux-$version"
+       ;;
+parisc|mips|powerpc)
+       installed_image_path="boot/vmlinux-$version"
+       ;;
+*)
+       installed_image_path="boot/vmlinuz-$version"
+esac
+
+BUILD_DEBUG="$(grep -s '^CONFIG_DEBUG_INFO=y' $KCONFIG_CONFIG || true)"
+
 # Setup the directory structure
-rm -rf "$tmpdir" "$fwdir" "$kernel_headers_dir" "$libc_headers_dir"
+rm -rf "$tmpdir" "$fwdir" "$kernel_headers_dir" "$libc_headers_dir" "$dbg_dir"
 mkdir -m 755 -p "$tmpdir/DEBIAN"
 mkdir -p  "$tmpdir/lib" "$tmpdir/boot" "$tmpdir/usr/share/doc/$packagename"
 mkdir -m 755 -p "$fwdir/DEBIAN"
@@ -101,26 +119,29 @@ mkdir -p "$kernel_headers_dir/lib/modules/$version/"
 if [ "$ARCH" = "um" ] ; then
        mkdir -p "$tmpdir/usr/lib/uml/modules/$version" "$tmpdir/usr/bin"
 fi
+if [ -n "$BUILD_DEBUG" ] ; then
+       mkdir -p "$dbg_dir/usr/share/doc/$dbg_packagename"
+       mkdir -m 755 -p "$dbg_dir/DEBIAN"
+fi
 
 # Build and install the kernel
 if [ "$ARCH" = "um" ] ; then
        $MAKE linux
        cp System.map "$tmpdir/usr/lib/uml/modules/$version/System.map"
-       cp .config "$tmpdir/usr/share/doc/$packagename/config"
+       cp $KCONFIG_CONFIG "$tmpdir/usr/share/doc/$packagename/config"
        gzip "$tmpdir/usr/share/doc/$packagename/config"
-       cp $KBUILD_IMAGE "$tmpdir/usr/bin/linux-$version"
 else 
        cp System.map "$tmpdir/boot/System.map-$version"
-       cp .config "$tmpdir/boot/config-$version"
-       # Not all arches include the boot path in KBUILD_IMAGE
-       if [ -e $KBUILD_IMAGE ]; then
-               cp $KBUILD_IMAGE "$tmpdir/boot/vmlinuz-$version"
-       else
-               cp arch/$ARCH/boot/$KBUILD_IMAGE "$tmpdir/boot/vmlinuz-$version"
-       fi
+       cp $KCONFIG_CONFIG "$tmpdir/boot/config-$version"
+fi
+# Not all arches include the boot path in KBUILD_IMAGE
+if [ -e $KBUILD_IMAGE ]; then
+       cp $KBUILD_IMAGE "$tmpdir/$installed_image_path"
+else
+       cp arch/$ARCH/boot/$KBUILD_IMAGE "$tmpdir/$installed_image_path"
 fi
 
-if grep -q '^CONFIG_MODULES=y' .config ; then
+if grep -q '^CONFIG_MODULES=y' $KCONFIG_CONFIG ; then
        INSTALL_MOD_PATH="$tmpdir" $MAKE KBUILD_SRC= modules_install
        rm -f "$tmpdir/lib/modules/$version/build"
        rm -f "$tmpdir/lib/modules/$version/source"
@@ -128,6 +149,20 @@ if grep -q '^CONFIG_MODULES=y' .config ; then
                mv "$tmpdir/lib/modules/$version"/* "$tmpdir/usr/lib/uml/modules/$version/"
                rmdir "$tmpdir/lib/modules/$version"
        fi
+       if [ -n "$BUILD_DEBUG" ] ; then
+               (
+                       cd $tmpdir
+                       for module in $(find lib/modules/ -name *.ko); do
+                               mkdir -p $(dirname $dbg_dir/usr/lib/debug/$module)
+                               # only keep debug symbols in the debug file
+                               objcopy --only-keep-debug $module $dbg_dir/usr/lib/debug/$module
+                               # strip original module from debug symbols
+                               objcopy --strip-debug $module
+                               # then add a link to those
+                               objcopy --add-gnu-debuglink=$dbg_dir/usr/lib/debug/$module $module
+                       done
+               )
+       fi
 fi
 
 if [ "$ARCH" != "um" ]; then
@@ -149,7 +184,7 @@ set -e
 # Pass maintainer script parameters to hook scripts
 export DEB_MAINT_PARAMS="\$*"
 
-test -d $debhookdir/$script.d && run-parts --arg="$version" $debhookdir/$script.d
+test -d $debhookdir/$script.d && run-parts --arg="$version" --arg="/$installed_image_path" $debhookdir/$script.d
 exit 0
 EOF
        chmod 755 "$tmpdir/DEBIAN/$script"
@@ -245,11 +280,12 @@ fi
 # Build header package
 (cd $srctree; find . -name Makefile\* -o -name Kconfig\* -o -name \*.pl > "$objtree/debian/hdrsrcfiles")
 (cd $srctree; find arch/$SRCARCH/include include scripts -type f >> "$objtree/debian/hdrsrcfiles")
-(cd $objtree; find arch/$SRCARCH/include .config Module.symvers include scripts -type f >> "$objtree/debian/hdrobjfiles")
+(cd $objtree; find arch/$SRCARCH/include Module.symvers include scripts -type f >> "$objtree/debian/hdrobjfiles")
 destdir=$kernel_headers_dir/usr/src/linux-headers-$version
 mkdir -p "$destdir"
 (cd $srctree; tar -c -f - -T "$objtree/debian/hdrsrcfiles") | (cd $destdir; tar -xf -)
 (cd $objtree; tar -c -f - -T "$objtree/debian/hdrobjfiles") | (cd $destdir; tar -xf -)
+(cd $objtree; cp $KCONFIG_CONFIG $destdir/.config) # copy .config manually to be where it's expected to be
 ln -sf "/usr/src/linux-headers-$version" "$kernel_headers_dir/lib/modules/$version/build"
 rm -f "$objtree/debian/hdrsrcfiles" "$objtree/debian/hdrobjfiles"
 arch=$(dpkg --print-architecture)
@@ -299,4 +335,30 @@ fi
 
 create_package "$packagename" "$tmpdir"
 
+if [ -n "$BUILD_DEBUG" ] ; then
+       # Build debug package
+       # Different tools want the image in different locations
+       # perf
+       mkdir -p $dbg_dir/usr/lib/debug/lib/modules/$version/
+       cp vmlinux $dbg_dir/usr/lib/debug/lib/modules/$version/
+       # systemtap
+       mkdir -p $dbg_dir/usr/lib/debug/boot/
+       ln -s ../lib/modules/$version/vmlinux $dbg_dir/usr/lib/debug/boot/vmlinux-$version
+       # kdump-tools
+       ln -s lib/modules/$version/vmlinux $dbg_dir/usr/lib/debug/vmlinux-$version
+
+       cat <<EOF >> debian/control
+
+Package: $dbg_packagename
+Section: debug
+Provides: linux-debug, linux-debug-$version
+Architecture: any
+Description: Linux kernel debugging symbols for $version
+ This package will come in handy if you need to debug the kernel. It provides
+ all the necessary debug symbols for the kernel and its modules.
+EOF
+
+       create_package "$dbg_packagename" "$dbg_dir"
+fi
+
 exit 0
index cdd9bb909bcda05efd16ba21f6700316194f6116..aa22f9447ddc2492bfee4241a1380bc4fb91a735 100644 (file)
@@ -87,6 +87,27 @@ case "${ARCH}" in
                [ -f "${objtree}/vmlinux.SYS" ] && cp -v -- "${objtree}/vmlinux.SYS" "${tmpdir}/boot/vmlinux-${KERNELRELEASE}.SYS"
                [ -f "${objtree}/vmlinux.dsk" ] && cp -v -- "${objtree}/vmlinux.dsk" "${tmpdir}/boot/vmlinux-${KERNELRELEASE}.dsk"
                ;;
+       mips)
+               if [ -f "${objtree}/arch/mips/boot/compressed/vmlinux.bin" ]; then
+                       cp -v -- "${objtree}/arch/mips/boot/compressed/vmlinux.bin" "${tmpdir}/boot/vmlinuz-${KERNELRELEASE}"
+               elif [ -f "${objtree}/arch/mips/boot/compressed/vmlinux.ecoff" ]; then
+                       cp -v -- "${objtree}/arch/mips/boot/compressed/vmlinux.ecoff" "${tmpdir}/boot/vmlinuz-${KERNELRELEASE}"
+               elif [ -f "${objtree}/arch/mips/boot/compressed/vmlinux.srec" ]; then
+                       cp -v -- "${objtree}/arch/mips/boot/compressed/vmlinux.srec" "${tmpdir}/boot/vmlinuz-${KERNELRELEASE}"
+               elif [ -f "${objtree}/vmlinux.32" ]; then
+                       cp -v -- "${objtree}/vmlinux.32" "${tmpdir}/boot/vmlinux-${KERNELRELEASE}"
+               elif [ -f "${objtree}/vmlinux.64" ]; then
+                       cp -v -- "${objtree}/vmlinux.64" "${tmpdir}/boot/vmlinux-${KERNELRELEASE}"
+               elif [ -f "${objtree}/arch/mips/boot/vmlinux.bin" ]; then
+                       cp -v -- "${objtree}/arch/mips/boot/vmlinux.bin" "${tmpdir}/boot/vmlinux-${KERNELRELEASE}"
+               elif [ -f "${objtree}/arch/mips/boot/vmlinux.ecoff" ]; then
+                       cp -v -- "${objtree}/arch/mips/boot/vmlinux.ecoff" "${tmpdir}/boot/vmlinux-${KERNELRELEASE}"
+               elif [ -f "${objtree}/arch/mips/boot/vmlinux.srec" ]; then
+                       cp -v -- "${objtree}/arch/mips/boot/vmlinux.srec" "${tmpdir}/boot/vmlinux-${KERNELRELEASE}"
+               elif [ -f "${objtree}/vmlinux" ]; then
+                       cp -v -- "${objtree}/vmlinux" "${tmpdir}/boot/vmlinux-${KERNELRELEASE}"
+               fi
+               ;;
        *)
                [ -f "${KBUILD_IMAGE}" ] && cp -v -- "${KBUILD_IMAGE}" "${tmpdir}/boot/vmlinux-kbuild-${KERNELRELEASE}"
                echo "" >&2
index fdd3fbf4d4a41a0d8bab7b93d5fb6f4c7896f94d..13957602f7ca5eb190170450b79ff877cd0cb3af 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 #
-#      Output a simple RPM spec file that uses no fancy features requiring
-#      RPM v4. This is intended to work with any RPM distro.
+#      Output a simple RPM spec file.
+#      This version assumes a minimum of RPM 4.0.3.
 #
 #      The only gothic bit here is redefining install_post to avoid
 #      stripping the symbols from files in the kernel which we want
@@ -59,6 +59,14 @@ echo "header files define structures and constants that are needed for"
 echo "building most standard programs and are also needed for rebuilding the"
 echo "glibc package."
 echo ""
+echo "%package devel"
+echo "Summary: Development package for building kernel modules to match the $__KERNELRELEASE kernel"
+echo "Group: System Environment/Kernel"
+echo "AutoReqProv: no"
+echo "%description -n kernel-devel"
+echo "This package provides kernel headers and makefiles sufficient to build modules"
+echo "against the $__KERNELRELEASE kernel package."
+echo ""
 
 if ! $PREBUILT; then
 echo "%prep"
@@ -77,13 +85,14 @@ echo "%install"
 echo 'KBUILD_IMAGE=$(make image_name)'
 echo "%ifarch ia64"
 echo 'mkdir -p $RPM_BUILD_ROOT/boot/efi $RPM_BUILD_ROOT/lib/modules'
-echo 'mkdir -p $RPM_BUILD_ROOT/lib/firmware'
 echo "%else"
 echo 'mkdir -p $RPM_BUILD_ROOT/boot $RPM_BUILD_ROOT/lib/modules'
-echo 'mkdir -p $RPM_BUILD_ROOT/lib/firmware'
 echo "%endif"
+echo 'mkdir -p $RPM_BUILD_ROOT'"/lib/firmware/$KERNELRELEASE"
 
-echo 'INSTALL_MOD_PATH=$RPM_BUILD_ROOT make %{?_smp_mflags} KBUILD_SRC= modules_install'
+echo 'INSTALL_MOD_PATH=$RPM_BUILD_ROOT make %{?_smp_mflags} KBUILD_SRC= mod-fw= modules_install'
+echo 'INSTALL_FW_PATH=$RPM_BUILD_ROOT'"/lib/firmware/$KERNELRELEASE"
+echo 'make INSTALL_FW_PATH=$INSTALL_FW_PATH' firmware_install
 echo "%ifarch ia64"
 echo 'cp $KBUILD_IMAGE $RPM_BUILD_ROOT'"/boot/efi/vmlinuz-$KERNELRELEASE"
 echo 'ln -s '"efi/vmlinuz-$KERNELRELEASE" '$RPM_BUILD_ROOT'"/boot/"
@@ -108,18 +117,43 @@ echo 'mv vmlinux.bz2 $RPM_BUILD_ROOT'"/boot/vmlinux-$KERNELRELEASE.bz2"
 echo 'mv vmlinux.orig vmlinux'
 echo "%endif"
 
+echo 'rm -f $RPM_BUILD_ROOT'"/lib/modules/$KERNELRELEASE/{build,source}"
+echo "mkdir -p "'$RPM_BUILD_ROOT'"/usr/src/kernels/$KERNELRELEASE"
+echo "EXCLUDES=\"$RCS_TAR_IGNORE --exclude .tmp_versions --exclude=*vmlinux* --exclude=*.o --exclude=*.ko --exclude=*.cmd --exclude=Documentation --exclude=firmware --exclude .config.old --exclude .missing-syscalls.d\""
+echo "tar "'$EXCLUDES'" -cf- . | (cd "'$RPM_BUILD_ROOT'"/usr/src/kernels/$KERNELRELEASE;tar xvf -)"
+echo 'cd $RPM_BUILD_ROOT'"/lib/modules/$KERNELRELEASE"
+echo "ln -sf /usr/src/kernels/$KERNELRELEASE build"
+echo "ln -sf /usr/src/kernels/$KERNELRELEASE source"
+
 echo ""
 echo "%clean"
 echo 'rm -rf $RPM_BUILD_ROOT'
 echo ""
+echo "%post"
+echo "if [ -x /sbin/installkernel -a -r /boot/vmlinuz-$KERNELRELEASE -a -r /boot/System.map-$KERNELRELEASE ]; then"
+echo "cp /boot/vmlinuz-$KERNELRELEASE /boot/vmlinuz-$KERNELRELEASE-rpm"
+echo "cp /boot/System.map-$KERNELRELEASE /boot/System.map-$KERNELRELEASE-rpm"
+echo "rm -f /boot/vmlinuz-$KERNELRELEASE /boot/System.map-$KERNELRELEASE"
+echo "/sbin/installkernel $KERNELRELEASE /boot/vmlinuz-$KERNELRELEASE-rpm /boot/System.map-$KERNELRELEASE-rpm"
+echo "rm -f /boot/vmlinuz-$KERNELRELEASE-rpm /boot/System.map-$KERNELRELEASE-rpm"
+echo "fi"
+echo ""
 echo "%files"
 echo '%defattr (-, root, root)'
 echo "%dir /lib/modules"
 echo "/lib/modules/$KERNELRELEASE"
-echo "/lib/firmware"
+echo "%exclude /lib/modules/$KERNELRELEASE/build"
+echo "%exclude /lib/modules/$KERNELRELEASE/source"
+echo "/lib/firmware/$KERNELRELEASE"
 echo "/boot/*"
 echo ""
 echo "%files headers"
 echo '%defattr (-, root, root)'
 echo "/usr/include"
 echo ""
+echo "%files devel"
+echo '%defattr (-, root, root)'
+echo "/usr/src/kernels/$KERNELRELEASE"
+echo "/lib/modules/$KERNELRELEASE/build"
+echo "/lib/modules/$KERNELRELEASE/source"
+echo ""
index 65f67cb0aefb22f323d8048c140417555c273c9d..6713f04e30ba8810415f88f7ed6e78cb5685f6f4 100644 (file)
@@ -50,8 +50,13 @@ int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall);
 
 static inline void selinux_xfrm_notify_policyload(void)
 {
+       struct net *net;
+
        atomic_inc(&flow_cache_genid);
-       rt_genid_bump(&init_net);
+       rtnl_lock();
+       for_each_net(net)
+               rt_genid_bump_all(net);
+       rtnl_unlock();
 }
 #else
 static inline int selinux_xfrm_enabled(void)
index 99db892d7299056568e5432bdd660ea14d3143c6..98969541cbcc9c62ff81afb9818d2399dd6e7eb0 100644 (file)
@@ -743,7 +743,7 @@ static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
        mutex_lock(&stream->device->lock);
        switch (_IOC_NR(cmd)) {
        case _IOC_NR(SNDRV_COMPRESS_IOCTL_VERSION):
-               put_user(SNDRV_COMPRESS_VERSION,
+               retval = put_user(SNDRV_COMPRESS_VERSION,
                                (int __user *)arg) ? -EFAULT : 0;
                break;
        case _IOC_NR(SNDRV_COMPRESS_GET_CAPS):
index 11048cc744d0ef01034ce0a9aceb517ff202b5a5..915b4d7fbb23fe8c1309e05c17ff525a6d7e7d78 100644 (file)
@@ -1022,7 +1022,7 @@ static void dummy_proc_write(struct snd_info_entry *entry,
                if (i >= ARRAY_SIZE(fields))
                        continue;
                snd_info_get_str(item, ptr, sizeof(item));
-               if (strict_strtoull(item, 0, &val))
+               if (kstrtoull(item, 0, &val))
                        continue;
                if (fields[i].size == sizeof(int))
                        *get_dummy_int_ptr(dummy, fields[i].offset) = val;
index 2c6386503940bf6db7f996a2dcc6a9a843182013..fe9e6e2f2c5b2a825ae24a432541d45de8f029fb 100644 (file)
@@ -49,7 +49,6 @@ struct fwspk {
        struct snd_card *card;
        struct fw_unit *unit;
        const struct device_info *device_info;
-       struct snd_pcm_substream *pcm;
        struct mutex mutex;
        struct cmp_connection connection;
        struct amdtp_out_stream stream;
@@ -363,8 +362,7 @@ static int fwspk_create_pcm(struct fwspk *fwspk)
                return err;
        pcm->private_data = fwspk;
        strcpy(pcm->name, fwspk->device_info->short_name);
-       fwspk->pcm = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
-       fwspk->pcm->ops = &ops;
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ops);
        return 0;
 }
 
index 8a36a1d9803fbf305bdbcc2bca35c961c4643f5f..46ec4dff094ba566ee28018167e244065734b074 100644 (file)
@@ -486,13 +486,9 @@ static const struct v4l2_ctrl_ops tea575x_ctrl_ops = {
        .s_ctrl = tea575x_s_ctrl,
 };
 
-/*
- * initialize all the tea575x chips
- */
-int snd_tea575x_init(struct snd_tea575x *tea, struct module *owner)
-{
-       int retval;
 
+int snd_tea575x_hw_init(struct snd_tea575x *tea)
+{
        tea->mute = true;
 
        /* Not all devices can or know how to read the data back.
@@ -507,6 +503,17 @@ int snd_tea575x_init(struct snd_tea575x *tea, struct module *owner)
        tea->freq = 90500 * 16;         /* 90.5Mhz default */
        snd_tea575x_set_freq(tea);
 
+       return 0;
+}
+EXPORT_SYMBOL(snd_tea575x_hw_init);
+
+int snd_tea575x_init(struct snd_tea575x *tea, struct module *owner)
+{
+       int retval = snd_tea575x_hw_init(tea);
+
+       if (retval)
+               return retval;
+
        tea->vd = tea575x_radio;
        video_set_drvdata(&tea->vd, tea);
        mutex_init(&tea->mutex);
index 8a005f0e5ca484c842e2fe5f684275abafbde248..fdbb09a9b9e53cc095ac41c0ac6b44d6bfcb871b 100644 (file)
@@ -1216,11 +1216,13 @@ static void hda_jackpoll_work(struct work_struct *work)
 {
        struct hda_codec *codec =
                container_of(work, struct hda_codec, jackpoll_work.work);
-       if (!codec->jackpoll_interval)
-               return;
 
        snd_hda_jack_set_dirty_all(codec);
        snd_hda_jack_poll_all(codec);
+
+       if (!codec->jackpoll_interval)
+               return;
+
        queue_delayed_work(codec->bus->workq, &codec->jackpoll_work,
                           codec->jackpoll_interval);
 }
index 8e77cbbad871dd4ff10263824d016487b1479813..f6c0344258ac579154345f15ca15ff80a97ec144 100644 (file)
@@ -142,6 +142,9 @@ static void parse_user_hints(struct hda_codec *codec)
        val = snd_hda_get_bool_hint(codec, "primary_hp");
        if (val >= 0)
                spec->no_primary_hp = !val;
+       val = snd_hda_get_bool_hint(codec, "multi_io");
+       if (val >= 0)
+               spec->no_multi_io = !val;
        val = snd_hda_get_bool_hint(codec, "multi_cap_vol");
        if (val >= 0)
                spec->multi_cap_vol = !!val;
@@ -1541,7 +1544,8 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
                                              cfg->speaker_pins,
                                              spec->multiout.extra_out_nid,
                                              spec->speaker_paths);
-                       if (fill_mio_first && cfg->line_outs == 1 &&
+                       if (!spec->no_multi_io &&
+                           fill_mio_first && cfg->line_outs == 1 &&
                            cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
                                err = fill_multi_ios(codec, cfg->line_out_pins[0], true);
                                if (!err)
@@ -1554,7 +1558,7 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
                                   spec->private_dac_nids, spec->out_paths,
                                   spec->main_out_badness);
 
-       if (fill_mio_first &&
+       if (!spec->no_multi_io && fill_mio_first &&
            cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
                /* try to fill multi-io first */
                err = fill_multi_ios(codec, cfg->line_out_pins[0], false);
@@ -1582,7 +1586,8 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
                        return err;
                badness += err;
        }
-       if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
+       if (!spec->no_multi_io &&
+           cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
                err = fill_multi_ios(codec, cfg->line_out_pins[0], false);
                if (err < 0)
                        return err;
@@ -1600,7 +1605,8 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
                                check_aamix_out_path(codec, spec->speaker_paths[0]);
        }
 
-       if (cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
+       if (!spec->no_multi_io &&
+           cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
                if (count_multiio_pins(codec, cfg->hp_pins[0]) >= 2)
                        spec->multi_ios = 1; /* give badness */
 
@@ -3724,7 +3730,8 @@ static int mux_select(struct hda_codec *codec, unsigned int adc_idx,
 /* check each pin in the given array; returns true if any of them is plugged */
 static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
 {
-       int i, present = 0;
+       int i;
+       bool present = false;
 
        for (i = 0; i < num_pins; i++) {
                hda_nid_t nid = pins[i];
@@ -3733,7 +3740,8 @@ static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
                /* don't detect pins retasked as inputs */
                if (snd_hda_codec_get_pin_target(codec, nid) & AC_PINCTL_IN_EN)
                        continue;
-               present |= snd_hda_jack_detect(codec, nid);
+               if (snd_hda_jack_detect_state(codec, nid) == HDA_JACK_PRESENT)
+                       present = true;
        }
        return present;
 }
@@ -3887,7 +3895,7 @@ void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, struct hda_jack_tbl *ja
                /* don't detect pins retasked as outputs */
                if (snd_hda_codec_get_pin_target(codec, pin) & AC_PINCTL_OUT_EN)
                        continue;
-               if (snd_hda_jack_detect(codec, pin)) {
+               if (snd_hda_jack_detect_state(codec, pin) == HDA_JACK_PRESENT) {
                        mux_select(codec, 0, spec->am_entry[i].idx);
                        return;
                }
index e199a852388b4506148b0cfcbcca7ee380406a52..48d44026705b0f05ac01c51fbdb199215195979f 100644 (file)
@@ -220,6 +220,7 @@ struct hda_gen_spec {
        unsigned int hp_mic:1; /* Allow HP as a mic-in */
        unsigned int suppress_hp_mic_detect:1; /* Don't detect HP/mic */
        unsigned int no_primary_hp:1; /* Don't prefer HP pins to speaker pins */
+       unsigned int no_multi_io:1; /* Don't try multi I/O config */
        unsigned int multi_cap_vol:1; /* allow multiple capture xxx volumes */
        unsigned int inv_dmic_split:1; /* inverted dmic w/a for conexant */
        unsigned int own_eapd_ctl:1; /* set EAPD by own function */
index ce67608734b58da8a762346eb678e082b2d6b747..fe0bda19de153f78da5da0c4add17e5fb3d95d65 100644 (file)
@@ -295,7 +295,7 @@ static ssize_t type##_store(struct device *dev,                     \
        struct snd_hwdep *hwdep = dev_get_drvdata(dev);         \
        struct hda_codec *codec = hwdep->private_data;          \
        unsigned long val;                                      \
-       int err = strict_strtoul(buf, 0, &val);                 \
+       int err = kstrtoul(buf, 0, &val);                       \
        if (err < 0)                                            \
                return err;                                     \
        codec->type = val;                                      \
@@ -654,7 +654,7 @@ int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp)
        p = snd_hda_get_hint(codec, key);
        if (!p)
                ret = -ENOENT;
-       else if (strict_strtoul(p, 0, &val))
+       else if (kstrtoul(p, 0, &val))
                ret = -EINVAL;
        else {
                *valp = val;
@@ -751,7 +751,7 @@ static void parse_##name##_mode(char *buf, struct hda_bus *bus, \
                                 struct hda_codec **codecp) \
 { \
        unsigned long val; \
-       if (!strict_strtoul(buf, 0, &val)) \
+       if (!kstrtoul(buf, 0, &val)) \
                (*codecp)->name = val; \
 }
 
index 8860dd529520d0335264af050fdb918ae47c1c60..7f9e4062a8d7ee9bd7c198b877d7cbaf4b915feb 100644 (file)
@@ -1160,7 +1160,7 @@ static int azx_reset(struct azx *chip, int full_reset)
                goto __skip;
 
        /* clear STATESTS */
-       azx_writeb(chip, STATESTS, STATESTS_INT_MASK);
+       azx_writew(chip, STATESTS, STATESTS_INT_MASK);
 
        /* reset controller */
        azx_enter_link_reset(chip);
@@ -1242,7 +1242,7 @@ static void azx_int_clear(struct azx *chip)
        }
 
        /* clear STATESTS */
-       azx_writeb(chip, STATESTS, STATESTS_INT_MASK);
+       azx_writew(chip, STATESTS, STATESTS_INT_MASK);
 
        /* clear rirb status */
        azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
@@ -1451,8 +1451,8 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
 
 #if 0
        /* clear state status int */
-       if (azx_readb(chip, STATESTS) & 0x04)
-               azx_writeb(chip, STATESTS, 0x04);
+       if (azx_readw(chip, STATESTS) & 0x04)
+               azx_writew(chip, STATESTS, 0x04);
 #endif
        spin_unlock(&chip->reg_lock);
        
@@ -2971,6 +2971,10 @@ static int azx_runtime_suspend(struct device *dev)
        struct snd_card *card = dev_get_drvdata(dev);
        struct azx *chip = card->private_data;
 
+       /* enable controller wake up event */
+       azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) |
+                 STATESTS_INT_MASK);
+
        azx_stop_chip(chip);
        azx_enter_link_reset(chip);
        azx_clear_irq_pending(chip);
@@ -2983,11 +2987,31 @@ static int azx_runtime_resume(struct device *dev)
 {
        struct snd_card *card = dev_get_drvdata(dev);
        struct azx *chip = card->private_data;
+       struct hda_bus *bus;
+       struct hda_codec *codec;
+       int status;
 
        if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
                hda_display_power(true);
+
+       /* Read STATESTS before controller reset */
+       status = azx_readw(chip, STATESTS);
+
        azx_init_pci(chip);
        azx_init_chip(chip, 1);
+
+       bus = chip->bus;
+       if (status && bus) {
+               list_for_each_entry(codec, &bus->codec_list, list)
+                       if (status & (1 << codec->addr))
+                               queue_delayed_work(codec->bus->workq,
+                                                  &codec->jackpoll_work, codec->jackpoll_interval);
+       }
+
+       /* disable controller Wake Up event*/
+       azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) &
+                       ~STATESTS_INT_MASK);
+
        return 0;
 }
 
index 3fd2973183e2dda266a78c00a96bc5517b5bb29f..dc93761a4bc5a8e848d805b63b6f2bbe070825d2 100644 (file)
@@ -194,18 +194,24 @@ u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid)
 EXPORT_SYMBOL_HDA(snd_hda_pin_sense);
 
 /**
- * snd_hda_jack_detect - query pin Presence Detect status
+ * snd_hda_jack_detect_state - query pin Presence Detect status
  * @codec: the CODEC to sense
  * @nid: the pin NID to sense
  *
- * Query and return the pin's Presence Detect status.
+ * Query and return the pin's Presence Detect status, as either
+ * HDA_JACK_NOT_PRESENT, HDA_JACK_PRESENT or HDA_JACK_PHANTOM.
  */
-int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid)
+int snd_hda_jack_detect_state(struct hda_codec *codec, hda_nid_t nid)
 {
-       u32 sense = snd_hda_pin_sense(codec, nid);
-       return get_jack_plug_state(sense);
+       struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid);
+       if (jack && jack->phantom_jack)
+               return HDA_JACK_PHANTOM;
+       else if (snd_hda_pin_sense(codec, nid) & AC_PINSENSE_PRESENCE)
+               return HDA_JACK_PRESENT;
+       else
+               return HDA_JACK_NOT_PRESENT;
 }
-EXPORT_SYMBOL_HDA(snd_hda_jack_detect);
+EXPORT_SYMBOL_HDA(snd_hda_jack_detect_state);
 
 /**
  * snd_hda_jack_detect_enable - enable the jack-detection
index ec12abd452631d12b9915e0c75a4c45fdbc07c95..379420c44eefac051e512b83c67790f9f3ce99a2 100644 (file)
@@ -75,7 +75,18 @@ int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid,
                                 hda_nid_t gating_nid);
 
 u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid);
-int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid);
+
+/* the jack state returned from snd_hda_jack_detect_state() */
+enum {
+       HDA_JACK_NOT_PRESENT, HDA_JACK_PRESENT, HDA_JACK_PHANTOM,
+};
+
+int snd_hda_jack_detect_state(struct hda_codec *codec, hda_nid_t nid);
+
+static inline bool snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid)
+{
+       return snd_hda_jack_detect_state(codec, nid) != HDA_JACK_NOT_PRESENT;
+}
 
 bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid);
 
index d97f0d61a15b5779bd10a17ef3d90a184673c008..0cbdd87dde6d90ac67767ddd30331c62b8d02862 100644 (file)
@@ -32,7 +32,6 @@
 #include "hda_jack.h"
 #include "hda_generic.h"
 
-#define ENABLE_AD_STATIC_QUIRKS
 
 struct ad198x_spec {
        struct hda_gen_spec gen;
@@ -43,114 +42,8 @@ struct ad198x_spec {
        hda_nid_t eapd_nid;
 
        unsigned int beep_amp;  /* beep amp value, set via set_beep_amp() */
-
-#ifdef ENABLE_AD_STATIC_QUIRKS
-       const struct snd_kcontrol_new *mixers[6];
-       int num_mixers;
-       const struct hda_verb *init_verbs[6];   /* initialization verbs
-                                                * don't forget NULL termination!
-                                                */
-       unsigned int num_init_verbs;
-
-       /* playback */
-       struct hda_multi_out multiout;  /* playback set-up
-                                        * max_channels, dacs must be set
-                                        * dig_out_nid and hp_nid are optional
-                                        */
-       unsigned int cur_eapd;
-       unsigned int need_dac_fix;
-
-       /* capture */
-       unsigned int num_adc_nids;
-       const hda_nid_t *adc_nids;
-       hda_nid_t dig_in_nid;           /* digital-in NID; optional */
-
-       /* capture source */
-       const struct hda_input_mux *input_mux;
-       const hda_nid_t *capsrc_nids;
-       unsigned int cur_mux[3];
-
-       /* channel model */
-       const struct hda_channel_mode *channel_mode;
-       int num_channel_mode;
-
-       /* PCM information */
-       struct hda_pcm pcm_rec[3];      /* used in alc_build_pcms() */
-
-       unsigned int spdif_route;
-
-       unsigned int jack_present: 1;
-       unsigned int inv_jack_detect: 1;/* inverted jack-detection */
-       unsigned int analog_beep: 1;    /* analog beep input present */
-       unsigned int avoid_init_slave_vol:1;
-
-#ifdef CONFIG_PM
-       struct hda_loopback_check loopback;
-#endif
-       /* for virtual master */
-       hda_nid_t vmaster_nid;
-       const char * const *slave_vols;
-       const char * const *slave_sws;
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-};
-
-#ifdef ENABLE_AD_STATIC_QUIRKS
-/*
- * input MUX handling (common part)
- */
-static int ad198x_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ad198x_spec *spec = codec->spec;
-
-       return snd_hda_input_mux_info(spec->input_mux, uinfo);
-}
-
-static int ad198x_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ad198x_spec *spec = codec->spec;
-       unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-
-       ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
-       return 0;
-}
-
-static int ad198x_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ad198x_spec *spec = codec->spec;
-       unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-
-       return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
-                                    spec->capsrc_nids[adc_idx],
-                                    &spec->cur_mux[adc_idx]);
-}
-
-/*
- * initialization (common callbacks)
- */
-static int ad198x_init(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec = codec->spec;
-       int i;
-
-       for (i = 0; i < spec->num_init_verbs; i++)
-               snd_hda_sequence_write(codec, spec->init_verbs[i]);
-       return 0;
-}
-
-static const char * const ad_slave_pfxs[] = {
-       "Front", "Surround", "Center", "LFE", "Side",
-       "Headphone", "Mono", "Speaker", "IEC958",
-       NULL
 };
 
-static const char * const ad1988_6stack_fp_slave_pfxs[] = {
-       "Front", "Surround", "Center", "LFE", "Side", "IEC958",
-       NULL
-};
-#endif /* ENABLE_AD_STATIC_QUIRKS */
 
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
 /* additional beep mixers; the actual parameters are overwritten at build */
@@ -160,12 +53,6 @@ static const struct snd_kcontrol_new ad_beep_mixer[] = {
        { } /* end */
 };
 
-static const struct snd_kcontrol_new ad_beep2_mixer[] = {
-       HDA_CODEC_VOLUME("Digital Beep Playback Volume", 0, 0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_BEEP("Digital Beep Playback Switch", 0, 0, HDA_OUTPUT),
-       { } /* end */
-};
-
 #define set_beep_amp(spec, nid, idx, dir) \
        ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */
 #else
@@ -181,8 +68,7 @@ static int create_beep_ctls(struct hda_codec *codec)
        if (!spec->beep_amp)
                return 0;
 
-       knew = spec->analog_beep ? ad_beep2_mixer : ad_beep_mixer;
-       for ( ; knew->name; knew++) {
+       for (knew = ad_beep_mixer ; knew->name; knew++) {
                int err;
                struct snd_kcontrol *kctl;
                kctl = snd_ctl_new1(knew, codec);
@@ -199,268 +85,6 @@ static int create_beep_ctls(struct hda_codec *codec)
 #define create_beep_ctls(codec)                0
 #endif
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static int ad198x_build_controls(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec = codec->spec;
-       struct snd_kcontrol *kctl;
-       unsigned int i;
-       int err;
-
-       for (i = 0; i < spec->num_mixers; i++) {
-               err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
-               if (err < 0)
-                       return err;
-       }
-       if (spec->multiout.dig_out_nid) {
-               err = snd_hda_create_spdif_out_ctls(codec,
-                                                   spec->multiout.dig_out_nid,
-                                                   spec->multiout.dig_out_nid);
-               if (err < 0)
-                       return err;
-               err = snd_hda_create_spdif_share_sw(codec,
-                                                   &spec->multiout);
-               if (err < 0)
-                       return err;
-               spec->multiout.share_spdif = 1;
-       } 
-       if (spec->dig_in_nid) {
-               err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
-               if (err < 0)
-                       return err;
-       }
-
-       /* create beep controls if needed */
-       err = create_beep_ctls(codec);
-       if (err < 0)
-               return err;
-
-       /* if we have no master control, let's create it */
-       if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
-               unsigned int vmaster_tlv[4];
-               snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
-                                       HDA_OUTPUT, vmaster_tlv);
-               err = __snd_hda_add_vmaster(codec, "Master Playback Volume",
-                                         vmaster_tlv,
-                                         (spec->slave_vols ?
-                                          spec->slave_vols : ad_slave_pfxs),
-                                         "Playback Volume",
-                                         !spec->avoid_init_slave_vol, NULL);
-               if (err < 0)
-                       return err;
-       }
-       if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
-               err = snd_hda_add_vmaster(codec, "Master Playback Switch",
-                                         NULL,
-                                         (spec->slave_sws ?
-                                          spec->slave_sws : ad_slave_pfxs),
-                                         "Playback Switch");
-               if (err < 0)
-                       return err;
-       }
-
-       /* assign Capture Source enums to NID */
-       kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
-       if (!kctl)
-               kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
-       for (i = 0; kctl && i < kctl->count; i++) {
-               err = snd_hda_add_nid(codec, kctl, i, spec->capsrc_nids[i]);
-               if (err < 0)
-                       return err;
-       }
-
-       /* assign IEC958 enums to NID */
-       kctl = snd_hda_find_mixer_ctl(codec,
-                       SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source");
-       if (kctl) {
-               err = snd_hda_add_nid(codec, kctl, 0,
-                                     spec->multiout.dig_out_nid);
-               if (err < 0)
-                       return err;
-       }
-
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static int ad198x_check_power_status(struct hda_codec *codec, hda_nid_t nid)
-{
-       struct ad198x_spec *spec = codec->spec;
-       return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
-}
-#endif
-
-/*
- * Analog playback callbacks
- */
-static int ad198x_playback_pcm_open(struct hda_pcm_stream *hinfo,
-                                   struct hda_codec *codec,
-                                   struct snd_pcm_substream *substream)
-{
-       struct ad198x_spec *spec = codec->spec;
-       return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
-                                            hinfo);
-}
-
-static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
-                                      struct hda_codec *codec,
-                                      unsigned int stream_tag,
-                                      unsigned int format,
-                                      struct snd_pcm_substream *substream)
-{
-       struct ad198x_spec *spec = codec->spec;
-       return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
-                                               format, substream);
-}
-
-static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
-                                      struct hda_codec *codec,
-                                      struct snd_pcm_substream *substream)
-{
-       struct ad198x_spec *spec = codec->spec;
-       return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
-}
-
-/*
- * Digital out
- */
-static int ad198x_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
-                                       struct hda_codec *codec,
-                                       struct snd_pcm_substream *substream)
-{
-       struct ad198x_spec *spec = codec->spec;
-       return snd_hda_multi_out_dig_open(codec, &spec->multiout);
-}
-
-static int ad198x_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
-                                        struct hda_codec *codec,
-                                        struct snd_pcm_substream *substream)
-{
-       struct ad198x_spec *spec = codec->spec;
-       return snd_hda_multi_out_dig_close(codec, &spec->multiout);
-}
-
-static int ad198x_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
-                                          struct hda_codec *codec,
-                                          unsigned int stream_tag,
-                                          unsigned int format,
-                                          struct snd_pcm_substream *substream)
-{
-       struct ad198x_spec *spec = codec->spec;
-       return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
-                                            format, substream);
-}
-
-static int ad198x_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
-                                          struct hda_codec *codec,
-                                          struct snd_pcm_substream *substream)
-{
-       struct ad198x_spec *spec = codec->spec;
-       return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
-}
-
-/*
- * Analog capture
- */
-static int ad198x_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
-                                     struct hda_codec *codec,
-                                     unsigned int stream_tag,
-                                     unsigned int format,
-                                     struct snd_pcm_substream *substream)
-{
-       struct ad198x_spec *spec = codec->spec;
-       snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
-                                  stream_tag, 0, format);
-       return 0;
-}
-
-static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
-                                     struct hda_codec *codec,
-                                     struct snd_pcm_substream *substream)
-{
-       struct ad198x_spec *spec = codec->spec;
-       snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
-       return 0;
-}
-
-/*
- */
-static const struct hda_pcm_stream ad198x_pcm_analog_playback = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 6, /* changed later */
-       .nid = 0, /* fill later */
-       .ops = {
-               .open = ad198x_playback_pcm_open,
-               .prepare = ad198x_playback_pcm_prepare,
-               .cleanup = ad198x_playback_pcm_cleanup,
-       },
-};
-
-static const struct hda_pcm_stream ad198x_pcm_analog_capture = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
-       .nid = 0, /* fill later */
-       .ops = {
-               .prepare = ad198x_capture_pcm_prepare,
-               .cleanup = ad198x_capture_pcm_cleanup
-       },
-};
-
-static const struct hda_pcm_stream ad198x_pcm_digital_playback = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
-       .nid = 0, /* fill later */
-       .ops = {
-               .open = ad198x_dig_playback_pcm_open,
-               .close = ad198x_dig_playback_pcm_close,
-               .prepare = ad198x_dig_playback_pcm_prepare,
-               .cleanup = ad198x_dig_playback_pcm_cleanup
-       },
-};
-
-static const struct hda_pcm_stream ad198x_pcm_digital_capture = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
-       /* NID is set in alc_build_pcms */
-};
-
-static int ad198x_build_pcms(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec = codec->spec;
-       struct hda_pcm *info = spec->pcm_rec;
-
-       codec->num_pcms = 1;
-       codec->pcm_info = info;
-
-       info->name = "AD198x Analog";
-       info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_analog_playback;
-       info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->multiout.max_channels;
-       info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
-       info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_analog_capture;
-       info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids;
-       info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
-
-       if (spec->multiout.dig_out_nid) {
-               info++;
-               codec->num_pcms++;
-               codec->spdif_status_reset = 1;
-               info->name = "AD198x Digital";
-               info->pcm_type = HDA_PCM_TYPE_SPDIF;
-               info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback;
-               info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
-               if (spec->dig_in_nid) {
-                       info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_digital_capture;
-                       info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
-               }
-       }
-
-       return 0;
-}
-#endif /* ENABLE_AD_STATIC_QUIRKS */
 
 static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front,
                                hda_nid_t hp)
@@ -507,18 +131,6 @@ static void ad198x_shutup(struct hda_codec *codec)
        ad198x_power_eapd(codec);
 }
 
-static void ad198x_free(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec = codec->spec;
-
-       if (!spec)
-               return;
-
-       snd_hda_gen_spec_free(&spec->gen);
-       kfree(spec);
-       snd_hda_detach_beep_device(codec);
-}
-
 #ifdef CONFIG_PM
 static int ad198x_suspend(struct hda_codec *codec)
 {
@@ -527,65 +139,6 @@ static int ad198x_suspend(struct hda_codec *codec)
 }
 #endif
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static const struct hda_codec_ops ad198x_patch_ops = {
-       .build_controls = ad198x_build_controls,
-       .build_pcms = ad198x_build_pcms,
-       .init = ad198x_init,
-       .free = ad198x_free,
-#ifdef CONFIG_PM
-       .check_power_status = ad198x_check_power_status,
-       .suspend = ad198x_suspend,
-#endif
-       .reboot_notify = ad198x_shutup,
-};
-
-
-/*
- * EAPD control
- * the private value = nid
- */
-#define ad198x_eapd_info       snd_ctl_boolean_mono_info
-
-static int ad198x_eapd_get(struct snd_kcontrol *kcontrol,
-                          struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ad198x_spec *spec = codec->spec;
-       if (codec->inv_eapd)
-               ucontrol->value.integer.value[0] = ! spec->cur_eapd;
-       else
-               ucontrol->value.integer.value[0] = spec->cur_eapd;
-       return 0;
-}
-
-static int ad198x_eapd_put(struct snd_kcontrol *kcontrol,
-                          struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ad198x_spec *spec = codec->spec;
-       hda_nid_t nid = kcontrol->private_value & 0xff;
-       unsigned int eapd;
-       eapd = !!ucontrol->value.integer.value[0];
-       if (codec->inv_eapd)
-               eapd = !eapd;
-       if (eapd == spec->cur_eapd)
-               return 0;
-       spec->cur_eapd = eapd;
-       snd_hda_codec_write_cache(codec, nid,
-                                 0, AC_VERB_SET_EAPD_BTLENABLE,
-                                 eapd ? 0x02 : 0x00);
-       return 1;
-}
-
-static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol,
-                              struct snd_ctl_elem_info *uinfo);
-static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol,
-                             struct snd_ctl_elem_value *ucontrol);
-static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
-                             struct snd_ctl_elem_value *ucontrol);
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
 
 /*
  * Automatic parse of I/O pins from the BIOS configuration
@@ -646,580 +199,124 @@ static int ad198x_parse_auto_config(struct hda_codec *codec)
  * AD1986A specific
  */
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-#define AD1986A_SPDIF_OUT      0x02
-#define AD1986A_FRONT_DAC      0x03
-#define AD1986A_SURR_DAC       0x04
-#define AD1986A_CLFE_DAC       0x05
-#define AD1986A_ADC            0x06
-
-static const hda_nid_t ad1986a_dac_nids[3] = {
-       AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC
-};
-static const hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC };
-static const hda_nid_t ad1986a_capsrc_nids[1] = { 0x12 };
-
-static const struct hda_input_mux ad1986a_capture_source = {
-       .num_items = 7,
-       .items = {
-               { "Mic", 0x0 },
-               { "CD", 0x1 },
-               { "Aux", 0x3 },
-               { "Line", 0x4 },
-               { "Mix", 0x5 },
-               { "Mono", 0x6 },
-               { "Phone", 0x7 },
-       },
-};
-
-
-static const struct hda_bind_ctls ad1986a_bind_pcm_vol = {
-       .ops = &snd_hda_bind_vol,
-       .values = {
-               HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT),
-               0
-       },
-};
+static int alloc_ad_spec(struct hda_codec *codec)
+{
+       struct ad198x_spec *spec;
 
-static const struct hda_bind_ctls ad1986a_bind_pcm_sw = {
-       .ops = &snd_hda_bind_sw,
-       .values = {
-               HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT),
-               0
-       },
-};
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+       codec->spec = spec;
+       snd_hda_gen_spec_init(&spec->gen);
+       return 0;
+}
 
 /*
- * mixers
+ * AD1986A fixup codes
  */
-static const struct snd_kcontrol_new ad1986a_mixers[] = {
-       /*
-        * bind volumes/mutes of 3 DACs as a single PCM control for simplicity
-        */
-       HDA_BIND_VOL("PCM Playback Volume", &ad1986a_bind_pcm_vol),
-       HDA_BIND_SW("PCM Playback Switch", &ad1986a_bind_pcm_sw),
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Surround Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x1d, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x1d, 2, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x1d, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x1d, 2, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x1a, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Capture Source",
-               .info = ad198x_mux_enum_info,
-               .get = ad198x_mux_enum_get,
-               .put = ad198x_mux_enum_put,
-       },
-       HDA_CODEC_MUTE("Stereo Downmix Switch", 0x09, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
-/* additional mixers for 3stack mode */
-static const struct snd_kcontrol_new ad1986a_3st_mixers[] = {
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Channel Mode",
-               .info = ad198x_ch_mode_info,
-               .get = ad198x_ch_mode_get,
-               .put = ad198x_ch_mode_put,
-       },
-       { } /* end */
-};
 
-/* laptop model - 2ch only */
-static const hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC };
+/* Lenovo N100 seems to report the reversed bit for HP jack-sensing */
+static void ad_fixup_inv_jack_detect(struct hda_codec *codec,
+                                    const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               codec->inv_jack_detect = 1;
+}
 
-/* master controls both pins 0x1a and 0x1b */
-static const struct hda_bind_ctls ad1986a_laptop_master_vol = {
-       .ops = &snd_hda_bind_vol,
-       .values = {
-               HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
-               0,
-       },
+enum {
+       AD1986A_FIXUP_INV_JACK_DETECT,
+       AD1986A_FIXUP_ULTRA,
+       AD1986A_FIXUP_SAMSUNG,
+       AD1986A_FIXUP_3STACK,
+       AD1986A_FIXUP_LAPTOP,
+       AD1986A_FIXUP_LAPTOP_IMIC,
 };
 
-static const struct hda_bind_ctls ad1986a_laptop_master_sw = {
-       .ops = &snd_hda_bind_sw,
-       .values = {
-               HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
-               0,
+static const struct hda_fixup ad1986a_fixups[] = {
+       [AD1986A_FIXUP_INV_JACK_DETECT] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = ad_fixup_inv_jack_detect,
        },
-};
-
-static const struct snd_kcontrol_new ad1986a_laptop_mixers[] = {
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
-       HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
-       HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT),
-       /* 
-          HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
-          HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), */
-       HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Capture Source",
-               .info = ad198x_mux_enum_info,
-               .get = ad198x_mux_enum_get,
-               .put = ad198x_mux_enum_put,
+       [AD1986A_FIXUP_ULTRA] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1b, 0x90170110 }, /* speaker */
+                       { 0x1d, 0x90a7013e }, /* int mic */
+                       {}
+               },
        },
-       { } /* end */
-};
-
-/* laptop-eapd model - 2ch only */
-
-static const struct hda_input_mux ad1986a_laptop_eapd_capture_source = {
-       .num_items = 3,
-       .items = {
-               { "Mic", 0x0 },
-               { "Internal Mic", 0x4 },
-               { "Mix", 0x5 },
+       [AD1986A_FIXUP_SAMSUNG] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1b, 0x90170110 }, /* speaker */
+                       { 0x1d, 0x90a7013e }, /* int mic */
+                       { 0x20, 0x411111f0 }, /* N/A */
+                       { 0x24, 0x411111f0 }, /* N/A */
+                       {}
+               },
        },
-};
-
-static const struct hda_input_mux ad1986a_automic_capture_source = {
-       .num_items = 2,
-       .items = {
-               { "Mic", 0x0 },
-               { "Mix", 0x5 },
+       [AD1986A_FIXUP_3STACK] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1a, 0x02214021 }, /* headphone */
+                       { 0x1b, 0x01014011 }, /* front */
+                       { 0x1c, 0x01013012 }, /* surround */
+                       { 0x1d, 0x01019015 }, /* clfe */
+                       { 0x1e, 0x411111f0 }, /* N/A */
+                       { 0x1f, 0x02a190f0 }, /* mic */
+                       { 0x20, 0x018130f0 }, /* line-in */
+                       {}
+               },
        },
-};
-
-static const struct snd_kcontrol_new ad1986a_laptop_master_mixers[] = {
-       HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
-       HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Capture Source",
-               .info = ad198x_mux_enum_info,
-               .get = ad198x_mux_enum_get,
-               .put = ad198x_mux_enum_put,
+       [AD1986A_FIXUP_LAPTOP] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1a, 0x02214021 }, /* headphone */
+                       { 0x1b, 0x90170110 }, /* speaker */
+                       { 0x1c, 0x411111f0 }, /* N/A */
+                       { 0x1d, 0x411111f0 }, /* N/A */
+                       { 0x1e, 0x411111f0 }, /* N/A */
+                       { 0x1f, 0x02a191f0 }, /* mic */
+                       { 0x20, 0x411111f0 }, /* N/A */
+                       {}
+               },
        },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "External Amplifier",
-               .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
-               .info = ad198x_eapd_info,
-               .get = ad198x_eapd_get,
-               .put = ad198x_eapd_put,
-               .private_value = 0x1b, /* port-D */
+       [AD1986A_FIXUP_LAPTOP_IMIC] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1d, 0x90a7013e }, /* int mic */
+                       {}
+               },
+               .chained_before = 1,
+               .chain_id = AD1986A_FIXUP_LAPTOP,
        },
-       { } /* end */
 };
 
-static const struct snd_kcontrol_new ad1986a_laptop_intmic_mixers[] = {
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT),
-       { } /* end */
+static const struct snd_pci_quirk ad1986a_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_FIXUP_LAPTOP_IMIC),
+       SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8100, "ASUS P5", AD1986A_FIXUP_3STACK),
+       SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8200, "ASUS M2", AD1986A_FIXUP_3STACK),
+       SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_FIXUP_3STACK),
+       SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_FIXUP_LAPTOP),
+       SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_FIXUP_SAMSUNG),
+       SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_FIXUP_ULTRA),
+       SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_FIXUP_INV_JACK_DETECT),
+       SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_FIXUP_3STACK),
+       SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_FIXUP_3STACK),
+       {}
 };
 
-/* re-connect the mic boost input according to the jack sensing */
-static void ad1986a_automic(struct hda_codec *codec)
-{
-       unsigned int present;
-       present = snd_hda_jack_detect(codec, 0x1f);
-       /* 0 = 0x1f, 2 = 0x1d, 4 = mixed */
-       snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_CONNECT_SEL,
-                           present ? 0 : 2);
-}
-
-#define AD1986A_MIC_EVENT              0x36
-
-static void ad1986a_automic_unsol_event(struct hda_codec *codec,
-                                           unsigned int res)
-{
-       if ((res >> 26) != AD1986A_MIC_EVENT)
-               return;
-       ad1986a_automic(codec);
-}
-
-static int ad1986a_automic_init(struct hda_codec *codec)
-{
-       ad198x_init(codec);
-       ad1986a_automic(codec);
-       return 0;
-}
-
-/* laptop-automute - 2ch only */
-
-static void ad1986a_update_hp(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec = codec->spec;
-       unsigned int mute;
-
-       if (spec->jack_present)
-               mute = HDA_AMP_MUTE; /* mute internal speaker */
-       else
-               /* unmute internal speaker if necessary */
-               mute = snd_hda_codec_amp_read(codec, 0x1a, 0, HDA_OUTPUT, 0);
-       snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, mute);
-}
-
-static void ad1986a_hp_automute(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec = codec->spec;
-
-       spec->jack_present = snd_hda_jack_detect(codec, 0x1a);
-       if (spec->inv_jack_detect)
-               spec->jack_present = !spec->jack_present;
-       ad1986a_update_hp(codec);
-}
-
-#define AD1986A_HP_EVENT               0x37
-
-static void ad1986a_hp_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-       if ((res >> 26) != AD1986A_HP_EVENT)
-               return;
-       ad1986a_hp_automute(codec);
-}
-
-static int ad1986a_hp_init(struct hda_codec *codec)
-{
-       ad198x_init(codec);
-       ad1986a_hp_automute(codec);
-       return 0;
-}
-
-/* bind hp and internal speaker mute (with plug check) */
-static int ad1986a_hp_master_sw_put(struct snd_kcontrol *kcontrol,
-                                   struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       int change = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
-       if (change)
-               ad1986a_update_hp(codec);
-       return change;
-}
-
-static const struct snd_kcontrol_new ad1986a_automute_master_mixers[] = {
-       HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Master Playback Switch",
-               .subdevice = HDA_SUBDEV_AMP_FLAG,
-               .info = snd_hda_mixer_amp_switch_info,
-               .get = snd_hda_mixer_amp_switch_get,
-               .put = ad1986a_hp_master_sw_put,
-               .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
-       },
-       { } /* end */
-};
-
-
-/*
- * initialization verbs
- */
-static const struct hda_verb ad1986a_init_verbs[] = {
-       /* Front, Surround, CLFE DAC; mute as default */
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       /* Downmix - off */
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       /* HP, Line-Out, Surround, CLFE selectors */
-       {0x0a, AC_VERB_SET_CONNECT_SEL, 0x0},
-       {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0},
-       {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
-       {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
-       /* Mono selector */
-       {0x0e, AC_VERB_SET_CONNECT_SEL, 0x0},
-       /* Mic selector: Mic 1/2 pin */
-       {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0},
-       /* Line-in selector: Line-in */
-       {0x10, AC_VERB_SET_CONNECT_SEL, 0x0},
-       /* Mic 1/2 swap */
-       {0x11, AC_VERB_SET_CONNECT_SEL, 0x0},
-       /* Record selector: mic */
-       {0x12, AC_VERB_SET_CONNECT_SEL, 0x0},
-       /* Mic, Phone, CD, Aux, Line-In amp; mute as default */
-       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       /* PC beep */
-       {0x18, AC_VERB_SET_CONNECT_SEL, 0x0},
-       /* HP, Line-Out, Surround, CLFE, Mono pins; mute as default */
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       /* HP Pin */
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
-       /* Front, Surround, CLFE Pins */
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-       {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-       /* Mono Pin */
-       {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-       /* Mic Pin */
-       {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
-       /* Line, Aux, CD, Beep-In Pin */
-       {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
-       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
-       {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
-       {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
-       {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
-       { } /* end */
-};
-
-static const struct hda_verb ad1986a_ch2_init[] = {
-       /* Surround out -> Line In */
-       { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
-       /* Line-in selectors */
-       { 0x10, AC_VERB_SET_CONNECT_SEL, 0x1 },
-       /* CLFE -> Mic in */
-       { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-       /* Mic selector, mix C/LFE (backmic) and Mic (frontmic) */
-       { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 },
-       { } /* end */
-};
-
-static const struct hda_verb ad1986a_ch4_init[] = {
-       /* Surround out -> Surround */
-       { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
-       /* CLFE -> Mic in */
-       { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-       { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 },
-       { } /* end */
-};
-
-static const struct hda_verb ad1986a_ch6_init[] = {
-       /* Surround out -> Surround out */
-       { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
-       /* CLFE -> CLFE */
-       { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x0 },
-       { } /* end */
-};
-
-static const struct hda_channel_mode ad1986a_modes[3] = {
-       { 2, ad1986a_ch2_init },
-       { 4, ad1986a_ch4_init },
-       { 6, ad1986a_ch6_init },
-};
-
-/* eapd initialization */
-static const struct hda_verb ad1986a_eapd_init_verbs[] = {
-       {0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
-       {}
-};
-
-static const struct hda_verb ad1986a_automic_verbs[] = {
-       {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       /*{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},*/
-       {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0},
-       {0x1f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_MIC_EVENT},
-       {}
-};
-
-/* Ultra initialization */
-static const struct hda_verb ad1986a_ultra_init[] = {
-       /* eapd initialization */
-       { 0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
-       /* CLFE -> Mic in */
-       { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2 },
-       { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
-       { 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
-       { } /* end */
-};
-
-/* pin sensing on HP jack */
-static const struct hda_verb ad1986a_hp_init_verbs[] = {
-       {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_HP_EVENT},
-       {}
-};
-
-static void ad1986a_samsung_p50_unsol_event(struct hda_codec *codec,
-                                           unsigned int res)
-{
-       switch (res >> 26) {
-       case AD1986A_HP_EVENT:
-               ad1986a_hp_automute(codec);
-               break;
-       case AD1986A_MIC_EVENT:
-               ad1986a_automic(codec);
-               break;
-       }
-}
-
-static int ad1986a_samsung_p50_init(struct hda_codec *codec)
-{
-       ad198x_init(codec);
-       ad1986a_hp_automute(codec);
-       ad1986a_automic(codec);
-       return 0;
-}
-
-
-/* models */
-enum {
-       AD1986A_AUTO,
-       AD1986A_6STACK,
-       AD1986A_3STACK,
-       AD1986A_LAPTOP,
-       AD1986A_LAPTOP_EAPD,
-       AD1986A_LAPTOP_AUTOMUTE,
-       AD1986A_ULTRA,
-       AD1986A_SAMSUNG,
-       AD1986A_SAMSUNG_P50,
-       AD1986A_MODELS
-};
-
-static const char * const ad1986a_models[AD1986A_MODELS] = {
-       [AD1986A_AUTO]          = "auto",
-       [AD1986A_6STACK]        = "6stack",
-       [AD1986A_3STACK]        = "3stack",
-       [AD1986A_LAPTOP]        = "laptop",
-       [AD1986A_LAPTOP_EAPD]   = "laptop-eapd",
-       [AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute",
-       [AD1986A_ULTRA]         = "ultra",
-       [AD1986A_SAMSUNG]       = "samsung",
-       [AD1986A_SAMSUNG_P50]   = "samsung-p50",
-};
-
-static const struct snd_pci_quirk ad1986a_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD),
-       SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9", AD1986A_LAPTOP_EAPD),
-       SND_PCI_QUIRK(0x1043, 0x11f7, "ASUS U5A", AD1986A_LAPTOP_EAPD),
-       SND_PCI_QUIRK(0x1043, 0x1213, "ASUS A6J", AD1986A_LAPTOP_EAPD),
-       SND_PCI_QUIRK(0x1043, 0x1263, "ASUS U5F", AD1986A_LAPTOP_EAPD),
-       SND_PCI_QUIRK(0x1043, 0x1297, "ASUS Z62F", AD1986A_LAPTOP_EAPD),
-       SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS V1j", AD1986A_LAPTOP_EAPD),
-       SND_PCI_QUIRK(0x1043, 0x1302, "ASUS W3j", AD1986A_LAPTOP_EAPD),
-       SND_PCI_QUIRK(0x1043, 0x1443, "ASUS VX1", AD1986A_LAPTOP),
-       SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8J", AD1986A_3STACK),
-       SND_PCI_QUIRK(0x1043, 0x817f, "ASUS P5", AD1986A_3STACK),
-       SND_PCI_QUIRK(0x1043, 0x818f, "ASUS P5", AD1986A_LAPTOP),
-       SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS P5", AD1986A_3STACK),
-       SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK),
-       SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK),
-       SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK),
-       SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40-10Q", AD1986A_3STACK),
-       SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK),
-       SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP),
-       SND_PCI_QUIRK(0x144d, 0xc024, "Samsung P50", AD1986A_SAMSUNG_P50),
-       SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA),
-       SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_SAMSUNG),
-       SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK),
-       SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP),
-       SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK),
-       SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_AUTOMUTE),
-       SND_PCI_QUIRK(0x17c0, 0x2017, "Samsung M50", AD1986A_LAPTOP),
-       {}
-};
-
-#ifdef CONFIG_PM
-static const struct hda_amp_list ad1986a_loopbacks[] = {
-       { 0x13, HDA_OUTPUT, 0 }, /* Mic */
-       { 0x14, HDA_OUTPUT, 0 }, /* Phone */
-       { 0x15, HDA_OUTPUT, 0 }, /* CD */
-       { 0x16, HDA_OUTPUT, 0 }, /* Aux */
-       { 0x17, HDA_OUTPUT, 0 }, /* Line */
-       { } /* end */
-};
-#endif
-
-static int is_jack_available(struct hda_codec *codec, hda_nid_t nid)
-{
-       unsigned int conf = snd_hda_codec_get_pincfg(codec, nid);
-       return get_defcfg_connect(conf) != AC_JACK_PORT_NONE;
-}
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
-static int alloc_ad_spec(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec;
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (!spec)
-               return -ENOMEM;
-       codec->spec = spec;
-       snd_hda_gen_spec_init(&spec->gen);
-       return 0;
-}
-
-/*
- * AD1986A fixup codes
- */
-
-/* Lenovo N100 seems to report the reversed bit for HP jack-sensing */
-static void ad_fixup_inv_jack_detect(struct hda_codec *codec,
-                                    const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PRE_PROBE)
-               codec->inv_jack_detect = 1;
-}
-
-enum {
-       AD1986A_FIXUP_INV_JACK_DETECT,
-};
-
-static const struct hda_fixup ad1986a_fixups[] = {
-       [AD1986A_FIXUP_INV_JACK_DETECT] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = ad_fixup_inv_jack_detect,
-       },
-};
-
-static const struct snd_pci_quirk ad1986a_fixup_tbl[] = {
-       SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_FIXUP_INV_JACK_DETECT),
+static const struct hda_model_fixup ad1986a_fixup_models[] = {
+       { .id = AD1986A_FIXUP_3STACK, .name = "3stack" },
+       { .id = AD1986A_FIXUP_LAPTOP, .name = "laptop" },
+       { .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-imic" },
+       { .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-eapd" }, /* alias */
        {}
 };
 
 /*
  */
-static int ad1986a_parse_auto_config(struct hda_codec *codec)
+static int patch_ad1986a(struct hda_codec *codec)
 {
        int err;
        struct ad198x_spec *spec;
@@ -1244,7 +341,8 @@ static int ad1986a_parse_auto_config(struct hda_codec *codec)
         */
        spec->gen.multiout.no_share_stream = 1;
 
-       snd_hda_pick_fixup(codec, NULL, ad1986a_fixup_tbl, ad1986a_fixups);
+       snd_hda_pick_fixup(codec, ad1986a_fixup_models, ad1986a_fixup_tbl,
+                          ad1986a_fixups);
        snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
 
        err = ad198x_parse_auto_config(codec);
@@ -1258,330 +356,11 @@ static int ad1986a_parse_auto_config(struct hda_codec *codec)
        return 0;
 }
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static int patch_ad1986a(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec;
-       int err, board_config;
-
-       board_config = snd_hda_check_board_config(codec, AD1986A_MODELS,
-                                                 ad1986a_models,
-                                                 ad1986a_cfg_tbl);
-       if (board_config < 0) {
-               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-                      codec->chip_name);
-               board_config = AD1986A_AUTO;
-       }
-
-       if (board_config == AD1986A_AUTO)
-               return ad1986a_parse_auto_config(codec);
-
-       err = alloc_ad_spec(codec);
-       if (err < 0)
-               return err;
-       spec = codec->spec;
-
-       err = snd_hda_attach_beep_device(codec, 0x19);
-       if (err < 0) {
-               ad198x_free(codec);
-               return err;
-       }
-       set_beep_amp(spec, 0x18, 0, HDA_OUTPUT);
-
-       spec->multiout.max_channels = 6;
-       spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids);
-       spec->multiout.dac_nids = ad1986a_dac_nids;
-       spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT;
-       spec->num_adc_nids = 1;
-       spec->adc_nids = ad1986a_adc_nids;
-       spec->capsrc_nids = ad1986a_capsrc_nids;
-       spec->input_mux = &ad1986a_capture_source;
-       spec->num_mixers = 1;
-       spec->mixers[0] = ad1986a_mixers;
-       spec->num_init_verbs = 1;
-       spec->init_verbs[0] = ad1986a_init_verbs;
-#ifdef CONFIG_PM
-       spec->loopback.amplist = ad1986a_loopbacks;
-#endif
-       spec->vmaster_nid = 0x1b;
-       codec->inv_eapd = 1; /* AD1986A has the inverted EAPD implementation */
-
-       codec->patch_ops = ad198x_patch_ops;
-
-       /* override some parameters */
-       switch (board_config) {
-       case AD1986A_3STACK:
-               spec->num_mixers = 2;
-               spec->mixers[1] = ad1986a_3st_mixers;
-               spec->num_init_verbs = 2;
-               spec->init_verbs[1] = ad1986a_ch2_init;
-               spec->channel_mode = ad1986a_modes;
-               spec->num_channel_mode = ARRAY_SIZE(ad1986a_modes);
-               spec->need_dac_fix = 1;
-               spec->multiout.max_channels = 2;
-               spec->multiout.num_dacs = 1;
-               break;
-       case AD1986A_LAPTOP:
-               spec->mixers[0] = ad1986a_laptop_mixers;
-               spec->multiout.max_channels = 2;
-               spec->multiout.num_dacs = 1;
-               spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
-               break;
-       case AD1986A_LAPTOP_EAPD:
-               spec->num_mixers = 3;
-               spec->mixers[0] = ad1986a_laptop_master_mixers;
-               spec->mixers[1] = ad1986a_laptop_eapd_mixers;
-               spec->mixers[2] = ad1986a_laptop_intmic_mixers;
-               spec->num_init_verbs = 2;
-               spec->init_verbs[1] = ad1986a_eapd_init_verbs;
-               spec->multiout.max_channels = 2;
-               spec->multiout.num_dacs = 1;
-               spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
-               if (!is_jack_available(codec, 0x25))
-                       spec->multiout.dig_out_nid = 0;
-               spec->input_mux = &ad1986a_laptop_eapd_capture_source;
-               break;
-       case AD1986A_SAMSUNG:
-               spec->num_mixers = 2;
-               spec->mixers[0] = ad1986a_laptop_master_mixers;
-               spec->mixers[1] = ad1986a_laptop_eapd_mixers;
-               spec->num_init_verbs = 3;
-               spec->init_verbs[1] = ad1986a_eapd_init_verbs;
-               spec->init_verbs[2] = ad1986a_automic_verbs;
-               spec->multiout.max_channels = 2;
-               spec->multiout.num_dacs = 1;
-               spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
-               if (!is_jack_available(codec, 0x25))
-                       spec->multiout.dig_out_nid = 0;
-               spec->input_mux = &ad1986a_automic_capture_source;
-               codec->patch_ops.unsol_event = ad1986a_automic_unsol_event;
-               codec->patch_ops.init = ad1986a_automic_init;
-               break;
-       case AD1986A_SAMSUNG_P50:
-               spec->num_mixers = 2;
-               spec->mixers[0] = ad1986a_automute_master_mixers;
-               spec->mixers[1] = ad1986a_laptop_eapd_mixers;
-               spec->num_init_verbs = 4;
-               spec->init_verbs[1] = ad1986a_eapd_init_verbs;
-               spec->init_verbs[2] = ad1986a_automic_verbs;
-               spec->init_verbs[3] = ad1986a_hp_init_verbs;
-               spec->multiout.max_channels = 2;
-               spec->multiout.num_dacs = 1;
-               spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
-               if (!is_jack_available(codec, 0x25))
-                       spec->multiout.dig_out_nid = 0;
-               spec->input_mux = &ad1986a_automic_capture_source;
-               codec->patch_ops.unsol_event = ad1986a_samsung_p50_unsol_event;
-               codec->patch_ops.init = ad1986a_samsung_p50_init;
-               break;
-       case AD1986A_LAPTOP_AUTOMUTE:
-               spec->num_mixers = 3;
-               spec->mixers[0] = ad1986a_automute_master_mixers;
-               spec->mixers[1] = ad1986a_laptop_eapd_mixers;
-               spec->mixers[2] = ad1986a_laptop_intmic_mixers;
-               spec->num_init_verbs = 3;
-               spec->init_verbs[1] = ad1986a_eapd_init_verbs;
-               spec->init_verbs[2] = ad1986a_hp_init_verbs;
-               spec->multiout.max_channels = 2;
-               spec->multiout.num_dacs = 1;
-               spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
-               if (!is_jack_available(codec, 0x25))
-                       spec->multiout.dig_out_nid = 0;
-               spec->input_mux = &ad1986a_laptop_eapd_capture_source;
-               codec->patch_ops.unsol_event = ad1986a_hp_unsol_event;
-               codec->patch_ops.init = ad1986a_hp_init;
-               /* Lenovo N100 seems to report the reversed bit
-                * for HP jack-sensing
-                */
-               spec->inv_jack_detect = 1;
-               break;
-       case AD1986A_ULTRA:
-               spec->mixers[0] = ad1986a_laptop_eapd_mixers;
-               spec->num_init_verbs = 2;
-               spec->init_verbs[1] = ad1986a_ultra_init;
-               spec->multiout.max_channels = 2;
-               spec->multiout.num_dacs = 1;
-               spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
-               spec->multiout.dig_out_nid = 0;
-               break;
-       }
-
-       /* AD1986A has a hardware problem that it can't share a stream
-        * with multiple output pins.  The copy of front to surrounds
-        * causes noisy or silent outputs at a certain timing, e.g.
-        * changing the volume.
-        * So, let's disable the shared stream.
-        */
-       spec->multiout.no_share_stream = 1;
-
-       codec->no_trigger_sense = 1;
-       codec->no_sticky_stream = 1;
-
-       return 0;
-}
-#else /* ENABLE_AD_STATIC_QUIRKS */
-#define patch_ad1986a  ad1986a_parse_auto_config
-#endif /* ENABLE_AD_STATIC_QUIRKS */
 
 /*
  * AD1983 specific
  */
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-#define AD1983_SPDIF_OUT       0x02
-#define AD1983_DAC             0x03
-#define AD1983_ADC             0x04
-
-static const hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC };
-static const hda_nid_t ad1983_adc_nids[1] = { AD1983_ADC };
-static const hda_nid_t ad1983_capsrc_nids[1] = { 0x15 };
-
-static const struct hda_input_mux ad1983_capture_source = {
-       .num_items = 4,
-       .items = {
-               { "Mic", 0x0 },
-               { "Line", 0x1 },
-               { "Mix", 0x2 },
-               { "Mix Mono", 0x3 },
-       },
-};
-
-/*
- * SPDIF playback route
- */
-static int ad1983_spdif_route_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
-       static const char * const texts[] = { "PCM", "ADC" };
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = 2;
-       if (uinfo->value.enumerated.item > 1)
-               uinfo->value.enumerated.item = 1;
-       strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
-       return 0;
-}
-
-static int ad1983_spdif_route_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ad198x_spec *spec = codec->spec;
-
-       ucontrol->value.enumerated.item[0] = spec->spdif_route;
-       return 0;
-}
-
-static int ad1983_spdif_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ad198x_spec *spec = codec->spec;
-
-       if (ucontrol->value.enumerated.item[0] > 1)
-               return -EINVAL;
-       if (spec->spdif_route != ucontrol->value.enumerated.item[0]) {
-               spec->spdif_route = ucontrol->value.enumerated.item[0];
-               snd_hda_codec_write_cache(codec, spec->multiout.dig_out_nid, 0,
-                                         AC_VERB_SET_CONNECT_SEL,
-                                         spec->spdif_route);
-               return 1;
-       }
-       return 0;
-}
-
-static const struct snd_kcontrol_new ad1983_mixers[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Capture Source",
-               .info = ad198x_mux_enum_info,
-               .get = ad198x_mux_enum_get,
-               .put = ad198x_mux_enum_put,
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
-               .info = ad1983_spdif_route_info,
-               .get = ad1983_spdif_route_get,
-               .put = ad1983_spdif_route_put,
-       },
-       { } /* end */
-};
-
-static const struct hda_verb ad1983_init_verbs[] = {
-       /* Front, HP, Mono; mute as default */
-       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       /* Beep, PCM, Mic, Line-In: mute */
-       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       /* Front, HP selectors; from Mix */
-       {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
-       {0x06, AC_VERB_SET_CONNECT_SEL, 0x01},
-       /* Mono selector; from Mix */
-       {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03},
-       /* Mic selector; Mic */
-       {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
-       /* Line-in selector: Line-in */
-       {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
-       /* Mic boost: 0dB */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
-       /* Record selector: mic */
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       /* SPDIF route: PCM */
-       {0x02, AC_VERB_SET_CONNECT_SEL, 0x0},
-       /* Front Pin */
-       {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-       /* HP Pin */
-       {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
-       /* Mono Pin */
-       {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-       /* Mic Pin */
-       {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
-       /* Line Pin */
-       {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
-       { } /* end */
-};
-
-#ifdef CONFIG_PM
-static const struct hda_amp_list ad1983_loopbacks[] = {
-       { 0x12, HDA_OUTPUT, 0 }, /* Mic */
-       { 0x13, HDA_OUTPUT, 0 }, /* Line */
-       { } /* end */
-};
-#endif
-
-/* models */
-enum {
-       AD1983_AUTO,
-       AD1983_BASIC,
-       AD1983_MODELS
-};
-
-static const char * const ad1983_models[AD1983_MODELS] = {
-       [AD1983_AUTO]           = "auto",
-       [AD1983_BASIC]          = "basic",
-};
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
-
 /*
  * SPDIF mux control for AD1983 auto-parser
  */
@@ -1656,7 +435,7 @@ static int ad1983_add_spdif_mux_ctl(struct hda_codec *codec)
        return 0;
 }
 
-static int ad1983_parse_auto_config(struct hda_codec *codec)
+static int patch_ad1983(struct hda_codec *codec)
 {
        struct ad198x_spec *spec;
        int err;
@@ -1681,432 +460,11 @@ static int ad1983_parse_auto_config(struct hda_codec *codec)
        return err;
 }
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static int patch_ad1983(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec;
-       int board_config;
-       int err;
-
-       board_config = snd_hda_check_board_config(codec, AD1983_MODELS,
-                                                 ad1983_models, NULL);
-       if (board_config < 0) {
-               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-                      codec->chip_name);
-               board_config = AD1983_AUTO;
-       }
-
-       if (board_config == AD1983_AUTO)
-               return ad1983_parse_auto_config(codec);
-
-       err = alloc_ad_spec(codec);
-       if (err < 0)
-               return err;
-       spec = codec->spec;
-
-       err = snd_hda_attach_beep_device(codec, 0x10);
-       if (err < 0) {
-               ad198x_free(codec);
-               return err;
-       }
-       set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
-
-       spec->multiout.max_channels = 2;
-       spec->multiout.num_dacs = ARRAY_SIZE(ad1983_dac_nids);
-       spec->multiout.dac_nids = ad1983_dac_nids;
-       spec->multiout.dig_out_nid = AD1983_SPDIF_OUT;
-       spec->num_adc_nids = 1;
-       spec->adc_nids = ad1983_adc_nids;
-       spec->capsrc_nids = ad1983_capsrc_nids;
-       spec->input_mux = &ad1983_capture_source;
-       spec->num_mixers = 1;
-       spec->mixers[0] = ad1983_mixers;
-       spec->num_init_verbs = 1;
-       spec->init_verbs[0] = ad1983_init_verbs;
-       spec->spdif_route = 0;
-#ifdef CONFIG_PM
-       spec->loopback.amplist = ad1983_loopbacks;
-#endif
-       spec->vmaster_nid = 0x05;
-
-       codec->patch_ops = ad198x_patch_ops;
-
-       codec->no_trigger_sense = 1;
-       codec->no_sticky_stream = 1;
-
-       return 0;
-}
-#else /* ENABLE_AD_STATIC_QUIRKS */
-#define patch_ad1983   ad1983_parse_auto_config
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
 
 /*
  * AD1981 HD specific
  */
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-#define AD1981_SPDIF_OUT       0x02
-#define AD1981_DAC             0x03
-#define AD1981_ADC             0x04
-
-static const hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC };
-static const hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC };
-static const hda_nid_t ad1981_capsrc_nids[1] = { 0x15 };
-
-/* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */
-static const struct hda_input_mux ad1981_capture_source = {
-       .num_items = 7,
-       .items = {
-               { "Front Mic", 0x0 },
-               { "Line", 0x1 },
-               { "Mix", 0x2 },
-               { "Mix Mono", 0x3 },
-               { "CD", 0x4 },
-               { "Mic", 0x6 },
-               { "Aux", 0x7 },
-       },
-};
-
-static const struct snd_kcontrol_new ad1981_mixers[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Aux Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Aux Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x08, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Capture Source",
-               .info = ad198x_mux_enum_info,
-               .get = ad198x_mux_enum_get,
-               .put = ad198x_mux_enum_put,
-       },
-       /* identical with AD1983 */
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
-               .info = ad1983_spdif_route_info,
-               .get = ad1983_spdif_route_get,
-               .put = ad1983_spdif_route_put,
-       },
-       { } /* end */
-};
-
-static const struct hda_verb ad1981_init_verbs[] = {
-       /* Front, HP, Mono; mute as default */
-       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       /* Beep, PCM, Front Mic, Line, Rear Mic, Aux, CD-In: mute */
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       /* Front, HP selectors; from Mix */
-       {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
-       {0x06, AC_VERB_SET_CONNECT_SEL, 0x01},
-       /* Mono selector; from Mix */
-       {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03},
-       /* Mic Mixer; select Front Mic */
-       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
-       {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       /* Mic boost: 0dB */
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       /* Record selector: Front mic */
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       /* SPDIF route: PCM */
-       {0x02, AC_VERB_SET_CONNECT_SEL, 0x0},
-       /* Front Pin */
-       {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-       /* HP Pin */
-       {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
-       /* Mono Pin */
-       {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-       /* Front & Rear Mic Pins */
-       {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
-       /* Line Pin */
-       {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
-       /* Digital Beep */
-       {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* Line-Out as Input: disabled */
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-       { } /* end */
-};
-
-#ifdef CONFIG_PM
-static const struct hda_amp_list ad1981_loopbacks[] = {
-       { 0x12, HDA_OUTPUT, 0 }, /* Front Mic */
-       { 0x13, HDA_OUTPUT, 0 }, /* Line */
-       { 0x1b, HDA_OUTPUT, 0 }, /* Aux */
-       { 0x1c, HDA_OUTPUT, 0 }, /* Mic */
-       { 0x1d, HDA_OUTPUT, 0 }, /* CD */
-       { } /* end */
-};
-#endif
-
-/*
- * Patch for HP nx6320
- *
- * nx6320 uses EAPD in the reverse way - EAPD-on means the internal
- * speaker output enabled _and_ mute-LED off.
- */
-
-#define AD1981_HP_EVENT                0x37
-#define AD1981_MIC_EVENT       0x38
-
-static const struct hda_verb ad1981_hp_init_verbs[] = {
-       {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, /* default off */
-       /* pin sensing on HP and Mic jacks */
-       {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT},
-       {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT},
-       {}
-};
-
-/* turn on/off EAPD (+ mute HP) as a master switch */
-static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol,
-                                  struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ad198x_spec *spec = codec->spec;
-
-       if (! ad198x_eapd_put(kcontrol, ucontrol))
-               return 0;
-       /* change speaker pin appropriately */
-       snd_hda_set_pin_ctl(codec, 0x05, spec->cur_eapd ? PIN_OUT : 0);
-       /* toggle HP mute appropriately */
-       snd_hda_codec_amp_stereo(codec, 0x06, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE,
-                                spec->cur_eapd ? 0 : HDA_AMP_MUTE);
-       return 1;
-}
-
-/* bind volumes of both NID 0x05 and 0x06 */
-static const struct hda_bind_ctls ad1981_hp_bind_master_vol = {
-       .ops = &snd_hda_bind_vol,
-       .values = {
-               HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(0x06, 3, 0, HDA_OUTPUT),
-               0
-       },
-};
-
-/* mute internal speaker if HP is plugged */
-static void ad1981_hp_automute(struct hda_codec *codec)
-{
-       unsigned int present;
-
-       present = snd_hda_jack_detect(codec, 0x06);
-       snd_hda_codec_amp_stereo(codec, 0x05, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-}
-
-/* toggle input of built-in and mic jack appropriately */
-static void ad1981_hp_automic(struct hda_codec *codec)
-{
-       static const struct hda_verb mic_jack_on[] = {
-               {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-               {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
-               {}
-       };
-       static const struct hda_verb mic_jack_off[] = {
-               {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-               {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
-               {}
-       };
-       unsigned int present;
-
-       present = snd_hda_jack_detect(codec, 0x08);
-       if (present)
-               snd_hda_sequence_write(codec, mic_jack_on);
-       else
-               snd_hda_sequence_write(codec, mic_jack_off);
-}
-
-/* unsolicited event for HP jack sensing */
-static void ad1981_hp_unsol_event(struct hda_codec *codec,
-                                 unsigned int res)
-{
-       res >>= 26;
-       switch (res) {
-       case AD1981_HP_EVENT:
-               ad1981_hp_automute(codec);
-               break;
-       case AD1981_MIC_EVENT:
-               ad1981_hp_automic(codec);
-               break;
-       }
-}
-
-static const struct hda_input_mux ad1981_hp_capture_source = {
-       .num_items = 3,
-       .items = {
-               { "Mic", 0x0 },
-               { "Dock Mic", 0x1 },
-               { "Mix", 0x2 },
-       },
-};
-
-static const struct snd_kcontrol_new ad1981_hp_mixers[] = {
-       HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .subdevice = HDA_SUBDEV_NID_FLAG | 0x05,
-               .name = "Master Playback Switch",
-               .info = ad198x_eapd_info,
-               .get = ad198x_eapd_get,
-               .put = ad1981_hp_master_sw_put,
-               .private_value = 0x05,
-       },
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
-#if 0
-       /* FIXME: analog mic/line loopback doesn't work with my tests...
-        *        (although recording is OK)
-        */
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
-       /* FIXME: does this laptop have analog CD connection? */
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
-#endif
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x08, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x18, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Capture Source",
-               .info = ad198x_mux_enum_info,
-               .get = ad198x_mux_enum_get,
-               .put = ad198x_mux_enum_put,
-       },
-       { } /* end */
-};
-
-/* initialize jack-sensing, too */
-static int ad1981_hp_init(struct hda_codec *codec)
-{
-       ad198x_init(codec);
-       ad1981_hp_automute(codec);
-       ad1981_hp_automic(codec);
-       return 0;
-}
-
-/* configuration for Toshiba Laptops */
-static const struct hda_verb ad1981_toshiba_init_verbs[] = {
-       {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x01 }, /* default on */
-       /* pin sensing on HP and Mic jacks */
-       {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT},
-       {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT},
-       {}
-};
-
-static const struct snd_kcontrol_new ad1981_toshiba_mixers[] = {
-       HDA_CODEC_VOLUME("Amp Volume", 0x1a, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Amp Switch", 0x1a, 0x0, HDA_OUTPUT),
-       { }
-};
-
-/* configuration for Lenovo Thinkpad T60 */
-static const struct snd_kcontrol_new ad1981_thinkpad_mixers[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x05, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Master Playback Switch", 0x05, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x08, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Capture Source",
-               .info = ad198x_mux_enum_info,
-               .get = ad198x_mux_enum_get,
-               .put = ad198x_mux_enum_put,
-       },
-       /* identical with AD1983 */
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
-               .info = ad1983_spdif_route_info,
-               .get = ad1983_spdif_route_get,
-               .put = ad1983_spdif_route_put,
-       },
-       { } /* end */
-};
-
-static const struct hda_input_mux ad1981_thinkpad_capture_source = {
-       .num_items = 3,
-       .items = {
-               { "Mic", 0x0 },
-               { "Mix", 0x2 },
-               { "CD", 0x4 },
-       },
-};
-
-/* models */
-enum {
-       AD1981_AUTO,
-       AD1981_BASIC,
-       AD1981_HP,
-       AD1981_THINKPAD,
-       AD1981_TOSHIBA,
-       AD1981_MODELS
-};
-
-static const char * const ad1981_models[AD1981_MODELS] = {
-       [AD1981_AUTO]           = "auto",
-       [AD1981_HP]             = "hp",
-       [AD1981_THINKPAD]       = "thinkpad",
-       [AD1981_BASIC]          = "basic",
-       [AD1981_TOSHIBA]        = "toshiba"
-};
-
-static const struct snd_pci_quirk ad1981_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD),
-       SND_PCI_QUIRK(0x1014, 0x05b7, "Lenovo Z60m", AD1981_THINKPAD),
-       /* All HP models */
-       SND_PCI_QUIRK_VENDOR(0x103c, "HP nx", AD1981_HP),
-       SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA),
-       /* Lenovo Thinkpad T60/X60/Z6xx */
-       SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1981_THINKPAD),
-       /* HP nx6320 (reversed SSID, H/W bug) */
-       SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP),
-       {}
-};
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
-
 /* follow EAPD via vmaster hook */
 static void ad_vmaster_eapd_hook(void *private_data, int enabled)
 {
@@ -2172,7 +530,7 @@ static const struct snd_pci_quirk ad1981_fixup_tbl[] = {
        {}
 };
 
-static int ad1981_parse_auto_config(struct hda_codec *codec)
+static int patch_ad1981(struct hda_codec *codec)
 {
        struct ad198x_spec *spec;
        int err;
@@ -2205,110 +563,6 @@ static int ad1981_parse_auto_config(struct hda_codec *codec)
        return err;
 }
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static int patch_ad1981(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec;
-       int err, board_config;
-
-       board_config = snd_hda_check_board_config(codec, AD1981_MODELS,
-                                                 ad1981_models,
-                                                 ad1981_cfg_tbl);
-       if (board_config < 0) {
-               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-                      codec->chip_name);
-               board_config = AD1981_AUTO;
-       }
-
-       if (board_config == AD1981_AUTO)
-               return ad1981_parse_auto_config(codec);
-
-       err = alloc_ad_spec(codec);
-       if (err < 0)
-               return -ENOMEM;
-       spec = codec->spec;
-
-       err = snd_hda_attach_beep_device(codec, 0x10);
-       if (err < 0) {
-               ad198x_free(codec);
-               return err;
-       }
-       set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT);
-
-       spec->multiout.max_channels = 2;
-       spec->multiout.num_dacs = ARRAY_SIZE(ad1981_dac_nids);
-       spec->multiout.dac_nids = ad1981_dac_nids;
-       spec->multiout.dig_out_nid = AD1981_SPDIF_OUT;
-       spec->num_adc_nids = 1;
-       spec->adc_nids = ad1981_adc_nids;
-       spec->capsrc_nids = ad1981_capsrc_nids;
-       spec->input_mux = &ad1981_capture_source;
-       spec->num_mixers = 1;
-       spec->mixers[0] = ad1981_mixers;
-       spec->num_init_verbs = 1;
-       spec->init_verbs[0] = ad1981_init_verbs;
-       spec->spdif_route = 0;
-#ifdef CONFIG_PM
-       spec->loopback.amplist = ad1981_loopbacks;
-#endif
-       spec->vmaster_nid = 0x05;
-
-       codec->patch_ops = ad198x_patch_ops;
-
-       /* override some parameters */
-       switch (board_config) {
-       case AD1981_HP:
-               spec->mixers[0] = ad1981_hp_mixers;
-               spec->num_init_verbs = 2;
-               spec->init_verbs[1] = ad1981_hp_init_verbs;
-               if (!is_jack_available(codec, 0x0a))
-                       spec->multiout.dig_out_nid = 0;
-               spec->input_mux = &ad1981_hp_capture_source;
-
-               codec->patch_ops.init = ad1981_hp_init;
-               codec->patch_ops.unsol_event = ad1981_hp_unsol_event;
-               /* set the upper-limit for mixer amp to 0dB for avoiding the
-                * possible damage by overloading
-                */
-               snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT,
-                                         (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
-                                         (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
-                                         (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
-                                         (1 << AC_AMPCAP_MUTE_SHIFT));
-               break;
-       case AD1981_THINKPAD:
-               spec->mixers[0] = ad1981_thinkpad_mixers;
-               spec->input_mux = &ad1981_thinkpad_capture_source;
-               /* set the upper-limit for mixer amp to 0dB for avoiding the
-                * possible damage by overloading
-                */
-               snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT,
-                                         (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
-                                         (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
-                                         (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
-                                         (1 << AC_AMPCAP_MUTE_SHIFT));
-               break;
-       case AD1981_TOSHIBA:
-               spec->mixers[0] = ad1981_hp_mixers;
-               spec->mixers[1] = ad1981_toshiba_mixers;
-               spec->num_init_verbs = 2;
-               spec->init_verbs[1] = ad1981_toshiba_init_verbs;
-               spec->multiout.dig_out_nid = 0;
-               spec->input_mux = &ad1981_hp_capture_source;
-               codec->patch_ops.init = ad1981_hp_init;
-               codec->patch_ops.unsol_event = ad1981_hp_unsol_event;
-               break;
-       }
-
-       codec->no_trigger_sense = 1;
-       codec->no_sticky_stream = 1;
-
-       return 0;
-}
-#else /* ENABLE_AD_STATIC_QUIRKS */
-#define patch_ad1981   ad1981_parse_auto_config
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
 
 /*
  * AD1988
@@ -2395,90 +649,7 @@ static int patch_ad1981(struct hda_codec *codec)
  *      E/F quad mic array
  */
 
-
 #ifdef ENABLE_AD_STATIC_QUIRKS
-/* models */
-enum {
-       AD1988_AUTO,
-       AD1988_6STACK,
-       AD1988_6STACK_DIG,
-       AD1988_3STACK,
-       AD1988_3STACK_DIG,
-       AD1988_LAPTOP,
-       AD1988_LAPTOP_DIG,
-       AD1988_MODEL_LAST,
-};
-
-/* reivision id to check workarounds */
-#define AD1988A_REV2           0x100200
-
-#define is_rev2(codec) \
-       ((codec)->vendor_id == 0x11d41988 && \
-        (codec)->revision_id == AD1988A_REV2)
-
-/*
- * mixers
- */
-
-static const hda_nid_t ad1988_6stack_dac_nids[4] = {
-       0x04, 0x06, 0x05, 0x0a
-};
-
-static const hda_nid_t ad1988_3stack_dac_nids[3] = {
-       0x04, 0x05, 0x0a
-};
-
-/* for AD1988A revision-2, DAC2-4 are swapped */
-static const hda_nid_t ad1988_6stack_dac_nids_rev2[4] = {
-       0x04, 0x05, 0x0a, 0x06
-};
-
-static const hda_nid_t ad1988_alt_dac_nid[1] = {
-       0x03
-};
-
-static const hda_nid_t ad1988_3stack_dac_nids_rev2[3] = {
-       0x04, 0x0a, 0x06
-};
-
-static const hda_nid_t ad1988_adc_nids[3] = {
-       0x08, 0x09, 0x0f
-};
-
-static const hda_nid_t ad1988_capsrc_nids[3] = {
-       0x0c, 0x0d, 0x0e
-};
-
-#define AD1988_SPDIF_OUT               0x02
-#define AD1988_SPDIF_OUT_HDMI  0x0b
-#define AD1988_SPDIF_IN                0x07
-
-static const hda_nid_t ad1989b_slave_dig_outs[] = {
-       AD1988_SPDIF_OUT, AD1988_SPDIF_OUT_HDMI, 0
-};
-
-static const struct hda_input_mux ad1988_6stack_capture_source = {
-       .num_items = 5,
-       .items = {
-               { "Front Mic", 0x1 },   /* port-B */
-               { "Line", 0x2 },        /* port-C */
-               { "Mic", 0x4 },         /* port-E */
-               { "CD", 0x5 },
-               { "Mix", 0x9 },
-       },
-};
-
-static const struct hda_input_mux ad1988_laptop_capture_source = {
-       .num_items = 3,
-       .items = {
-               { "Mic/Line", 0x1 },    /* port-B */
-               { "CD", 0x5 },
-               { "Mix", 0x9 },
-       },
-};
-
-/*
- */
 static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol,
                               struct snd_ctl_elem_info *uinfo)
 {
@@ -2509,636 +680,73 @@ static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
                spec->multiout.num_dacs = spec->multiout.max_channels / 2;
        return err;
 }
+#endif /* ENABLE_AD_STATIC_QUIRKS */
 
-/* 6-stack mode */
-static const struct snd_kcontrol_new ad1988_6stack_mixers1[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x06, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Side Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new ad1988_6stack_mixers1_rev2[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x05, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0a, 2, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Side Playback Volume", 0x06, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new ad1988_6stack_mixers2[] = {
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
-       HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT),
-       HDA_BIND_MUTE("Side Playback Switch", 0x28, 2, HDA_INPUT),
-       HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
-       HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
-
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
-
-       HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
-
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
-/* 3-stack mode */
-static const struct snd_kcontrol_new ad1988_3stack_mixers1[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new ad1988_3stack_mixers1_rev2[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x06, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x06, 2, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new ad1988_3stack_mixers2[] = {
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
-       HDA_BIND_MUTE("Surround Playback Switch", 0x2c, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x26, 1, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x26, 2, 2, HDA_INPUT),
-       HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
-       HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
-
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
-
-       HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
-
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Channel Mode",
-               .info = ad198x_ch_mode_info,
-               .get = ad198x_ch_mode_get,
-               .put = ad198x_ch_mode_put,
-       },
-
-       { } /* end */
-};
-
-/* laptop mode */
-static const struct snd_kcontrol_new ad1988_laptop_mixers[] = {
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("PCM Playback Switch", 0x29, 0x0, HDA_INPUT),
-       HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
-
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
-
-       HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
-
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
-
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "External Amplifier",
-               .subdevice = HDA_SUBDEV_NID_FLAG | 0x12,
-               .info = ad198x_eapd_info,
-               .get = ad198x_eapd_get,
-               .put = ad198x_eapd_put,
-               .private_value = 0x12, /* port-D */
-       },
-
-       { } /* end */
-};
-
-/* capture */
-static const struct snd_kcontrol_new ad1988_capture_mixers[] = {
-       HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x0e, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x0e, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               /* The multiple "Capture Source" controls confuse alsamixer
-                * So call somewhat different..
-                */
-               /* .name = "Capture Source", */
-               .name = "Input Source",
-               .count = 3,
-               .info = ad198x_mux_enum_info,
-               .get = ad198x_mux_enum_get,
-               .put = ad198x_mux_enum_put,
-       },
-       { } /* end */
-};
-
-static int ad1988_spdif_playback_source_info(struct snd_kcontrol *kcontrol,
-                                            struct snd_ctl_elem_info *uinfo)
+static int ad1988_auto_smux_enum_info(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_info *uinfo)
 {
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        static const char * const texts[] = {
-               "PCM", "ADC1", "ADC2", "ADC3"
+               "PCM", "ADC1", "ADC2", "ADC3",
        };
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = 4;
-       if (uinfo->value.enumerated.item >= 4)
-               uinfo->value.enumerated.item = 3;
-       strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
-       return 0;
+       int num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1;
+       if (num_conns > 4)
+               num_conns = 4;
+       return snd_hda_enum_helper_info(kcontrol, uinfo, num_conns, texts);
 }
 
-static int ad1988_spdif_playback_source_get(struct snd_kcontrol *kcontrol,
-                                           struct snd_ctl_elem_value *ucontrol)
+static int ad1988_auto_smux_enum_get(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       unsigned int sel;
-
-       sel = snd_hda_codec_read(codec, 0x1d, 0, AC_VERB_GET_AMP_GAIN_MUTE,
-                                AC_AMP_GET_INPUT);
-       if (!(sel & 0x80))
-               ucontrol->value.enumerated.item[0] = 0;
-       else {
-               sel = snd_hda_codec_read(codec, 0x0b, 0,
-                                        AC_VERB_GET_CONNECT_SEL, 0);
-               if (sel < 3)
-                       sel++;
-               else
-                       sel = 0;
-               ucontrol->value.enumerated.item[0] = sel;
-       }
+       struct ad198x_spec *spec = codec->spec;
+
+       ucontrol->value.enumerated.item[0] = spec->cur_smux;
        return 0;
 }
 
-static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol,
-                                           struct snd_ctl_elem_value *ucontrol)
+static int ad1988_auto_smux_enum_put(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       unsigned int val, sel;
-       int change;
+       struct ad198x_spec *spec = codec->spec;
+       unsigned int val = ucontrol->value.enumerated.item[0];
+       struct nid_path *path;
+       int num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1;
 
-       val = ucontrol->value.enumerated.item[0];
-       if (val > 3)
+       if (val >= num_conns)
                return -EINVAL;
-       if (!val) {
-               sel = snd_hda_codec_read(codec, 0x1d, 0,
-                                        AC_VERB_GET_AMP_GAIN_MUTE,
-                                        AC_AMP_GET_INPUT);
-               change = sel & 0x80;
-               if (change) {
-                       snd_hda_codec_write_cache(codec, 0x1d, 0,
-                                                 AC_VERB_SET_AMP_GAIN_MUTE,
-                                                 AMP_IN_UNMUTE(0));
-                       snd_hda_codec_write_cache(codec, 0x1d, 0,
-                                                 AC_VERB_SET_AMP_GAIN_MUTE,
-                                                 AMP_IN_MUTE(1));
-               }
-       } else {
-               sel = snd_hda_codec_read(codec, 0x1d, 0,
-                                        AC_VERB_GET_AMP_GAIN_MUTE,
-                                        AC_AMP_GET_INPUT | 0x01);
-               change = sel & 0x80;
-               if (change) {
-                       snd_hda_codec_write_cache(codec, 0x1d, 0,
-                                                 AC_VERB_SET_AMP_GAIN_MUTE,
-                                                 AMP_IN_MUTE(0));
-                       snd_hda_codec_write_cache(codec, 0x1d, 0,
-                                                 AC_VERB_SET_AMP_GAIN_MUTE,
-                                                 AMP_IN_UNMUTE(1));
-               }
-               sel = snd_hda_codec_read(codec, 0x0b, 0,
-                                        AC_VERB_GET_CONNECT_SEL, 0) + 1;
-               change |= sel != val;
-               if (change)
-                       snd_hda_codec_write_cache(codec, 0x0b, 0,
-                                                 AC_VERB_SET_CONNECT_SEL,
-                                                 val - 1);
-       }
-       return change;
-}
+       if (spec->cur_smux == val)
+               return 0;
 
-static const struct snd_kcontrol_new ad1988_spdif_out_mixers[] = {
-       HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "IEC958 Playback Source",
-               .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
-               .info = ad1988_spdif_playback_source_info,
-               .get = ad1988_spdif_playback_source_get,
-               .put = ad1988_spdif_playback_source_put,
-       },
-       { } /* end */
-};
+       mutex_lock(&codec->control_mutex);
+       codec->cached_write = 1;
+       path = snd_hda_get_path_from_idx(codec,
+                                        spec->smux_paths[spec->cur_smux]);
+       if (path)
+               snd_hda_activate_path(codec, path, false, true);
+       path = snd_hda_get_path_from_idx(codec, spec->smux_paths[val]);
+       if (path)
+               snd_hda_activate_path(codec, path, true, true);
+       spec->cur_smux = val;
+       codec->cached_write = 0;
+       mutex_unlock(&codec->control_mutex);
+       snd_hda_codec_flush_cache(codec); /* flush the updates */
+       return 1;
+}
 
-static const struct snd_kcontrol_new ad1988_spdif_in_mixers[] = {
-       HDA_CODEC_VOLUME("IEC958 Capture Volume", 0x1c, 0x0, HDA_INPUT),
-       { } /* end */
+static struct snd_kcontrol_new ad1988_auto_smux_mixer = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "IEC958 Playback Source",
+       .info = ad1988_auto_smux_enum_info,
+       .get = ad1988_auto_smux_enum_get,
+       .put = ad1988_auto_smux_enum_put,
 };
 
-static const struct snd_kcontrol_new ad1989_spdif_out_mixers[] = {
-       HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("HDMI Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
-/*
- * initialization verbs
- */
-
-/*
- * for 6-stack (+dig)
- */
-static const struct hda_verb ad1988_6stack_init_verbs[] = {
-       /* Front, Surround, CLFE, side DAC; unmute as default */
-       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Port-A front headphon path */
-       {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       /* Port-D line-out path */
-       {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       /* Port-F surround path */
-       {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       /* Port-G CLFE path */
-       {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       /* Port-H side path */
-       {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       /* Mono out path */
-       {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
-       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
-       /* Port-B front mic-in path */
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       /* Port-C line-in path */
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
-       /* Port-E mic-in path */
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
-       /* Analog CD Input */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       /* Analog Mix output amp */
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
-
-       { }
-};
-
-static const struct hda_verb ad1988_6stack_fp_init_verbs[] = {
-       /* Headphone; unmute as default */
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Port-A front headphon path */
-       {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-
-       { }
-};
-
-static const struct hda_verb ad1988_capture_init_verbs[] = {
-       /* mute analog mix */
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
-       /* select ADCs - front-mic */
-       {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
-       {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
-       {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
-
-       { }
-};
-
-static const struct hda_verb ad1988_spdif_init_verbs[] = {
-       /* SPDIF out sel */
-       {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
-       {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, /* ADC1 */
-       {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       /* SPDIF out pin */
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
-
-       { }
-};
-
-static const struct hda_verb ad1988_spdif_in_init_verbs[] = {
-       /* unmute SPDIF input pin */
-       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       { }
-};
-
-/* AD1989 has no ADC -> SPDIF route */
-static const struct hda_verb ad1989_spdif_init_verbs[] = {
-       /* SPDIF-1 out pin */
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
-       /* SPDIF-2/HDMI out pin */
-       {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
-       { }
-};
-
-/*
- * verbs for 3stack (+dig)
- */
-static const struct hda_verb ad1988_3stack_ch2_init[] = {
-       /* set port-C to line-in */
-       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
-       /* set port-E to mic-in */
-       { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-       { } /* end */
-};
-
-static const struct hda_verb ad1988_3stack_ch6_init[] = {
-       /* set port-C to surround out */
-       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       /* set port-E to CLFE out */
-       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { } /* end */
-};
-
-static const struct hda_channel_mode ad1988_3stack_modes[2] = {
-       { 2, ad1988_3stack_ch2_init },
-       { 6, ad1988_3stack_ch6_init },
-};
-
-static const struct hda_verb ad1988_3stack_init_verbs[] = {
-       /* Front, Surround, CLFE, side DAC; unmute as default */
-       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Port-A front headphon path */
-       {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       /* Port-D line-out path */
-       {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       /* Mono out path */
-       {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
-       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
-       /* Port-B front mic-in path */
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       /* Port-C line-in/surround path - 6ch mode as default */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x31, AC_VERB_SET_CONNECT_SEL, 0x0}, /* output sel: DAC 0x05 */
-       {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
-       /* Port-E mic-in/CLFE path - 6ch mode as default */
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x32, AC_VERB_SET_CONNECT_SEL, 0x1}, /* output sel: DAC 0x0a */
-       {0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
-       /* mute analog mix */
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
-       /* select ADCs - front-mic */
-       {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
-       {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
-       {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
-       /* Analog Mix output amp */
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
-       { }
-};
-
-/*
- * verbs for laptop mode (+dig)
- */
-static const struct hda_verb ad1988_laptop_hp_on[] = {
-       /* unmute port-A and mute port-D */
-       { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { } /* end */
-};
-static const struct hda_verb ad1988_laptop_hp_off[] = {
-       /* mute port-A and unmute port-D */
-       { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { } /* end */
-};
-
-#define AD1988_HP_EVENT        0x01
-
-static const struct hda_verb ad1988_laptop_init_verbs[] = {
-       /* Front, Surround, CLFE, side DAC; unmute as default */
-       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Port-A front headphon path */
-       {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       /* unsolicited event for pin-sense */
-       {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1988_HP_EVENT },
-       /* Port-D line-out path + EAPD */
-       {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x00}, /* EAPD-off */
-       /* Mono out path */
-       {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
-       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
-       /* Port-B mic-in path */
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       /* Port-C docking station - try to output */
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
-       /* mute analog mix */
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
-       /* select ADCs - mic */
-       {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
-       {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
-       {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
-       /* Analog Mix output amp */
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
-       { }
-};
-
-static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-       if ((res >> 26) != AD1988_HP_EVENT)
-               return;
-       if (snd_hda_jack_detect(codec, 0x11))
-               snd_hda_sequence_write(codec, ad1988_laptop_hp_on);
-       else
-               snd_hda_sequence_write(codec, ad1988_laptop_hp_off);
-} 
-
-#ifdef CONFIG_PM
-static const struct hda_amp_list ad1988_loopbacks[] = {
-       { 0x20, HDA_INPUT, 0 }, /* Front Mic */
-       { 0x20, HDA_INPUT, 1 }, /* Line */
-       { 0x20, HDA_INPUT, 4 }, /* Mic */
-       { 0x20, HDA_INPUT, 6 }, /* CD */
-       { } /* end */
-};
-#endif
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
-static int ad1988_auto_smux_enum_info(struct snd_kcontrol *kcontrol,
-                                     struct snd_ctl_elem_info *uinfo)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       static const char * const texts[] = {
-               "PCM", "ADC1", "ADC2", "ADC3",
-       };
-       int num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1;
-       if (num_conns > 4)
-               num_conns = 4;
-       return snd_hda_enum_helper_info(kcontrol, uinfo, num_conns, texts);
-}
-
-static int ad1988_auto_smux_enum_get(struct snd_kcontrol *kcontrol,
-                                    struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ad198x_spec *spec = codec->spec;
-
-       ucontrol->value.enumerated.item[0] = spec->cur_smux;
-       return 0;
-}
-
-static int ad1988_auto_smux_enum_put(struct snd_kcontrol *kcontrol,
-                                    struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ad198x_spec *spec = codec->spec;
-       unsigned int val = ucontrol->value.enumerated.item[0];
-       struct nid_path *path;
-       int num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1;
-
-       if (val >= num_conns)
-               return -EINVAL;
-       if (spec->cur_smux == val)
-               return 0;
-
-       mutex_lock(&codec->control_mutex);
-       codec->cached_write = 1;
-       path = snd_hda_get_path_from_idx(codec,
-                                        spec->smux_paths[spec->cur_smux]);
-       if (path)
-               snd_hda_activate_path(codec, path, false, true);
-       path = snd_hda_get_path_from_idx(codec, spec->smux_paths[val]);
-       if (path)
-               snd_hda_activate_path(codec, path, true, true);
-       spec->cur_smux = val;
-       codec->cached_write = 0;
-       mutex_unlock(&codec->control_mutex);
-       snd_hda_codec_flush_cache(codec); /* flush the updates */
-       return 1;
-}
-
-static struct snd_kcontrol_new ad1988_auto_smux_mixer = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "IEC958 Playback Source",
-       .info = ad1988_auto_smux_enum_info,
-       .get = ad1988_auto_smux_enum_get,
-       .put = ad1988_auto_smux_enum_put,
-};
-
-static int ad1988_auto_init(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec = codec->spec;
-       int i, err;
+static int ad1988_auto_init(struct hda_codec *codec)
+{
+       struct ad198x_spec *spec = codec->spec;
+       int i, err;
 
        err = snd_hda_gen_init(codec);
        if (err < 0)
@@ -3220,7 +828,34 @@ static int ad1988_add_spdif_mux_ctl(struct hda_codec *codec)
 /*
  */
 
-static int ad1988_parse_auto_config(struct hda_codec *codec)
+enum {
+       AD1988_FIXUP_6STACK_DIG,
+};
+
+static const struct hda_fixup ad1988_fixups[] = {
+       [AD1988_FIXUP_6STACK_DIG] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x11, 0x02214130 }, /* front-hp */
+                       { 0x12, 0x01014010 }, /* line-out */
+                       { 0x14, 0x02a19122 }, /* front-mic */
+                       { 0x15, 0x01813021 }, /* line-in */
+                       { 0x16, 0x01011012 }, /* line-out */
+                       { 0x17, 0x01a19020 }, /* mic */
+                       { 0x1b, 0x0145f1f0 }, /* SPDIF */
+                       { 0x24, 0x01016011 }, /* line-out */
+                       { 0x25, 0x01012013 }, /* line-out */
+                       { }
+               }
+       },
+};
+
+static const struct hda_model_fixup ad1988_fixup_models[] = {
+       { .id = AD1988_FIXUP_6STACK_DIG, .name = "6stack-dig" },
+       {}
+};
+
+static int patch_ad1988(struct hda_codec *codec)
 {
        struct ad198x_spec *spec;
        int err;
@@ -3234,12 +869,19 @@ static int ad1988_parse_auto_config(struct hda_codec *codec)
        spec->gen.mixer_merge_nid = 0x21;
        spec->gen.beep_nid = 0x10;
        set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
+
+       snd_hda_pick_fixup(codec, ad1988_fixup_models, NULL, ad1988_fixups);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
        err = ad198x_parse_auto_config(codec);
        if (err < 0)
                goto error;
        err = ad1988_add_spdif_mux_ctl(codec);
        if (err < 0)
                goto error;
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
        return 0;
 
  error:
@@ -3247,169 +889,6 @@ static int ad1988_parse_auto_config(struct hda_codec *codec)
        return err;
 }
 
-/*
- */
-
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static const char * const ad1988_models[AD1988_MODEL_LAST] = {
-       [AD1988_6STACK]         = "6stack",
-       [AD1988_6STACK_DIG]     = "6stack-dig",
-       [AD1988_3STACK]         = "3stack",
-       [AD1988_3STACK_DIG]     = "3stack-dig",
-       [AD1988_LAPTOP]         = "laptop",
-       [AD1988_LAPTOP_DIG]     = "laptop-dig",
-       [AD1988_AUTO]           = "auto",
-};
-
-static const struct snd_pci_quirk ad1988_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG),
-       SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG),
-       SND_PCI_QUIRK(0x1043, 0x8277, "Asus P5K-E/WIFI-AP", AD1988_6STACK_DIG),
-       SND_PCI_QUIRK(0x1043, 0x82c0, "Asus M3N-HT Deluxe", AD1988_6STACK_DIG),
-       SND_PCI_QUIRK(0x1043, 0x8311, "Asus P5Q-Premium/Pro", AD1988_6STACK_DIG),
-       {}
-};
-
-static int patch_ad1988(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec;
-       int err, board_config;
-
-       board_config = snd_hda_check_board_config(codec, AD1988_MODEL_LAST,
-                                                 ad1988_models, ad1988_cfg_tbl);
-       if (board_config < 0) {
-               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-                      codec->chip_name);
-               board_config = AD1988_AUTO;
-       }
-
-       if (board_config == AD1988_AUTO)
-               return ad1988_parse_auto_config(codec);
-
-       err = alloc_ad_spec(codec);
-       if (err < 0)
-               return err;
-       spec = codec->spec;
-
-       if (is_rev2(codec))
-               snd_printk(KERN_INFO "patch_analog: AD1988A rev.2 is detected, enable workarounds\n");
-
-       err = snd_hda_attach_beep_device(codec, 0x10);
-       if (err < 0) {
-               ad198x_free(codec);
-               return err;
-       }
-       set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
-
-       if (!spec->multiout.hp_nid)
-               spec->multiout.hp_nid = ad1988_alt_dac_nid[0];
-       switch (board_config) {
-       case AD1988_6STACK:
-       case AD1988_6STACK_DIG:
-               spec->multiout.max_channels = 8;
-               spec->multiout.num_dacs = 4;
-               if (is_rev2(codec))
-                       spec->multiout.dac_nids = ad1988_6stack_dac_nids_rev2;
-               else
-                       spec->multiout.dac_nids = ad1988_6stack_dac_nids;
-               spec->input_mux = &ad1988_6stack_capture_source;
-               spec->num_mixers = 2;
-               if (is_rev2(codec))
-                       spec->mixers[0] = ad1988_6stack_mixers1_rev2;
-               else
-                       spec->mixers[0] = ad1988_6stack_mixers1;
-               spec->mixers[1] = ad1988_6stack_mixers2;
-               spec->num_init_verbs = 1;
-               spec->init_verbs[0] = ad1988_6stack_init_verbs;
-               if (board_config == AD1988_6STACK_DIG) {
-                       spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
-                       spec->dig_in_nid = AD1988_SPDIF_IN;
-               }
-               break;
-       case AD1988_3STACK:
-       case AD1988_3STACK_DIG:
-               spec->multiout.max_channels = 6;
-               spec->multiout.num_dacs = 3;
-               if (is_rev2(codec))
-                       spec->multiout.dac_nids = ad1988_3stack_dac_nids_rev2;
-               else
-                       spec->multiout.dac_nids = ad1988_3stack_dac_nids;
-               spec->input_mux = &ad1988_6stack_capture_source;
-               spec->channel_mode = ad1988_3stack_modes;
-               spec->num_channel_mode = ARRAY_SIZE(ad1988_3stack_modes);
-               spec->num_mixers = 2;
-               if (is_rev2(codec))
-                       spec->mixers[0] = ad1988_3stack_mixers1_rev2;
-               else
-                       spec->mixers[0] = ad1988_3stack_mixers1;
-               spec->mixers[1] = ad1988_3stack_mixers2;
-               spec->num_init_verbs = 1;
-               spec->init_verbs[0] = ad1988_3stack_init_verbs;
-               if (board_config == AD1988_3STACK_DIG)
-                       spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
-               break;
-       case AD1988_LAPTOP:
-       case AD1988_LAPTOP_DIG:
-               spec->multiout.max_channels = 2;
-               spec->multiout.num_dacs = 1;
-               spec->multiout.dac_nids = ad1988_3stack_dac_nids;
-               spec->input_mux = &ad1988_laptop_capture_source;
-               spec->num_mixers = 1;
-               spec->mixers[0] = ad1988_laptop_mixers;
-               codec->inv_eapd = 1; /* inverted EAPD */
-               spec->num_init_verbs = 1;
-               spec->init_verbs[0] = ad1988_laptop_init_verbs;
-               if (board_config == AD1988_LAPTOP_DIG)
-                       spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
-               break;
-       }
-
-       spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids);
-       spec->adc_nids = ad1988_adc_nids;
-       spec->capsrc_nids = ad1988_capsrc_nids;
-       spec->mixers[spec->num_mixers++] = ad1988_capture_mixers;
-       spec->init_verbs[spec->num_init_verbs++] = ad1988_capture_init_verbs;
-       if (spec->multiout.dig_out_nid) {
-               if (codec->vendor_id >= 0x11d4989a) {
-                       spec->mixers[spec->num_mixers++] =
-                               ad1989_spdif_out_mixers;
-                       spec->init_verbs[spec->num_init_verbs++] =
-                               ad1989_spdif_init_verbs;
-                       codec->slave_dig_outs = ad1989b_slave_dig_outs;
-               } else {
-                       spec->mixers[spec->num_mixers++] =
-                               ad1988_spdif_out_mixers;
-                       spec->init_verbs[spec->num_init_verbs++] =
-                               ad1988_spdif_init_verbs;
-               }
-       }
-       if (spec->dig_in_nid && codec->vendor_id < 0x11d4989a) {
-               spec->mixers[spec->num_mixers++] = ad1988_spdif_in_mixers;
-               spec->init_verbs[spec->num_init_verbs++] =
-                       ad1988_spdif_in_init_verbs;
-       }
-
-       codec->patch_ops = ad198x_patch_ops;
-       switch (board_config) {
-       case AD1988_LAPTOP:
-       case AD1988_LAPTOP_DIG:
-               codec->patch_ops.unsol_event = ad1988_laptop_unsol_event;
-               break;
-       }
-#ifdef CONFIG_PM
-       spec->loopback.amplist = ad1988_loopbacks;
-#endif
-       spec->vmaster_nid = 0x04;
-
-       codec->no_trigger_sense = 1;
-       codec->no_sticky_stream = 1;
-
-       return 0;
-}
-#else /* ENABLE_AD_STATIC_QUIRKS */
-#define patch_ad1988   ad1988_parse_auto_config
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
 
 /*
  * AD1884 / AD1984
@@ -3423,167 +902,19 @@ static int patch_ad1988(struct hda_codec *codec)
  *
  * AD1984 = AD1884 + two digital mic-ins
  *
- * FIXME:
- * For simplicity, we share the single DAC for both HP and line-outs
- * right now.  The inidividual playbacks could be easily implemented,
- * but no build-up framework is given, so far.
- */
-
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static const hda_nid_t ad1884_dac_nids[1] = {
-       0x04,
-};
-
-static const hda_nid_t ad1884_adc_nids[2] = {
-       0x08, 0x09,
-};
-
-static const hda_nid_t ad1884_capsrc_nids[2] = {
-       0x0c, 0x0d,
-};
-
-#define AD1884_SPDIF_OUT       0x02
-
-static const struct hda_input_mux ad1884_capture_source = {
-       .num_items = 4,
-       .items = {
-               { "Front Mic", 0x0 },
-               { "Mic", 0x1 },
-               { "CD", 0x2 },
-               { "Mix", 0x3 },
-       },
-};
-
-static const struct snd_kcontrol_new ad1884_base_mixers[] = {
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
-       /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               /* The multiple "Capture Source" controls confuse alsamixer
-                * So call somewhat different..
-                */
-               /* .name = "Capture Source", */
-               .name = "Input Source",
-               .count = 2,
-               .info = ad198x_mux_enum_info,
-               .get = ad198x_mux_enum_get,
-               .put = ad198x_mux_enum_put,
-       },
-       /* SPDIF controls */
-       HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
-               /* identical with ad1983 */
-               .info = ad1983_spdif_route_info,
-               .get = ad1983_spdif_route_get,
-               .put = ad1983_spdif_route_put,
-       },
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new ad1984_dmic_mixers[] = {
-       HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x05, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x05, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME_IDX("Digital Mic Capture Volume", 1, 0x06, 0x0,
-                            HDA_INPUT),
-       HDA_CODEC_MUTE_IDX("Digital Mic Capture Switch", 1, 0x06, 0x0,
-                          HDA_INPUT),
-       { } /* end */
-};
-
-/*
- * initialization verbs
+ * AD1883 / AD1884A / AD1984A / AD1984B
+ *
+ * port-B (0x14) - front mic-in
+ * port-E (0x1c) - rear mic-in
+ * port-F (0x16) - CD / ext out
+ * port-C (0x15) - rear line-in
+ * port-D (0x12) - rear line-out
+ * port-A (0x11) - front hp-out
+ *
+ * AD1984A = AD1884A + digital-mic
+ * AD1883 = equivalent with AD1984A
+ * AD1984B = AD1984A + extra SPDIF-out
  */
-static const struct hda_verb ad1884_init_verbs[] = {
-       /* DACs; mute as default */
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       /* Port-A (HP) mixer */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* Port-A pin */
-       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* HP selector - select DAC2 */
-       {0x22, AC_VERB_SET_CONNECT_SEL, 0x1},
-       /* Port-D (Line-out) mixer */
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* Port-D pin */
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Mono-out mixer */
-       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* Mono-out pin */
-       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Mono selector */
-       {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
-       /* Port-B (front mic) pin */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       /* Port-C (rear mic) pin */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       /* Analog mixer; mute as default */
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       /* Analog Mix output amp */
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
-       /* SPDIF output selector */
-       {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
-       { } /* end */
-};
-
-#ifdef CONFIG_PM
-static const struct hda_amp_list ad1884_loopbacks[] = {
-       { 0x20, HDA_INPUT, 0 }, /* Front Mic */
-       { 0x20, HDA_INPUT, 1 }, /* Mic */
-       { 0x20, HDA_INPUT, 2 }, /* CD */
-       { 0x20, HDA_INPUT, 4 }, /* Docking */
-       { } /* end */
-};
-#endif
-
-static const char * const ad1884_slave_vols[] = {
-       "PCM", "Mic", "Mono", "Front Mic", "Mic", "CD",
-       "Internal Mic", "Dock Mic", /* "Beep", */ "IEC958",
-       NULL
-};
-
-enum {
-       AD1884_AUTO,
-       AD1884_BASIC,
-       AD1884_MODELS
-};
-
-static const char * const ad1884_models[AD1884_MODELS] = {
-       [AD1884_AUTO]           = "auto",
-       [AD1884_BASIC]          = "basic",
-};
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
 
 /* set the upper-limit for mixer amp to 0dB for avoiding the possible
  * damage by overloading
@@ -3599,14 +930,34 @@ static void ad1884_fixup_amp_override(struct hda_codec *codec,
                                          (1 << AC_AMPCAP_MUTE_SHIFT));
 }
 
+/* toggle GPIO1 according to the mute state */
+static void ad1884_vmaster_hp_gpio_hook(void *private_data, int enabled)
+{
+       struct hda_codec *codec = private_data;
+       struct ad198x_spec *spec = codec->spec;
+
+       if (spec->eapd_nid)
+               ad_vmaster_eapd_hook(private_data, enabled);
+       snd_hda_codec_update_cache(codec, 0x01, 0,
+                                  AC_VERB_SET_GPIO_DATA,
+                                  enabled ? 0x00 : 0x02);
+}
+
 static void ad1884_fixup_hp_eapd(struct hda_codec *codec,
                                 const struct hda_fixup *fix, int action)
 {
        struct ad198x_spec *spec = codec->spec;
+       static const struct hda_verb gpio_init_verbs[] = {
+               {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
+               {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
+               {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
+               {},
+       };
 
        switch (action) {
        case HDA_FIXUP_ACT_PRE_PROBE:
-               spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
+               spec->gen.vmaster_mute.hook = ad1884_vmaster_hp_gpio_hook;
+               snd_hda_sequence_write_cache(codec, gpio_init_verbs);
                break;
        case HDA_FIXUP_ACT_PROBE:
                if (spec->gen.autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
@@ -3617,9 +968,18 @@ static void ad1884_fixup_hp_eapd(struct hda_codec *codec,
        }
 }
 
+/* set magic COEFs for dmic */
+static const struct hda_verb ad1884_dmic_init_verbs[] = {
+       {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
+       {0x01, AC_VERB_SET_PROC_COEF, 0x08},
+       {}
+};
+
 enum {
        AD1884_FIXUP_AMP_OVERRIDE,
        AD1884_FIXUP_HP_EAPD,
+       AD1884_FIXUP_DMIC_COEF,
+       AD1884_FIXUP_HP_TOUCHSMART,
 };
 
 static const struct hda_fixup ad1884_fixups[] = {
@@ -3633,15 +993,27 @@ static const struct hda_fixup ad1884_fixups[] = {
                .chained = true,
                .chain_id = AD1884_FIXUP_AMP_OVERRIDE,
        },
+       [AD1884_FIXUP_DMIC_COEF] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = ad1884_dmic_init_verbs,
+       },
+       [AD1884_FIXUP_HP_TOUCHSMART] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = ad1884_dmic_init_verbs,
+               .chained = true,
+               .chain_id = AD1884_FIXUP_HP_EAPD,
+       },
 };
 
 static const struct snd_pci_quirk ad1884_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x103c, 0x2a82, "HP Touchsmart", AD1884_FIXUP_HP_TOUCHSMART),
        SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1884_FIXUP_HP_EAPD),
+       SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1884_FIXUP_DMIC_COEF),
        {}
 };
 
 
-static int ad1884_parse_auto_config(struct hda_codec *codec)
+static int patch_ad1884(struct hda_codec *codec)
 {
        struct ad198x_spec *spec;
        int err;
@@ -3674,1170 +1046,6 @@ static int ad1884_parse_auto_config(struct hda_codec *codec)
        return err;
 }
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static int patch_ad1884_basic(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec;
-       int err;
-
-       err = alloc_ad_spec(codec);
-       if (err < 0)
-               return err;
-       spec = codec->spec;
-
-       err = snd_hda_attach_beep_device(codec, 0x10);
-       if (err < 0) {
-               ad198x_free(codec);
-               return err;
-       }
-       set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
-
-       spec->multiout.max_channels = 2;
-       spec->multiout.num_dacs = ARRAY_SIZE(ad1884_dac_nids);
-       spec->multiout.dac_nids = ad1884_dac_nids;
-       spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
-       spec->num_adc_nids = ARRAY_SIZE(ad1884_adc_nids);
-       spec->adc_nids = ad1884_adc_nids;
-       spec->capsrc_nids = ad1884_capsrc_nids;
-       spec->input_mux = &ad1884_capture_source;
-       spec->num_mixers = 1;
-       spec->mixers[0] = ad1884_base_mixers;
-       spec->num_init_verbs = 1;
-       spec->init_verbs[0] = ad1884_init_verbs;
-       spec->spdif_route = 0;
-#ifdef CONFIG_PM
-       spec->loopback.amplist = ad1884_loopbacks;
-#endif
-       spec->vmaster_nid = 0x04;
-       /* we need to cover all playback volumes */
-       spec->slave_vols = ad1884_slave_vols;
-       /* slaves may contain input volumes, so we can't raise to 0dB blindly */
-       spec->avoid_init_slave_vol = 1;
-
-       codec->patch_ops = ad198x_patch_ops;
-
-       codec->no_trigger_sense = 1;
-       codec->no_sticky_stream = 1;
-
-       return 0;
-}
-
-static int patch_ad1884(struct hda_codec *codec)
-{
-       int board_config;
-
-       board_config = snd_hda_check_board_config(codec, AD1884_MODELS,
-                                                 ad1884_models, NULL);
-       if (board_config < 0) {
-               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-                      codec->chip_name);
-               board_config = AD1884_AUTO;
-       }
-
-       if (board_config == AD1884_AUTO)
-               return ad1884_parse_auto_config(codec);
-       else
-               return patch_ad1884_basic(codec);
-}
-#else /* ENABLE_AD_STATIC_QUIRKS */
-#define patch_ad1884   ad1884_parse_auto_config
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
-
-#ifdef ENABLE_AD_STATIC_QUIRKS
-/*
- * Lenovo Thinkpad T61/X61
- */
-static const struct hda_input_mux ad1984_thinkpad_capture_source = {
-       .num_items = 4,
-       .items = {
-               { "Mic", 0x0 },
-               { "Internal Mic", 0x1 },
-               { "Mix", 0x3 },
-               { "Dock Mic", 0x4 },
-       },
-};
-
-
-/*
- * Dell Precision T3400
- */
-static const struct hda_input_mux ad1984_dell_desktop_capture_source = {
-       .num_items = 3,
-       .items = {
-               { "Front Mic", 0x0 },
-               { "Line-In", 0x1 },
-               { "Mix", 0x3 },
-       },
-};
-
-
-static const struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
-       /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
-       HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
-       HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               /* The multiple "Capture Source" controls confuse alsamixer
-                * So call somewhat different..
-                */
-               /* .name = "Capture Source", */
-               .name = "Input Source",
-               .count = 2,
-               .info = ad198x_mux_enum_info,
-               .get = ad198x_mux_enum_get,
-               .put = ad198x_mux_enum_put,
-       },
-       /* SPDIF controls */
-       HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
-               /* identical with ad1983 */
-               .info = ad1983_spdif_route_info,
-               .get = ad1983_spdif_route_get,
-               .put = ad1983_spdif_route_put,
-       },
-       { } /* end */
-};
-
-/* additional verbs */
-static const struct hda_verb ad1984_thinkpad_init_verbs[] = {
-       /* Port-E (docking station mic) pin */
-       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* docking mic boost */
-       {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       /* Analog PC Beeper - allow firmware/ACPI beeps */
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3) | 0x1a},
-       /* Analog mixer - docking mic; mute as default */
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       /* enable EAPD bit */
-       {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
-       { } /* end */
-};
-
-/*
- * Dell Precision T3400
- */
-static const struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = {
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line-In Playback Volume", 0x20, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Line-In Playback Switch", 0x20, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line-In Boost Volume", 0x15, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               /* The multiple "Capture Source" controls confuse alsamixer
-                * So call somewhat different..
-                */
-               /* .name = "Capture Source", */
-               .name = "Input Source",
-               .count = 2,
-               .info = ad198x_mux_enum_info,
-               .get = ad198x_mux_enum_get,
-               .put = ad198x_mux_enum_put,
-       },
-       { } /* end */
-};
-
-/* Digial MIC ADC NID 0x05 + 0x06 */
-static int ad1984_pcm_dmic_prepare(struct hda_pcm_stream *hinfo,
-                                  struct hda_codec *codec,
-                                  unsigned int stream_tag,
-                                  unsigned int format,
-                                  struct snd_pcm_substream *substream)
-{
-       snd_hda_codec_setup_stream(codec, 0x05 + substream->number,
-                                  stream_tag, 0, format);
-       return 0;
-}
-
-static int ad1984_pcm_dmic_cleanup(struct hda_pcm_stream *hinfo,
-                                  struct hda_codec *codec,
-                                  struct snd_pcm_substream *substream)
-{
-       snd_hda_codec_cleanup_stream(codec, 0x05 + substream->number);
-       return 0;
-}
-
-static const struct hda_pcm_stream ad1984_pcm_dmic_capture = {
-       .substreams = 2,
-       .channels_min = 2,
-       .channels_max = 2,
-       .nid = 0x05,
-       .ops = {
-               .prepare = ad1984_pcm_dmic_prepare,
-               .cleanup = ad1984_pcm_dmic_cleanup
-       },
-};
-
-static int ad1984_build_pcms(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec = codec->spec;
-       struct hda_pcm *info;
-       int err;
-
-       err = ad198x_build_pcms(codec);
-       if (err < 0)
-               return err;
-
-       info = spec->pcm_rec + codec->num_pcms;
-       codec->num_pcms++;
-       info->name = "AD1984 Digital Mic";
-       info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad1984_pcm_dmic_capture;
-       return 0;
-}
-
-/* models */
-enum {
-       AD1984_AUTO,
-       AD1984_BASIC,
-       AD1984_THINKPAD,
-       AD1984_DELL_DESKTOP,
-       AD1984_MODELS
-};
-
-static const char * const ad1984_models[AD1984_MODELS] = {
-       [AD1984_AUTO]           = "auto",
-       [AD1984_BASIC]          = "basic",
-       [AD1984_THINKPAD]       = "thinkpad",
-       [AD1984_DELL_DESKTOP]   = "dell_desktop",
-};
-
-static const struct snd_pci_quirk ad1984_cfg_tbl[] = {
-       /* Lenovo Thinkpad T61/X61 */
-       SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1984_THINKPAD),
-       SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP),
-       SND_PCI_QUIRK(0x1028, 0x0233, "Dell Latitude E6400", AD1984_DELL_DESKTOP),
-       {}
-};
-
-static int patch_ad1984(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec;
-       int board_config, err;
-
-       board_config = snd_hda_check_board_config(codec, AD1984_MODELS,
-                                                 ad1984_models, ad1984_cfg_tbl);
-       if (board_config < 0) {
-               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-                      codec->chip_name);
-               board_config = AD1984_AUTO;
-       }
-
-       if (board_config == AD1984_AUTO)
-               return ad1884_parse_auto_config(codec);
-
-       err = patch_ad1884_basic(codec);
-       if (err < 0)
-               return err;
-       spec = codec->spec;
-
-       switch (board_config) {
-       case AD1984_BASIC:
-               /* additional digital mics */
-               spec->mixers[spec->num_mixers++] = ad1984_dmic_mixers;
-               codec->patch_ops.build_pcms = ad1984_build_pcms;
-               break;
-       case AD1984_THINKPAD:
-               if (codec->subsystem_id == 0x17aa20fb) {
-                       /* Thinpad X300 does not have the ability to do SPDIF,
-                          or attach to docking station to use SPDIF */
-                       spec->multiout.dig_out_nid = 0;
-               } else
-                       spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
-               spec->input_mux = &ad1984_thinkpad_capture_source;
-               spec->mixers[0] = ad1984_thinkpad_mixers;
-               spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs;
-               spec->analog_beep = 1;
-               break;
-       case AD1984_DELL_DESKTOP:
-               spec->multiout.dig_out_nid = 0;
-               spec->input_mux = &ad1984_dell_desktop_capture_source;
-               spec->mixers[0] = ad1984_dell_desktop_mixers;
-               break;
-       }
-       return 0;
-}
-#else /* ENABLE_AD_STATIC_QUIRKS */
-#define patch_ad1984   ad1884_parse_auto_config
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
-
-/*
- * AD1883 / AD1884A / AD1984A / AD1984B
- *
- * port-B (0x14) - front mic-in
- * port-E (0x1c) - rear mic-in
- * port-F (0x16) - CD / ext out
- * port-C (0x15) - rear line-in
- * port-D (0x12) - rear line-out
- * port-A (0x11) - front hp-out
- *
- * AD1984A = AD1884A + digital-mic
- * AD1883 = equivalent with AD1984A
- * AD1984B = AD1984A + extra SPDIF-out
- *
- * FIXME:
- * We share the single DAC for both HP and line-outs (see AD1884/1984).
- */
-
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static const hda_nid_t ad1884a_dac_nids[1] = {
-       0x03,
-};
-
-#define ad1884a_adc_nids       ad1884_adc_nids
-#define ad1884a_capsrc_nids    ad1884_capsrc_nids
-
-#define AD1884A_SPDIF_OUT      0x02
-
-static const struct hda_input_mux ad1884a_capture_source = {
-       .num_items = 5,
-       .items = {
-               { "Front Mic", 0x0 },
-               { "Mic", 0x4 },
-               { "Line", 0x1 },
-               { "CD", 0x2 },
-               { "Mix", 0x3 },
-       },
-};
-
-static const struct snd_kcontrol_new ad1884a_base_mixers[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
-       HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               /* The multiple "Capture Source" controls confuse alsamixer
-                * So call somewhat different..
-                */
-               /* .name = "Capture Source", */
-               .name = "Input Source",
-               .count = 2,
-               .info = ad198x_mux_enum_info,
-               .get = ad198x_mux_enum_get,
-               .put = ad198x_mux_enum_put,
-       },
-       /* SPDIF controls */
-       HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
-               /* identical with ad1983 */
-               .info = ad1983_spdif_route_info,
-               .get = ad1983_spdif_route_get,
-               .put = ad1983_spdif_route_put,
-       },
-       { } /* end */
-};
-
-/*
- * initialization verbs
- */
-static const struct hda_verb ad1884a_init_verbs[] = {
-       /* DACs; unmute as default */
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
-       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
-       /* Port-A (HP) mixer - route only from analog mixer */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* Port-A pin */
-       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Port-D (Line-out) mixer - route only from analog mixer */
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* Port-D pin */
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Mono-out mixer - route only from analog mixer */
-       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* Mono-out pin */
-       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Port-B (front mic) pin */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       /* Port-C (rear line-in) pin */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       /* Port-E (rear mic) pin */
-       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* no boost */
-       /* Port-F (CD) pin */
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Analog mixer; mute as default */
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, /* aux */
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
-       /* Analog Mix output amp */
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* capture sources */
-       {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* SPDIF output amp */
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
-       { } /* end */
-};
-
-#ifdef CONFIG_PM
-static const struct hda_amp_list ad1884a_loopbacks[] = {
-       { 0x20, HDA_INPUT, 0 }, /* Front Mic */
-       { 0x20, HDA_INPUT, 1 }, /* Mic */
-       { 0x20, HDA_INPUT, 2 }, /* CD */
-       { 0x20, HDA_INPUT, 4 }, /* Docking */
-       { } /* end */
-};
-#endif
-
-/*
- * Laptop model
- *
- * Port A: Headphone jack
- * Port B: MIC jack
- * Port C: Internal MIC
- * Port D: Dock Line Out (if enabled)
- * Port E: Dock Line In (if enabled)
- * Port F: Internal speakers
- */
-
-static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol,
-                                       struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       int ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
-       int mute = (!ucontrol->value.integer.value[0] &&
-                   !ucontrol->value.integer.value[1]);
-       /* toggle GPIO1 according to the mute state */
-       snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
-                           mute ? 0x02 : 0x0);
-       return ret;
-}
-
-static const struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Master Playback Switch",
-               .subdevice = HDA_SUBDEV_AMP_FLAG,
-               .info = snd_hda_mixer_amp_switch_info,
-               .get = snd_hda_mixer_amp_switch_get,
-               .put = ad1884a_mobile_master_sw_put,
-               .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
-       },
-       HDA_CODEC_MUTE("Dock Playback Switch", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
-       HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new ad1884a_mobile_mixers[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
-       /*HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Master Playback Switch",
-               .subdevice = HDA_SUBDEV_AMP_FLAG,
-               .info = snd_hda_mixer_amp_switch_info,
-               .get = snd_hda_mixer_amp_switch_get,
-               .put = ad1884a_mobile_master_sw_put,
-               .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
-       },
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
-       HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Capture Volume", 0x14, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x15, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
-/* mute internal speaker if HP is plugged */
-static void ad1884a_hp_automute(struct hda_codec *codec)
-{
-       unsigned int present;
-
-       present = snd_hda_jack_detect(codec, 0x11);
-       snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-       snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE,
-                           present ? 0x00 : 0x02);
-}
-
-/* switch to external mic if plugged */
-static void ad1884a_hp_automic(struct hda_codec *codec)
-{
-       unsigned int present;
-
-       present = snd_hda_jack_detect(codec, 0x14);
-       snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL,
-                           present ? 0 : 1);
-}
-
-#define AD1884A_HP_EVENT               0x37
-#define AD1884A_MIC_EVENT              0x36
-
-/* unsolicited event for HP jack sensing */
-static void ad1884a_hp_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-       switch (res >> 26) {
-       case AD1884A_HP_EVENT:
-               ad1884a_hp_automute(codec);
-               break;
-       case AD1884A_MIC_EVENT:
-               ad1884a_hp_automic(codec);
-               break;
-       }
-}
-
-/* initialize jack-sensing, too */
-static int ad1884a_hp_init(struct hda_codec *codec)
-{
-       ad198x_init(codec);
-       ad1884a_hp_automute(codec);
-       ad1884a_hp_automic(codec);
-       return 0;
-}
-
-/* mute internal speaker if HP or docking HP is plugged */
-static void ad1884a_laptop_automute(struct hda_codec *codec)
-{
-       unsigned int present;
-
-       present = snd_hda_jack_detect(codec, 0x11);
-       if (!present)
-               present = snd_hda_jack_detect(codec, 0x12);
-       snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-       snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE,
-                           present ? 0x00 : 0x02);
-}
-
-/* switch to external mic if plugged */
-static void ad1884a_laptop_automic(struct hda_codec *codec)
-{
-       unsigned int idx;
-
-       if (snd_hda_jack_detect(codec, 0x14))
-               idx = 0;
-       else if (snd_hda_jack_detect(codec, 0x1c))
-               idx = 4;
-       else
-               idx = 1;
-       snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL, idx);
-}
-
-/* unsolicited event for HP jack sensing */
-static void ad1884a_laptop_unsol_event(struct hda_codec *codec,
-                                      unsigned int res)
-{
-       switch (res >> 26) {
-       case AD1884A_HP_EVENT:
-               ad1884a_laptop_automute(codec);
-               break;
-       case AD1884A_MIC_EVENT:
-               ad1884a_laptop_automic(codec);
-               break;
-       }
-}
-
-/* initialize jack-sensing, too */
-static int ad1884a_laptop_init(struct hda_codec *codec)
-{
-       ad198x_init(codec);
-       ad1884a_laptop_automute(codec);
-       ad1884a_laptop_automic(codec);
-       return 0;
-}
-
-/* additional verbs for laptop model */
-static const struct hda_verb ad1884a_laptop_verbs[] = {
-       /* Port-A (HP) pin - always unmuted */
-       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Port-F (int speaker) mixer - route only from analog mixer */
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* Port-F (int speaker) pin */
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* required for compaq 6530s/6531s speaker output */
-       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       /* Port-C pin - internal mic-in */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
-       /* Port-D (docking line-out) pin - default unmuted */
-       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* analog mix */
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       /* unsolicited event for pin-sense */
-       {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
-       {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
-       {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
-       /* allow to touch GPIO1 (for mute control) */
-       {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
-       {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
-       {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
-       { } /* end */
-};
-
-static const struct hda_verb ad1884a_mobile_verbs[] = {
-       /* DACs; unmute as default */
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
-       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
-       /* Port-A (HP) mixer - route only from analog mixer */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* Port-A pin */
-       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       /* Port-A (HP) pin - always unmuted */
-       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Port-B (mic jack) pin */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
-       /* Port-C (int mic) pin */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
-       /* Port-F (int speaker) mixer - route only from analog mixer */
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* Port-F pin */
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Analog mixer; mute as default */
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
-       /* Analog Mix output amp */
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* capture sources */
-       /* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* unsolicited event for pin-sense */
-       {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
-       /* allow to touch GPIO1 (for mute control) */
-       {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
-       {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
-       {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
-       { } /* end */
-};
-
-/*
- * Thinkpad X300
- * 0x11 - HP
- * 0x12 - speaker
- * 0x14 - mic-in
- * 0x17 - built-in mic
- */
-
-static const struct hda_verb ad1984a_thinkpad_verbs[] = {
-       /* HP unmute */
-       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* analog mix */
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       /* turn on EAPD */
-       {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
-       /* unsolicited event for pin-sense */
-       {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
-       /* internal mic - dmic */
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       /* set magic COEFs for dmic */
-       {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
-       {0x01, AC_VERB_SET_PROC_COEF, 0x08},
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
-       HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Capture Source",
-               .info = ad198x_mux_enum_info,
-               .get = ad198x_mux_enum_get,
-               .put = ad198x_mux_enum_put,
-       },
-       { } /* end */
-};
-
-static const struct hda_input_mux ad1984a_thinkpad_capture_source = {
-       .num_items = 3,
-       .items = {
-               { "Mic", 0x0 },
-               { "Internal Mic", 0x5 },
-               { "Mix", 0x3 },
-       },
-};
-
-/* mute internal speaker if HP is plugged */
-static void ad1984a_thinkpad_automute(struct hda_codec *codec)
-{
-       unsigned int present;
-
-       present = snd_hda_jack_detect(codec, 0x11);
-       snd_hda_codec_amp_stereo(codec, 0x12, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-}
-
-/* unsolicited event for HP jack sensing */
-static void ad1984a_thinkpad_unsol_event(struct hda_codec *codec,
-                                        unsigned int res)
-{
-       if ((res >> 26) != AD1884A_HP_EVENT)
-               return;
-       ad1984a_thinkpad_automute(codec);
-}
-
-/* initialize jack-sensing, too */
-static int ad1984a_thinkpad_init(struct hda_codec *codec)
-{
-       ad198x_init(codec);
-       ad1984a_thinkpad_automute(codec);
-       return 0;
-}
-
-/*
- * Precision R5500
- * 0x12 - HP/line-out
- * 0x13 - speaker (mono)
- * 0x15 - mic-in
- */
-
-static const struct hda_verb ad1984a_precision_verbs[] = {
-       /* Unmute main output path */
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x1f}, /* 0dB */
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) + 0x17}, /* 0dB */
-       /* Analog mixer; mute as default */
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       /* Select mic as input */
-       {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x27}, /* 0dB */
-       /* Configure as mic */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
-       /* HP unmute */
-       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* turn on EAPD */
-       {0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
-       /* unsolicited event for pin-sense */
-       {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new ad1984a_precision_mixers[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
-       HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
-
-/* mute internal speaker if HP is plugged */
-static void ad1984a_precision_automute(struct hda_codec *codec)
-{
-       unsigned int present;
-
-       present = snd_hda_jack_detect(codec, 0x12);
-       snd_hda_codec_amp_stereo(codec, 0x13, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-}
-
-
-/* unsolicited event for HP jack sensing */
-static void ad1984a_precision_unsol_event(struct hda_codec *codec,
-                                        unsigned int res)
-{
-       if ((res >> 26) != AD1884A_HP_EVENT)
-               return;
-       ad1984a_precision_automute(codec);
-}
-
-/* initialize jack-sensing, too */
-static int ad1984a_precision_init(struct hda_codec *codec)
-{
-       ad198x_init(codec);
-       ad1984a_precision_automute(codec);
-       return 0;
-}
-
-
-/*
- * HP Touchsmart
- * port-A (0x11)      - front hp-out
- * port-B (0x14)      - unused
- * port-C (0x15)      - unused
- * port-D (0x12)      - rear line out
- * port-E (0x1c)      - front mic-in
- * port-F (0x16)      - Internal speakers
- * digital-mic (0x17) - Internal mic
- */
-
-static const struct hda_verb ad1984a_touchsmart_verbs[] = {
-       /* DACs; unmute as default */
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
-       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
-       /* Port-A (HP) mixer - route only from analog mixer */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* Port-A pin */
-       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       /* Port-A (HP) pin - always unmuted */
-       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Port-E (int speaker) mixer - route only from analog mixer */
-       {0x25, AC_VERB_SET_AMP_GAIN_MUTE, 0x03},
-       /* Port-E pin */
-       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       /* Port-F (int speaker) mixer - route only from analog mixer */
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* Port-F pin */
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Analog mixer; mute as default */
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
-       /* Analog Mix output amp */
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* capture sources */
-       /* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* unsolicited event for pin-sense */
-       {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
-       {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
-       /* allow to touch GPIO1 (for mute control) */
-       {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
-       {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
-       {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
-       /* internal mic - dmic */
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       /* set magic COEFs for dmic */
-       {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
-       {0x01, AC_VERB_SET_PROC_COEF, 0x08},
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
-/*     HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .subdevice = HDA_SUBDEV_AMP_FLAG,
-               .name = "Master Playback Switch",
-               .info = snd_hda_mixer_amp_switch_info,
-               .get = snd_hda_mixer_amp_switch_get,
-               .put = ad1884a_mobile_master_sw_put,
-               .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
-       },
-       HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
-       HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT),
-       { } /* end */
-};
-
-/* switch to external mic if plugged */
-static void ad1984a_touchsmart_automic(struct hda_codec *codec)
-{
-       if (snd_hda_jack_detect(codec, 0x1c))
-               snd_hda_codec_write(codec, 0x0c, 0,
-                                    AC_VERB_SET_CONNECT_SEL, 0x4);
-       else
-               snd_hda_codec_write(codec, 0x0c, 0,
-                                    AC_VERB_SET_CONNECT_SEL, 0x5);
-}
-
-
-/* unsolicited event for HP jack sensing */
-static void ad1984a_touchsmart_unsol_event(struct hda_codec *codec,
-       unsigned int res)
-{
-       switch (res >> 26) {
-       case AD1884A_HP_EVENT:
-               ad1884a_hp_automute(codec);
-               break;
-       case AD1884A_MIC_EVENT:
-               ad1984a_touchsmart_automic(codec);
-               break;
-       }
-}
-
-/* initialize jack-sensing, too */
-static int ad1984a_touchsmart_init(struct hda_codec *codec)
-{
-       ad198x_init(codec);
-       ad1884a_hp_automute(codec);
-       ad1984a_touchsmart_automic(codec);
-       return 0;
-}
-
-
-/*
- */
-
-enum {
-       AD1884A_AUTO,
-       AD1884A_DESKTOP,
-       AD1884A_LAPTOP,
-       AD1884A_MOBILE,
-       AD1884A_THINKPAD,
-       AD1984A_TOUCHSMART,
-       AD1984A_PRECISION,
-       AD1884A_MODELS
-};
-
-static const char * const ad1884a_models[AD1884A_MODELS] = {
-       [AD1884A_AUTO]          = "auto",
-       [AD1884A_DESKTOP]       = "desktop",
-       [AD1884A_LAPTOP]        = "laptop",
-       [AD1884A_MOBILE]        = "mobile",
-       [AD1884A_THINKPAD]      = "thinkpad",
-       [AD1984A_TOUCHSMART]    = "touchsmart",
-       [AD1984A_PRECISION]     = "precision",
-};
-
-static const struct snd_pci_quirk ad1884a_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x1028, 0x04ac, "Precision R5500", AD1984A_PRECISION),
-       SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE),
-       SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP),
-       SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE),
-       SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x3070, "HP", AD1884A_MOBILE),
-       SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30d0, "HP laptop", AD1884A_LAPTOP),
-       SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30e0, "HP laptop", AD1884A_LAPTOP),
-       SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3600, "HP laptop", AD1884A_LAPTOP),
-       SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x7010, "HP laptop", AD1884A_MOBILE),
-       SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD),
-       SND_PCI_QUIRK(0x103c, 0x2a82, "Touchsmart", AD1984A_TOUCHSMART),
-       {}
-};
-
-static int patch_ad1884a(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec;
-       int err, board_config;
-
-       board_config = snd_hda_check_board_config(codec, AD1884A_MODELS,
-                                                 ad1884a_models,
-                                                 ad1884a_cfg_tbl);
-       if (board_config < 0) {
-               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-                      codec->chip_name);
-               board_config = AD1884A_AUTO;
-       }
-
-       if (board_config == AD1884A_AUTO)
-               return ad1884_parse_auto_config(codec);
-
-       err = alloc_ad_spec(codec);
-       if (err < 0)
-               return err;
-       spec = codec->spec;
-
-       err = snd_hda_attach_beep_device(codec, 0x10);
-       if (err < 0) {
-               ad198x_free(codec);
-               return err;
-       }
-       set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
-
-       spec->multiout.max_channels = 2;
-       spec->multiout.num_dacs = ARRAY_SIZE(ad1884a_dac_nids);
-       spec->multiout.dac_nids = ad1884a_dac_nids;
-       spec->multiout.dig_out_nid = AD1884A_SPDIF_OUT;
-       spec->num_adc_nids = ARRAY_SIZE(ad1884a_adc_nids);
-       spec->adc_nids = ad1884a_adc_nids;
-       spec->capsrc_nids = ad1884a_capsrc_nids;
-       spec->input_mux = &ad1884a_capture_source;
-       spec->num_mixers = 1;
-       spec->mixers[0] = ad1884a_base_mixers;
-       spec->num_init_verbs = 1;
-       spec->init_verbs[0] = ad1884a_init_verbs;
-       spec->spdif_route = 0;
-#ifdef CONFIG_PM
-       spec->loopback.amplist = ad1884a_loopbacks;
-#endif
-       codec->patch_ops = ad198x_patch_ops;
-
-       /* override some parameters */
-       switch (board_config) {
-       case AD1884A_LAPTOP:
-               spec->mixers[0] = ad1884a_laptop_mixers;
-               spec->init_verbs[spec->num_init_verbs++] = ad1884a_laptop_verbs;
-               spec->multiout.dig_out_nid = 0;
-               codec->patch_ops.unsol_event = ad1884a_laptop_unsol_event;
-               codec->patch_ops.init = ad1884a_laptop_init;
-               /* set the upper-limit for mixer amp to 0dB for avoiding the
-                * possible damage by overloading
-                */
-               snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
-                                         (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
-                                         (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
-                                         (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
-                                         (1 << AC_AMPCAP_MUTE_SHIFT));
-               break;
-       case AD1884A_MOBILE:
-               spec->mixers[0] = ad1884a_mobile_mixers;
-               spec->init_verbs[0] = ad1884a_mobile_verbs;
-               spec->multiout.dig_out_nid = 0;
-               codec->patch_ops.unsol_event = ad1884a_hp_unsol_event;
-               codec->patch_ops.init = ad1884a_hp_init;
-               /* set the upper-limit for mixer amp to 0dB for avoiding the
-                * possible damage by overloading
-                */
-               snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
-                                         (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
-                                         (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
-                                         (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
-                                         (1 << AC_AMPCAP_MUTE_SHIFT));
-               break;
-       case AD1884A_THINKPAD:
-               spec->mixers[0] = ad1984a_thinkpad_mixers;
-               spec->init_verbs[spec->num_init_verbs++] =
-                       ad1984a_thinkpad_verbs;
-               spec->multiout.dig_out_nid = 0;
-               spec->input_mux = &ad1984a_thinkpad_capture_source;
-               codec->patch_ops.unsol_event = ad1984a_thinkpad_unsol_event;
-               codec->patch_ops.init = ad1984a_thinkpad_init;
-               break;
-       case AD1984A_PRECISION:
-               spec->mixers[0] = ad1984a_precision_mixers;
-               spec->init_verbs[spec->num_init_verbs++] =
-                       ad1984a_precision_verbs;
-               spec->multiout.dig_out_nid = 0;
-               codec->patch_ops.unsol_event = ad1984a_precision_unsol_event;
-               codec->patch_ops.init = ad1984a_precision_init;
-               break;
-       case AD1984A_TOUCHSMART:
-               spec->mixers[0] = ad1984a_touchsmart_mixers;
-               spec->init_verbs[0] = ad1984a_touchsmart_verbs;
-               spec->multiout.dig_out_nid = 0;
-               codec->patch_ops.unsol_event = ad1984a_touchsmart_unsol_event;
-               codec->patch_ops.init = ad1984a_touchsmart_init;
-               /* set the upper-limit for mixer amp to 0dB for avoiding the
-                * possible damage by overloading
-                */
-               snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
-                                         (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
-                                         (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
-                                         (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
-                                         (1 << AC_AMPCAP_MUTE_SHIFT));
-               break;
-       }
-
-       codec->no_trigger_sense = 1;
-       codec->no_sticky_stream = 1;
-
-       return 0;
-}
-#else /* ENABLE_AD_STATIC_QUIRKS */
-#define patch_ad1884a  ad1884_parse_auto_config
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
-
 /*
  * AD1882 / AD1882A
  *
@@ -4850,299 +1058,7 @@ static int patch_ad1884a(struct hda_codec *codec)
  * port-G - rear clfe-out (6stack)
  */
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static const hda_nid_t ad1882_dac_nids[3] = {
-       0x04, 0x03, 0x05
-};
-
-static const hda_nid_t ad1882_adc_nids[2] = {
-       0x08, 0x09,
-};
-
-static const hda_nid_t ad1882_capsrc_nids[2] = {
-       0x0c, 0x0d,
-};
-
-#define AD1882_SPDIF_OUT       0x02
-
-/* list: 0x11, 0x39, 0x3a, 0x18, 0x3c, 0x3b, 0x12, 0x20 */
-static const struct hda_input_mux ad1882_capture_source = {
-       .num_items = 5,
-       .items = {
-               { "Front Mic", 0x1 },
-               { "Mic", 0x4 },
-               { "Line", 0x2 },
-               { "CD", 0x3 },
-               { "Mix", 0x7 },
-       },
-};
-
-/* list: 0x11, 0x39, 0x3a, 0x3c, 0x18, 0x1f, 0x12, 0x20 */
-static const struct hda_input_mux ad1882a_capture_source = {
-       .num_items = 5,
-       .items = {
-               { "Front Mic", 0x1 },
-               { "Mic", 0x4},
-               { "Line", 0x2 },
-               { "Digital Mic", 0x06 },
-               { "Mix", 0x7 },
-       },
-};
-
-static const struct snd_kcontrol_new ad1882_base_mixers[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
-
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Line-In Boost Volume", 0x3a, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               /* The multiple "Capture Source" controls confuse alsamixer
-                * So call somewhat different..
-                */
-               /* .name = "Capture Source", */
-               .name = "Input Source",
-               .count = 2,
-               .info = ad198x_mux_enum_info,
-               .get = ad198x_mux_enum_get,
-               .put = ad198x_mux_enum_put,
-       },
-       /* SPDIF controls */
-       HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
-               /* identical with ad1983 */
-               .info = ad1983_spdif_route_info,
-               .get = ad1983_spdif_route_get,
-               .put = ad1983_spdif_route_put,
-       },
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new ad1882_loopback_mixers[] = {
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new ad1882a_loopback_mixers[] = {
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
-       HDA_CODEC_VOLUME("Digital Mic Boost Volume", 0x1f, 0x0, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new ad1882_3stack_mixers[] = {
-       HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x17, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x17, 2, 0x0, HDA_OUTPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Channel Mode",
-               .info = ad198x_ch_mode_info,
-               .get = ad198x_ch_mode_get,
-               .put = ad198x_ch_mode_put,
-       },
-       { } /* end */
-};
-
-/* simple auto-mute control for AD1882 3-stack board */
-#define AD1882_HP_EVENT        0x01
-
-static void ad1882_3stack_automute(struct hda_codec *codec)
-{
-       bool mute = snd_hda_jack_detect(codec, 0x11);
-       snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-                           mute ? 0 : PIN_OUT);
-}
-
-static int ad1882_3stack_automute_init(struct hda_codec *codec)
-{
-       ad198x_init(codec);
-       ad1882_3stack_automute(codec);
-       return 0;
-}
-
-static void ad1882_3stack_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-       switch (res >> 26) {
-       case AD1882_HP_EVENT:
-               ad1882_3stack_automute(codec);
-               break;
-       }
-}
-
-static const struct snd_kcontrol_new ad1882_6stack_mixers[] = {
-       HDA_CODEC_MUTE("Surround Playback Switch", 0x16, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x24, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x24, 2, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
-static const struct hda_verb ad1882_ch2_init[] = {
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       { } /* end */
-};
-
-static const struct hda_verb ad1882_ch4_init[] = {
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       { } /* end */
-};
-
-static const struct hda_verb ad1882_ch6_init[] = {
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       { } /* end */
-};
-
-static const struct hda_channel_mode ad1882_modes[3] = {
-       { 2, ad1882_ch2_init },
-       { 4, ad1882_ch4_init },
-       { 6, ad1882_ch6_init },
-};
-
-/*
- * initialization verbs
- */
-static const struct hda_verb ad1882_init_verbs[] = {
-       /* DACs; mute as default */
-       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       /* Port-A (HP) mixer */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* Port-A pin */
-       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* HP selector - select DAC2 */
-       {0x37, AC_VERB_SET_CONNECT_SEL, 0x1},
-       /* Port-D (Line-out) mixer */
-       {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* Port-D pin */
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Mono-out mixer */
-       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* Mono-out pin */
-       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Port-B (front mic) pin */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
-       /* Port-C (line-in) pin */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
-       /* Port-C mixer - mute as input */
-       {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       /* Port-E (mic-in) pin */
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
-       /* Port-E mixer - mute as input */
-       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       /* Port-F (surround) */
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Port-G (CLFE) */
-       {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Analog mixer; mute as default */
-       /* list: 0x39, 0x3a, 0x11, 0x12, 0x3c, 0x3b, 0x18, 0x1a */
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
-       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
-       /* Analog Mix output amp */
-       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
-       /* SPDIF output selector */
-       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
-       {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
-       { } /* end */
-};
-
-static const struct hda_verb ad1882_3stack_automute_verbs[] = {
-       {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1882_HP_EVENT},
-       { } /* end */
-};
-
-#ifdef CONFIG_PM
-static const struct hda_amp_list ad1882_loopbacks[] = {
-       { 0x20, HDA_INPUT, 0 }, /* Front Mic */
-       { 0x20, HDA_INPUT, 1 }, /* Mic */
-       { 0x20, HDA_INPUT, 4 }, /* Line */
-       { 0x20, HDA_INPUT, 6 }, /* CD */
-       { } /* end */
-};
-#endif
-
-/* models */
-enum {
-       AD1882_AUTO,
-       AD1882_3STACK,
-       AD1882_6STACK,
-       AD1882_3STACK_AUTOMUTE,
-       AD1882_MODELS
-};
-
-static const char * const ad1882_models[AD1986A_MODELS] = {
-       [AD1882_AUTO]           = "auto",
-       [AD1882_3STACK]         = "3stack",
-       [AD1882_6STACK]         = "6stack",
-       [AD1882_3STACK_AUTOMUTE] = "3stack-automute",
-};
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
-static int ad1882_parse_auto_config(struct hda_codec *codec)
+static int patch_ad1882(struct hda_codec *codec)
 {
        struct ad198x_spec *spec;
        int err;
@@ -5169,110 +1085,20 @@ static int ad1882_parse_auto_config(struct hda_codec *codec)
        return err;
 }
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static int patch_ad1882(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec;
-       int err, board_config;
-
-       board_config = snd_hda_check_board_config(codec, AD1882_MODELS,
-                                                 ad1882_models, NULL);
-       if (board_config < 0) {
-               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-                      codec->chip_name);
-               board_config = AD1882_AUTO;
-       }
-
-       if (board_config == AD1882_AUTO)
-               return ad1882_parse_auto_config(codec);
-
-       err = alloc_ad_spec(codec);
-       if (err < 0)
-               return err;
-       spec = codec->spec;
-
-       err = snd_hda_attach_beep_device(codec, 0x10);
-       if (err < 0) {
-               ad198x_free(codec);
-               return err;
-       }
-       set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
-
-       spec->multiout.max_channels = 6;
-       spec->multiout.num_dacs = 3;
-       spec->multiout.dac_nids = ad1882_dac_nids;
-       spec->multiout.dig_out_nid = AD1882_SPDIF_OUT;
-       spec->num_adc_nids = ARRAY_SIZE(ad1882_adc_nids);
-       spec->adc_nids = ad1882_adc_nids;
-       spec->capsrc_nids = ad1882_capsrc_nids;
-       if (codec->vendor_id == 0x11d41882)
-               spec->input_mux = &ad1882_capture_source;
-       else
-               spec->input_mux = &ad1882a_capture_source;
-       spec->num_mixers = 2;
-       spec->mixers[0] = ad1882_base_mixers;
-       if (codec->vendor_id == 0x11d41882)
-               spec->mixers[1] = ad1882_loopback_mixers;
-       else
-               spec->mixers[1] = ad1882a_loopback_mixers;
-       spec->num_init_verbs = 1;
-       spec->init_verbs[0] = ad1882_init_verbs;
-       spec->spdif_route = 0;
-#ifdef CONFIG_PM
-       spec->loopback.amplist = ad1882_loopbacks;
-#endif
-       spec->vmaster_nid = 0x04;
-
-       codec->patch_ops = ad198x_patch_ops;
-
-       /* override some parameters */
-       switch (board_config) {
-       default:
-       case AD1882_3STACK:
-       case AD1882_3STACK_AUTOMUTE:
-               spec->num_mixers = 3;
-               spec->mixers[2] = ad1882_3stack_mixers;
-               spec->channel_mode = ad1882_modes;
-               spec->num_channel_mode = ARRAY_SIZE(ad1882_modes);
-               spec->need_dac_fix = 1;
-               spec->multiout.max_channels = 2;
-               spec->multiout.num_dacs = 1;
-               if (board_config != AD1882_3STACK) {
-                       spec->init_verbs[spec->num_init_verbs++] =
-                               ad1882_3stack_automute_verbs;
-                       codec->patch_ops.unsol_event = ad1882_3stack_unsol_event;
-                       codec->patch_ops.init = ad1882_3stack_automute_init;
-               }
-               break;
-       case AD1882_6STACK:
-               spec->num_mixers = 3;
-               spec->mixers[2] = ad1882_6stack_mixers;
-               break;
-       }
-
-       codec->no_trigger_sense = 1;
-       codec->no_sticky_stream = 1;
-
-       return 0;
-}
-#else /* ENABLE_AD_STATIC_QUIRKS */
-#define patch_ad1882   ad1882_parse_auto_config
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
 
 /*
  * patch entries
  */
 static const struct hda_codec_preset snd_hda_preset_analog[] = {
-       { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884a },
+       { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884 },
        { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 },
-       { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884a },
+       { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884 },
        { .id = 0x11d41884, .name = "AD1884", .patch = patch_ad1884 },
-       { .id = 0x11d4194a, .name = "AD1984A", .patch = patch_ad1884a },
-       { .id = 0x11d4194b, .name = "AD1984B", .patch = patch_ad1884a },
+       { .id = 0x11d4194a, .name = "AD1984A", .patch = patch_ad1884 },
+       { .id = 0x11d4194b, .name = "AD1984B", .patch = patch_ad1884 },
        { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 },
        { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 },
-       { .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1984 },
+       { .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1884 },
        { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a },
        { .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 },
        { .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 },
index de00ce166470d5c73ac646c452f8a3ccd86e717a..4edd2d0f9a3ce66e625f7576b3b7053548397a51 100644 (file)
@@ -66,6 +66,8 @@ struct conexant_spec {
        hda_nid_t eapds[4];
        bool dynamic_eapd;
 
+       unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */
+
 #ifdef ENABLE_CXT_STATIC_QUIRKS
        const struct snd_kcontrol_new *mixers[5];
        int num_mixers;
@@ -3200,6 +3202,9 @@ static int cx_auto_init(struct hda_codec *codec)
        snd_hda_gen_init(codec);
        if (!spec->dynamic_eapd)
                cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true);
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
+
        return 0;
 }
 
@@ -3224,6 +3229,8 @@ enum {
        CXT_PINCFG_LEMOTE_A1205,
        CXT_FIXUP_STEREO_DMIC,
        CXT_FIXUP_INC_MIC_BOOST,
+       CXT_FIXUP_HEADPHONE_MIC_PIN,
+       CXT_FIXUP_HEADPHONE_MIC,
 };
 
 static void cxt_fixup_stereo_dmic(struct hda_codec *codec,
@@ -3246,6 +3253,59 @@ static void cxt5066_increase_mic_boost(struct hda_codec *codec,
                                  (0 << AC_AMPCAP_MUTE_SHIFT));
 }
 
+static void cxt_update_headset_mode(struct hda_codec *codec)
+{
+       /* The verbs used in this function were tested on a Conexant CX20751/2 codec. */
+       int i;
+       bool mic_mode = false;
+       struct conexant_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->gen.autocfg;
+
+       hda_nid_t mux_pin = spec->gen.imux_pins[spec->gen.cur_mux[0]];
+
+       for (i = 0; i < cfg->num_inputs; i++)
+               if (cfg->inputs[i].pin == mux_pin) {
+                       mic_mode = !!cfg->inputs[i].is_headphone_mic;
+                       break;
+               }
+
+       if (mic_mode) {
+               snd_hda_codec_write_cache(codec, 0x1c, 0, 0x410, 0x7c); /* enable merged mode for analog int-mic */
+               spec->gen.hp_jack_present = false;
+       } else {
+               snd_hda_codec_write_cache(codec, 0x1c, 0, 0x410, 0x54); /* disable merged mode for analog int-mic */
+               spec->gen.hp_jack_present = snd_hda_jack_detect(codec, spec->gen.autocfg.hp_pins[0]);
+       }
+
+       snd_hda_gen_update_outputs(codec);
+}
+
+static void cxt_update_headset_mode_hook(struct hda_codec *codec,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       cxt_update_headset_mode(codec);
+}
+
+static void cxt_fixup_headphone_mic(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+       struct conexant_spec *spec = codec->spec;
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               spec->parse_flags |= HDA_PINCFG_HEADPHONE_MIC;
+               break;
+       case HDA_FIXUP_ACT_PROBE:
+               spec->gen.cap_sync_hook = cxt_update_headset_mode_hook;
+               spec->gen.automute_hook = cxt_update_headset_mode;
+               break;
+       case HDA_FIXUP_ACT_INIT:
+               cxt_update_headset_mode(codec);
+               break;
+       }
+}
+
+
 /* ThinkPad X200 & co with cxt5051 */
 static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = {
        { 0x16, 0x042140ff }, /* HP (seq# overridden) */
@@ -3302,6 +3362,19 @@ static const struct hda_fixup cxt_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = cxt5066_increase_mic_boost,
        },
+       [CXT_FIXUP_HEADPHONE_MIC_PIN] = {
+               .type = HDA_FIXUP_PINS,
+               .chained = true,
+               .chain_id = CXT_FIXUP_HEADPHONE_MIC,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x18, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
+                       { }
+               }
+       },
+       [CXT_FIXUP_HEADPHONE_MIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cxt_fixup_headphone_mic,
+       },
 };
 
 static const struct snd_pci_quirk cxt5051_fixups[] = {
@@ -3311,6 +3384,7 @@ static const struct snd_pci_quirk cxt5051_fixups[] = {
 
 static const struct snd_pci_quirk cxt5066_fixups[] = {
        SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC),
+       SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN),
        SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410),
        SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T410", CXT_PINCFG_LENOVO_TP410),
        SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410),
@@ -3395,7 +3469,8 @@ static int patch_conexant_auto(struct hda_codec *codec)
 
        snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
 
-       err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0);
+       err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL,
+                                      spec->parse_flags);
        if (err < 0)
                goto error;
 
@@ -3416,6 +3491,8 @@ static int patch_conexant_auto(struct hda_codec *codec)
                codec->bus->allow_bus_reset = 1;
        }
 
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
        return 0;
 
  error:
index 8bd2261498680676c0b62b7861fbd5be2aa4daac..ad7a0985edfe589c8cc85299d1c9b8dac61e5c6b 100644 (file)
@@ -282,6 +282,7 @@ static void alc_eapd_shutup(struct hda_codec *codec)
 {
        alc_auto_setup_eapd(codec, false);
        msleep(200);
+       snd_hda_shutup_pins(codec);
 }
 
 /* generic EAPD initialization */
@@ -826,7 +827,8 @@ static inline void alc_shutup(struct hda_codec *codec)
 
        if (spec && spec->shutup)
                spec->shutup(codec);
-       snd_hda_shutup_pins(codec);
+       else
+               snd_hda_shutup_pins(codec);
 }
 
 #define alc_free       snd_hda_gen_free
@@ -1843,8 +1845,10 @@ static void alc882_fixup_no_primary_hp(struct hda_codec *codec,
                                       const struct hda_fixup *fix, int action)
 {
        struct alc_spec *spec = codec->spec;
-       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
                spec->gen.no_primary_hp = 1;
+               spec->gen.no_multi_io = 1;
+       }
 }
 
 static const struct hda_fixup alc882_fixups[] = {
@@ -2573,15 +2577,13 @@ static void alc269_shutup(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
 
-       if (spec->codec_variant != ALC269_TYPE_ALC269VB)
-               return;
-
        if (spec->codec_variant == ALC269_TYPE_ALC269VB)
                alc269vb_toggle_power_output(codec, 0);
        if (spec->codec_variant == ALC269_TYPE_ALC269VB &&
                        (alc_get_coef0(codec) & 0x00ff) == 0x018) {
                msleep(150);
        }
+       snd_hda_shutup_pins(codec);
 }
 
 static void alc5505_coef_set(struct hda_codec *codec, unsigned int index_reg,
@@ -2712,6 +2714,13 @@ static int alc269_resume(struct hda_codec *codec)
        hda_call_check_power_status(codec, 0x01);
        if (spec->has_alc5505_dsp)
                alc5505_dsp_resume(codec);
+
+       /* clear the power-save mode for ALC283 */
+       if (codec->vendor_id == 0x10ec0283) {
+               alc_write_coef_idx(codec, 0x4, 0xaf01);
+               alc_write_coef_idx(codec, 0x6, 0x2104);
+       }
+
        return 0;
 }
 #endif /* CONFIG_PM */
@@ -3775,6 +3784,30 @@ static void alc269_fill_coef(struct hda_codec *codec)
        alc_write_coef_idx(codec, 0x4, val | (1<<11));
 }
 
+/* don't clear mic pin; otherwise it results in noise in D3 */
+static void alc283_headset_shutup(struct hda_codec *codec)
+{
+       int i;
+
+       if (codec->bus->shutdown)
+               return;
+
+       for (i = 0; i < codec->init_pins.used; i++) {
+               struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i);
+               /* use read here for syncing after issuing each verb */
+               if (pin->nid != 0x19)
+                       snd_hda_codec_read(codec, pin->nid, 0,
+                                          AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
+       }
+
+       alc_write_coef_idx(codec, 0x4, 0x0f01); /* power save */
+       alc_write_coef_idx(codec, 0x6, 0x2100); /* power save */
+       snd_hda_codec_write(codec, 0x19, 0,
+                       AC_VERB_SET_PIN_WIDGET_CONTROL,
+                       PIN_VREFHIZ);
+       codec->pins_shutup = 1;
+}
+
 /*
  */
 static int patch_alc269(struct hda_codec *codec)
@@ -3789,6 +3822,9 @@ static int patch_alc269(struct hda_codec *codec)
        spec = codec->spec;
        spec->gen.shared_mic_vref_pin = 0x18;
 
+       if (codec->vendor_id == 0x10ec0283)
+               spec->shutup = alc283_headset_shutup;
+
        snd_hda_pick_fixup(codec, alc269_fixup_models,
                       alc269_fixup_tbl, alc269_fixups);
        snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
@@ -3862,7 +3898,8 @@ static int patch_alc269(struct hda_codec *codec)
        codec->patch_ops.suspend = alc269_suspend;
        codec->patch_ops.resume = alc269_resume;
 #endif
-       spec->shutup = alc269_shutup;
+       if (!spec->shutup)
+               spec->shutup = alc269_shutup;
 
        snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
 
index 92b9b4324372e8f9d15aba987c3a55a4cb6945c0..ef0a22fd05dfca46aebe4f29adbfc1876ccc64f7 100644 (file)
@@ -158,6 +158,7 @@ enum {
        STAC_D965_VERBS,
        STAC_DELL_3ST,
        STAC_DELL_BIOS,
+       STAC_DELL_BIOS_AMIC,
        STAC_DELL_BIOS_SPDIF,
        STAC_927X_DELL_DMIC,
        STAC_927X_VOLKNOB,
@@ -3230,8 +3231,6 @@ static const struct hda_fixup stac927x_fixups[] = {
        [STAC_DELL_BIOS] = {
                .type = HDA_FIXUP_PINS,
                .v.pins = (const struct hda_pintbl[]) {
-                       /* configure the analog microphone on some laptops */
-                       { 0x0c, 0x90a79130 },
                        /* correct the front output jack as a hp out */
                        { 0x0f, 0x0221101f },
                        /* correct the front input jack as a mic */
@@ -3241,6 +3240,16 @@ static const struct hda_fixup stac927x_fixups[] = {
                .chained = true,
                .chain_id = STAC_927X_DELL_DMIC,
        },
+       [STAC_DELL_BIOS_AMIC] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       /* configure the analog microphone on some laptops */
+                       { 0x0c, 0x90a79130 },
+                       {}
+               },
+               .chained = true,
+               .chain_id = STAC_DELL_BIOS,
+       },
        [STAC_DELL_BIOS_SPDIF] = {
                .type = HDA_FIXUP_PINS,
                .v.pins = (const struct hda_pintbl[]) {
@@ -3269,6 +3278,7 @@ static const struct hda_model_fixup stac927x_models[] = {
        { .id = STAC_D965_5ST_NO_FP, .name = "5stack-no-fp" },
        { .id = STAC_DELL_3ST, .name = "dell-3stack" },
        { .id = STAC_DELL_BIOS, .name = "dell-bios" },
+       { .id = STAC_DELL_BIOS_AMIC, .name = "dell-bios-amic" },
        { .id = STAC_927X_VOLKNOB, .name = "volknob" },
        {}
 };
index e2481baddc70ff6ff265ee0ed118377869847db6..0bc20ef5687ac3558996ca3fd56a741c75bc042b 100644 (file)
@@ -207,9 +207,9 @@ static void vt1708_stop_hp_work(struct hda_codec *codec)
                return;
        if (spec->hp_work_active) {
                snd_hda_codec_write(codec, 0x1, 0, 0xf81, 1);
+               codec->jackpoll_interval = 0;
                cancel_delayed_work_sync(&codec->jackpoll_work);
                spec->hp_work_active = false;
-               codec->jackpoll_interval = 0;
        }
 }
 
index bd501931ee2341f1a6f913dc1b21a967268de704..ec6335e2fda0df2c7f000c0e8ea43ab81608eab4 100644 (file)
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  *
  */
+
+/* *************    Register Documentation   *******************************************************
+ *
+ * Work in progress! Documentation is based on the code in this file.
+ *
+ * --------- HDSPM_controlRegister ---------
+ * :7654.3210:7654.3210:7654.3210:7654.3210: bit number per byte
+ * :||||.||||:||||.||||:||||.||||:||||.||||:
+ * :3322.2222:2222.1111:1111.1100:0000.0000: bit number
+ * :1098.7654:3210.9876:5432.1098:7654.3210: 0..31
+ * :||||.||||:||||.||||:||||.||||:||||.||||:
+ * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit
+ * :    .    :    .    :    .    :  x .    :  HDSPM_AudioInterruptEnable \_ setting both bits
+ * :    .    :    .    :    .    :    .   x:  HDSPM_Start                /  enables audio IO
+ * :    .    :    .    :    .    :   x.    :  HDSPM_ClockModeMaster - 1: Master, 0: Slave
+ * :    .    :    .    :    .    :    .210 :  HDSPM_LatencyMask - 3 Bit value for latency
+ * :    .    :    .    :    .    :    .    :      0:64, 1:128, 2:256, 3:512,
+ * :    .    :    .    :    .    :    .    :      4:1024, 5:2048, 6:4096, 7:8192
+ * :x   .    :    .    :    .   x:xx  .    :  HDSPM_FrequencyMask
+ * :    .    :    .    :    .    :10  .    :  HDSPM_Frequency1|HDSPM_Frequency0: 1=32K,2=44.1K,3=48K,0=??
+ * :    .    :    .    :    .   x:    .    :  <MADI> HDSPM_DoubleSpeed
+ * :x   .    :    .    :    .    :    .    :  <MADI> HDSPM_QuadSpeed
+ * :    .  3 :    .  10:  2 .    :    .    :  HDSPM_SyncRefMask :
+ * :    .    :    .   x:    .    :    .    :  HDSPM_SyncRef0
+ * :    .    :    .  x :    .    :    .    :  HDSPM_SyncRef1
+ * :    .    :    .    :  x .    :    .    :  <AES32> HDSPM_SyncRef2
+ * :    .  x :    .    :    .    :    .    :  <AES32> HDSPM_SyncRef3
+ * :    .    :    .  10:    .    :    .    :  <MADI> sync ref: 0:WC, 1:Madi, 2:TCO, 3:SyncIn
+ * :    .  3 :    .  10:  2 .    :    .    :  <AES32>  0:WC, 1:AES1 ... 8:AES8, 9: TCO, 10:SyncIn?
+ * :    .  x :    .    :    .    :    .    :  <MADIe> HDSPe_FLOAT_FORMAT
+ * :    .    :    .    : x  .    :    .    :  <MADI> HDSPM_InputSelect0 : 0=optical,1=coax
+ * :    .    :    .    :x   .    :    .    :  <MADI> HDSPM_InputSelect1
+ * :    .    :    .x   :    .    :    .    :  <MADI> HDSPM_clr_tms
+ * :    .    :    .    :    . x  :    .    :  <MADI> HDSPM_TX_64ch
+ * :    .    :    .    :    . x  :    .    :  <AES32> HDSPM_Emphasis
+ * :    .    :    .    :    .x   :    .    :  <MADI> HDSPM_AutoInp
+ * :    .    :    . x  :    .    :    .    :  <MADI> HDSPM_SMUX
+ * :    .    :    .x   :    .    :    .    :  <MADI> HDSPM_clr_tms
+ * :    .    :   x.    :    .    :    .    :  <MADI> HDSPM_taxi_reset
+ * :    .   x:    .    :    .    :    .    :  <MADI> HDSPM_LineOut
+ * :    .   x:    .    :    .    :    .    :  <AES32> ??????????????????
+ * :    .    :   x.    :    .    :    .    :  <AES32> HDSPM_WCK48
+ * :    .    :    .    :    .x   :    .    :  <AES32> HDSPM_Dolby
+ * :    .    : x  .    :    .    :    .    :  HDSPM_Midi0InterruptEnable
+ * :    .    :x   .    :    .    :    .    :  HDSPM_Midi1InterruptEnable
+ * :    .    :  x .    :    .    :    .    :  HDSPM_Midi2InterruptEnable
+ * :    . x  :    .    :    .    :    .    :  <MADI> HDSPM_Midi3InterruptEnable
+ * :    . x  :    .    :    .    :    .    :  <AES32> HDSPM_DS_DoubleWire
+ * :    .x   :    .    :    .    :    .    :  <AES32> HDSPM_QS_DoubleWire
+ * :   x.    :    .    :    .    :    .    :  <AES32> HDSPM_QS_QuadWire
+ * :    .    :    .    :    .  x :    .    :  <AES32> HDSPM_Professional
+ * : x  .    :    .    :    .    :    .    :  HDSPM_wclk_sel
+ * :    .    :    .    :    .    :    .    :
+ * :7654.3210:7654.3210:7654.3210:7654.3210: bit number per byte
+ * :||||.||||:||||.||||:||||.||||:||||.||||:
+ * :3322.2222:2222.1111:1111.1100:0000.0000: bit number
+ * :1098.7654:3210.9876:5432.1098:7654.3210: 0..31
+ * :||||.||||:||||.||||:||||.||||:||||.||||:
+ * :8421.8421:8421.8421:8421.8421:8421.8421:hex digit
+ *
+ *
+ *
+ * AIO / RayDAT only
+ *
+ * ------------ HDSPM_WR_SETTINGS ----------
+ * :3322.2222:2222.1111:1111.1100:0000.0000: bit number per byte
+ * :1098.7654:3210.9876:5432.1098:7654.3210:
+ * :||||.||||:||||.||||:||||.||||:||||.||||: bit number
+ * :7654.3210:7654.3210:7654.3210:7654.3210: 0..31
+ * :||||.||||:||||.||||:||||.||||:||||.||||:
+ * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit
+ * :    .    :    .    :    .    :    .   x: HDSPM_c0Master 1: Master, 0: Slave
+ * :    .    :    .    :    .    :    .  x : HDSPM_c0_SyncRef0
+ * :    .    :    .    :    .    :    . x  : HDSPM_c0_SyncRef1
+ * :    .    :    .    :    .    :    .x   : HDSPM_c0_SyncRef2
+ * :    .    :    .    :    .    :   x.    : HDSPM_c0_SyncRef3
+ * :    .    :    .    :    .    :   3.210 : HDSPM_c0_SyncRefMask:
+ * :    .    :    .    :    .    :    .    :  RayDat: 0:WC, 1:AES, 2:SPDIF, 3..6: ADAT1..4,
+ * :    .    :    .    :    .    :    .    :          9:TCO, 10:SyncIn
+ * :    .    :    .    :    .    :    .    :  AIO: 0:WC, 1:AES, 2: SPDIF, 3: ATAT,
+ * :    .    :    .    :    .    :    .    :          9:TCO, 10:SyncIn
+ * :    .    :    .    :    .    :    .    :
+ * :    .    :    .    :    .    :    .    :
+ * :3322.2222:2222.1111:1111.1100:0000.0000: bit number per byte
+ * :1098.7654:3210.9876:5432.1098:7654.3210:
+ * :||||.||||:||||.||||:||||.||||:||||.||||: bit number
+ * :7654.3210:7654.3210:7654.3210:7654.3210: 0..31
+ * :||||.||||:||||.||||:||||.||||:||||.||||:
+ * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit
+ *
+ */
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -95,7 +186,7 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
 #define HDSPM_controlRegister       64
 #define HDSPM_interruptConfirmation  96
 #define HDSPM_control2Reg           256  /* not in specs ???????? */
-#define HDSPM_freqReg                256  /* for AES32 */
+#define HDSPM_freqReg                256  /* for setting arbitrary clock values (DDS feature) */
 #define HDSPM_midiDataOut0          352  /* just believe in old code */
 #define HDSPM_midiDataOut1          356
 #define HDSPM_eeprom_wr                     384  /* for AES32 */
@@ -258,6 +349,25 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
 
 #define HDSPM_wclk_sel (1<<30)
 
+/* additional control register bits for AIO*/
+#define HDSPM_c0_Wck48                         0x20 /* also RayDAT */
+#define HDSPM_c0_Input0                                0x1000
+#define HDSPM_c0_Input1                                0x2000
+#define HDSPM_c0_Spdif_Opt                     0x4000
+#define HDSPM_c0_Pro                           0x8000
+#define HDSPM_c0_clr_tms                       0x10000
+#define HDSPM_c0_AEB1                          0x20000
+#define HDSPM_c0_AEB2                          0x40000
+#define HDSPM_c0_LineOut                       0x80000
+#define HDSPM_c0_AD_GAIN0                      0x100000
+#define HDSPM_c0_AD_GAIN1                      0x200000
+#define HDSPM_c0_DA_GAIN0                      0x400000
+#define HDSPM_c0_DA_GAIN1                      0x800000
+#define HDSPM_c0_PH_GAIN0                      0x1000000
+#define HDSPM_c0_PH_GAIN1                      0x2000000
+#define HDSPM_c0_Sym6db                                0x4000000
+
+
 /* --- bit helper defines */
 #define HDSPM_LatencyMask    (HDSPM_Latency0|HDSPM_Latency1|HDSPM_Latency2)
 #define HDSPM_FrequencyMask  (HDSPM_Frequency0|HDSPM_Frequency1|\
@@ -341,11 +451,11 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
 #define HDSPM_madiLock           (1<<3)        /* MADI Locked =1, no=0 */
 #define HDSPM_madiSync          (1<<18) /* MADI is in sync */
 
-#define HDSPM_tcoLock    0x00000020 /* Optional TCO locked status FOR HDSPe MADI! */
-#define HDSPM_tcoSync    0x10000000 /* Optional TCO sync status */
+#define HDSPM_tcoLockMadi    0x00000020 /* Optional TCO locked status for HDSPe MADI*/
+#define HDSPM_tcoSync    0x10000000 /* Optional TCO sync status for HDSPe MADI and AES32!*/
 
-#define HDSPM_syncInLock 0x00010000 /* Sync In lock status FOR HDSPe MADI! */
-#define HDSPM_syncInSync 0x00020000 /* Sync In sync status FOR HDSPe MADI! */
+#define HDSPM_syncInLock 0x00010000 /* Sync In lock status for HDSPe MADI! */
+#define HDSPM_syncInSync 0x00020000 /* Sync In sync status for HDSPe MADI! */
 
 #define HDSPM_BufferPositionMask 0x000FFC0 /* Bit 6..15 : h/w buffer pointer */
                        /* since 64byte accurate, last 6 bits are not used */
@@ -363,7 +473,7 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
                                         * Interrupt
                                         */
 #define HDSPM_tco_detect         0x08000000
-#define HDSPM_tco_lock          0x20000000
+#define HDSPM_tcoLockAes         0x20000000 /* Optional TCO locked status for HDSPe AES */
 
 #define HDSPM_s2_tco_detect      0x00000040
 #define HDSPM_s2_AEBO_D          0x00000080
@@ -461,7 +571,9 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
 #define HDSPM_AES32_AUTOSYNC_FROM_AES6 6
 #define HDSPM_AES32_AUTOSYNC_FROM_AES7 7
 #define HDSPM_AES32_AUTOSYNC_FROM_AES8 8
-#define HDSPM_AES32_AUTOSYNC_FROM_NONE 9
+#define HDSPM_AES32_AUTOSYNC_FROM_TCO 9
+#define HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN 10
+#define HDSPM_AES32_AUTOSYNC_FROM_NONE 11
 
 /*  status2 */
 /* HDSPM_LockAES_bit is given by HDSPM_LockAES >> (AES# - 1) */
@@ -537,36 +649,39 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
 /* names for speed modes */
 static char *hdspm_speed_names[] = { "single", "double", "quad" };
 
-static char *texts_autosync_aes_tco[] = { "Word Clock",
+static const char *const texts_autosync_aes_tco[] = { "Word Clock",
                                          "AES1", "AES2", "AES3", "AES4",
                                          "AES5", "AES6", "AES7", "AES8",
-                                         "TCO" };
-static char *texts_autosync_aes[] = { "Word Clock",
+                                         "TCO", "Sync In"
+};
+static const char *const texts_autosync_aes[] = { "Word Clock",
                                      "AES1", "AES2", "AES3", "AES4",
-                                     "AES5", "AES6", "AES7", "AES8" };
-static char *texts_autosync_madi_tco[] = { "Word Clock",
+                                     "AES5", "AES6", "AES7", "AES8",
+                                     "Sync In"
+};
+static const char *const texts_autosync_madi_tco[] = { "Word Clock",
                                           "MADI", "TCO", "Sync In" };
-static char *texts_autosync_madi[] = { "Word Clock",
+static const char *const texts_autosync_madi[] = { "Word Clock",
                                       "MADI", "Sync In" };
 
-static char *texts_autosync_raydat_tco[] = {
+static const char *const texts_autosync_raydat_tco[] = {
        "Word Clock",
        "ADAT 1", "ADAT 2", "ADAT 3", "ADAT 4",
        "AES", "SPDIF", "TCO", "Sync In"
 };
-static char *texts_autosync_raydat[] = {
+static const char *const texts_autosync_raydat[] = {
        "Word Clock",
        "ADAT 1", "ADAT 2", "ADAT 3", "ADAT 4",
        "AES", "SPDIF", "Sync In"
 };
-static char *texts_autosync_aio_tco[] = {
+static const char *const texts_autosync_aio_tco[] = {
        "Word Clock",
        "ADAT", "AES", "SPDIF", "TCO", "Sync In"
 };
-static char *texts_autosync_aio[] = { "Word Clock",
+static const char *const texts_autosync_aio[] = { "Word Clock",
                                      "ADAT", "AES", "SPDIF", "Sync In" };
 
-static char *texts_freq[] = {
+static const char *const texts_freq[] = {
        "No Lock",
        "32 kHz",
        "44.1 kHz",
@@ -629,7 +744,8 @@ static char *texts_ports_aio_in_ss[] = {
        "AES.L", "AES.R",
        "SPDIF.L", "SPDIF.R",
        "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", "ADAT.5", "ADAT.6",
-       "ADAT.7", "ADAT.8"
+       "ADAT.7", "ADAT.8",
+       "AEB.1", "AEB.2", "AEB.3", "AEB.4"
 };
 
 static char *texts_ports_aio_out_ss[] = {
@@ -638,14 +754,16 @@ static char *texts_ports_aio_out_ss[] = {
        "SPDIF.L", "SPDIF.R",
        "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", "ADAT.5", "ADAT.6",
        "ADAT.7", "ADAT.8",
-       "Phone.L", "Phone.R"
+       "Phone.L", "Phone.R",
+       "AEB.1", "AEB.2", "AEB.3", "AEB.4"
 };
 
 static char *texts_ports_aio_in_ds[] = {
        "Analogue.L", "Analogue.R",
        "AES.L", "AES.R",
        "SPDIF.L", "SPDIF.R",
-       "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4"
+       "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4",
+       "AEB.1", "AEB.2", "AEB.3", "AEB.4"
 };
 
 static char *texts_ports_aio_out_ds[] = {
@@ -653,14 +771,16 @@ static char *texts_ports_aio_out_ds[] = {
        "AES.L", "AES.R",
        "SPDIF.L", "SPDIF.R",
        "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4",
-       "Phone.L", "Phone.R"
+       "Phone.L", "Phone.R",
+       "AEB.1", "AEB.2", "AEB.3", "AEB.4"
 };
 
 static char *texts_ports_aio_in_qs[] = {
        "Analogue.L", "Analogue.R",
        "AES.L", "AES.R",
        "SPDIF.L", "SPDIF.R",
-       "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4"
+       "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4",
+       "AEB.1", "AEB.2", "AEB.3", "AEB.4"
 };
 
 static char *texts_ports_aio_out_qs[] = {
@@ -668,7 +788,8 @@ static char *texts_ports_aio_out_qs[] = {
        "AES.L", "AES.R",
        "SPDIF.L", "SPDIF.R",
        "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4",
-       "Phone.L", "Phone.R"
+       "Phone.L", "Phone.R",
+       "AEB.1", "AEB.2", "AEB.3", "AEB.4"
 };
 
 static char *texts_ports_aes32[] = {
@@ -745,8 +866,8 @@ static char channel_map_aio_in_ss[HDSPM_MAX_CHANNELS] = {
        8, 9,                   /* aes in, */
        10, 11,                 /* spdif in */
        12, 13, 14, 15, 16, 17, 18, 19, /* ADAT in */
-       -1, -1,
-       -1, -1, -1, -1, -1, -1, -1, -1,
+       2, 3, 4, 5,             /* AEB */
+       -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
@@ -760,7 +881,8 @@ static char channel_map_aio_out_ss[HDSPM_MAX_CHANNELS] = {
        10, 11,                 /* spdif out */
        12, 13, 14, 15, 16, 17, 18, 19, /* ADAT out */
        6, 7,                   /* phone out */
-       -1, -1, -1, -1, -1, -1, -1, -1,
+       2, 3, 4, 5,             /* AEB */
+       -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
@@ -773,7 +895,8 @@ static char channel_map_aio_in_ds[HDSPM_MAX_CHANNELS] = {
        8, 9,                   /* aes in */
        10, 11,                 /* spdif in */
        12, 14, 16, 18,         /* adat in */
-       -1, -1, -1, -1, -1, -1,
+       2, 3, 4, 5,             /* AEB */
+       -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
@@ -788,7 +911,7 @@ static char channel_map_aio_out_ds[HDSPM_MAX_CHANNELS] = {
        10, 11,                 /* spdif out */
        12, 14, 16, 18,         /* adat out */
        6, 7,                   /* phone out */
-       -1, -1, -1, -1,
+       2, 3, 4, 5,             /* AEB */
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
@@ -802,7 +925,8 @@ static char channel_map_aio_in_qs[HDSPM_MAX_CHANNELS] = {
        8, 9,                   /* aes in */
        10, 11,                 /* spdif in */
        12, 16,                 /* adat in */
-       -1, -1, -1, -1, -1, -1, -1, -1,
+       2, 3, 4, 5,             /* AEB */
+       -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
@@ -817,7 +941,8 @@ static char channel_map_aio_out_qs[HDSPM_MAX_CHANNELS] = {
        10, 11,                 /* spdif out */
        12, 16,                 /* adat out */
        6, 7,                   /* phone out */
-       -1, -1, -1, -1, -1, -1,
+       2, 3, 4, 5,             /* AEB */
+       -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,
@@ -856,11 +981,11 @@ struct hdspm_midi {
 };
 
 struct hdspm_tco {
-       int input;
-       int framerate;
-       int wordclock;
-       int samplerate;
-       int pull;
+       int input; /* 0: LTC, 1:Video, 2: WC*/
+       int framerate; /* 0=24, 1=25, 2=29.97, 3=29.97d, 4=30, 5=30d */
+       int wordclock; /* 0=1:1, 1=44.1->48, 2=48->44.1 */
+       int samplerate; /* 0=44.1, 1=48, 2= freq from app */
+       int pull; /*   0=0, 1=+0.1%, 2=-0.1%, 3=+4%, 4=-4%*/
        int term; /* 0 = off, 1 = on */
 };
 
@@ -879,7 +1004,7 @@ struct hdspm {
 
        u32 control_register;   /* cached value */
        u32 control2_register;  /* cached value */
-       u32 settings_register;
+       u32 settings_register;  /* cached value for AIO / RayDat (sync reference, master/slave) */
 
        struct hdspm_midi midi[4];
        struct tasklet_struct midi_tasklet;
@@ -941,7 +1066,7 @@ struct hdspm {
 
        struct hdspm_tco *tco;  /* NULL if no TCO detected */
 
-       char **texts_autosync;
+       const char *const *texts_autosync;
        int texts_autosync_items;
 
        cycles_t last_interrupt;
@@ -976,12 +1101,24 @@ static inline void snd_hdspm_initialize_midi_flush(struct hdspm *hdspm);
 static inline int hdspm_get_pll_freq(struct hdspm *hdspm);
 static int hdspm_update_simple_mixer_controls(struct hdspm *hdspm);
 static int hdspm_autosync_ref(struct hdspm *hdspm);
+static int hdspm_set_toggle_setting(struct hdspm *hdspm, u32 regmask, int out);
 static int snd_hdspm_set_defaults(struct hdspm *hdspm);
 static int hdspm_system_clock_mode(struct hdspm *hdspm);
 static void hdspm_set_sgbuf(struct hdspm *hdspm,
                            struct snd_pcm_substream *substream,
                             unsigned int reg, int channels);
 
+static int hdspm_aes_sync_check(struct hdspm *hdspm, int idx);
+static int hdspm_wc_sync_check(struct hdspm *hdspm);
+static int hdspm_tco_sync_check(struct hdspm *hdspm);
+static int hdspm_sync_in_sync_check(struct hdspm *hdspm);
+
+static int hdspm_get_aes_sample_rate(struct hdspm *hdspm, int index);
+static int hdspm_get_tco_sample_rate(struct hdspm *hdspm);
+static int hdspm_get_wc_sample_rate(struct hdspm *hdspm);
+
+
+
 static inline int HDSPM_bit2freq(int n)
 {
        static const int bit2freq_tab[] = {
@@ -992,6 +1129,12 @@ static inline int HDSPM_bit2freq(int n)
        return bit2freq_tab[n];
 }
 
+static bool hdspm_is_raydat_or_aio(struct hdspm *hdspm)
+{
+       return ((AIO == hdspm->io_type) || (RayDAT == hdspm->io_type));
+}
+
+
 /* Write/read to/from HDSPM with Adresses in Bytes
    not words but only 32Bit writes are allowed */
 
@@ -1107,14 +1250,11 @@ static int hdspm_rate_multiplier(struct hdspm *hdspm, int rate)
                else if (hdspm->control_register &
                                HDSPM_DoubleSpeed)
                        return rate * 2;
-       };
+       }
        return rate;
 }
 
-static int hdspm_tco_sync_check(struct hdspm *hdspm);
-static int hdspm_sync_in_sync_check(struct hdspm *hdspm);
-
-/* check for external sample rate */
+/* check for external sample rate, returns the sample rate in Hz*/
 static int hdspm_external_sample_rate(struct hdspm *hdspm)
 {
        unsigned int status, status2, timecode;
@@ -1127,17 +1267,36 @@ static int hdspm_external_sample_rate(struct hdspm *hdspm)
                timecode = hdspm_read(hdspm, HDSPM_timecodeRegister);
 
                syncref = hdspm_autosync_ref(hdspm);
+               switch (syncref) {
+               case HDSPM_AES32_AUTOSYNC_FROM_WORD:
+               /* Check WC sync and get sample rate */
+                       if (hdspm_wc_sync_check(hdspm))
+                               return HDSPM_bit2freq(hdspm_get_wc_sample_rate(hdspm));
+                       break;
 
-               if (syncref == HDSPM_AES32_AUTOSYNC_FROM_WORD &&
-                               status & HDSPM_AES32_wcLock)
-                       return HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF);
+               case HDSPM_AES32_AUTOSYNC_FROM_AES1:
+               case HDSPM_AES32_AUTOSYNC_FROM_AES2:
+               case HDSPM_AES32_AUTOSYNC_FROM_AES3:
+               case HDSPM_AES32_AUTOSYNC_FROM_AES4:
+               case HDSPM_AES32_AUTOSYNC_FROM_AES5:
+               case HDSPM_AES32_AUTOSYNC_FROM_AES6:
+               case HDSPM_AES32_AUTOSYNC_FROM_AES7:
+               case HDSPM_AES32_AUTOSYNC_FROM_AES8:
+               /* Check AES sync and get sample rate */
+                       if (hdspm_aes_sync_check(hdspm, syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1))
+                               return HDSPM_bit2freq(hdspm_get_aes_sample_rate(hdspm,
+                                                       syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1));
+                       break;
 
-               if (syncref >= HDSPM_AES32_AUTOSYNC_FROM_AES1 &&
-                               syncref <= HDSPM_AES32_AUTOSYNC_FROM_AES8 &&
-                               status2 & (HDSPM_LockAES >>
-                               (syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1)))
-                       return HDSPM_bit2freq((timecode >> (4*(syncref-HDSPM_AES32_AUTOSYNC_FROM_AES1))) & 0xF);
-               return 0;
+
+               case HDSPM_AES32_AUTOSYNC_FROM_TCO:
+               /* Check TCO sync and get sample rate */
+                       if (hdspm_tco_sync_check(hdspm))
+                               return HDSPM_bit2freq(hdspm_get_tco_sample_rate(hdspm));
+                       break;
+               default:
+                       return 0;
+               } /* end switch(syncref) */
                break;
 
        case MADIface:
@@ -2129,6 +2288,9 @@ static int hdspm_get_wc_sample_rate(struct hdspm *hdspm)
                status = hdspm_read(hdspm, HDSPM_RD_STATUS_1);
                return (status >> 16) & 0xF;
                break;
+       case AES32:
+               status = hdspm_read(hdspm, HDSPM_statusRegister);
+               return (status >> HDSPM_AES32_wcFreq_bit) & 0xF;
        default:
                break;
        }
@@ -2152,6 +2314,9 @@ static int hdspm_get_tco_sample_rate(struct hdspm *hdspm)
                        status = hdspm_read(hdspm, HDSPM_RD_STATUS_1);
                        return (status >> 20) & 0xF;
                        break;
+               case AES32:
+                       status = hdspm_read(hdspm, HDSPM_statusRegister);
+                       return (status >> 1) & 0xF;
                default:
                        break;
                }
@@ -2183,6 +2348,23 @@ static int hdspm_get_sync_in_sample_rate(struct hdspm *hdspm)
        return 0;
 }
 
+/**
+ * Returns the AES sample rate class for the given card.
+ **/
+static int hdspm_get_aes_sample_rate(struct hdspm *hdspm, int index)
+{
+       int timecode;
+
+       switch (hdspm->io_type) {
+       case AES32:
+               timecode = hdspm_read(hdspm, HDSPM_timecodeRegister);
+               return (timecode >> (4*index)) & 0xF;
+               break;
+       default:
+               break;
+       }
+       return 0;
+}
 
 /**
  * Returns the sample rate class for input source <idx> for
@@ -2196,15 +2378,23 @@ static int hdspm_get_s1_sample_rate(struct hdspm *hdspm, unsigned int idx)
 }
 
 #define ENUMERATED_CTL_INFO(info, texts) \
-{ \
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; \
-       uinfo->count = 1; \
-       uinfo->value.enumerated.items = ARRAY_SIZE(texts); \
-       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) \
-               uinfo->value.enumerated.item =  uinfo->value.enumerated.items - 1; \
-       strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); \
-}
+       snd_ctl_enum_info(info, 1, ARRAY_SIZE(texts), texts)
+
 
+/* Helper function to query the external sample rate and return the
+ * corresponding enum to be returned to userspace.
+ */
+static int hdspm_external_rate_to_enum(struct hdspm *hdspm)
+{
+       int rate = hdspm_external_sample_rate(hdspm);
+       int i, selected_rate = 0;
+       for (i = 1; i < 10; i++)
+               if (HDSPM_bit2freq(i) == rate) {
+                       selected_rate = i;
+                       break;
+               }
+       return selected_rate;
+}
 
 
 #define HDSPM_AUTOSYNC_SAMPLE_RATE(xname, xindex) \
@@ -2270,7 +2460,7 @@ static int snd_hdspm_get_autosync_sample_rate(struct snd_kcontrol *kcontrol,
                default:
                        ucontrol->value.enumerated.item[0] =
                                hdspm_get_s1_sample_rate(hdspm,
-                                               ucontrol->id.index-1);
+                                               kcontrol->private_value-1);
                }
                break;
 
@@ -2289,28 +2479,24 @@ static int snd_hdspm_get_autosync_sample_rate(struct snd_kcontrol *kcontrol,
                        ucontrol->value.enumerated.item[0] =
                                hdspm_get_sync_in_sample_rate(hdspm);
                        break;
+               case 11: /* External Rate */
+                       ucontrol->value.enumerated.item[0] =
+                               hdspm_external_rate_to_enum(hdspm);
+                       break;
                default: /* AES1 to AES8 */
                        ucontrol->value.enumerated.item[0] =
-                               hdspm_get_s1_sample_rate(hdspm,
-                                               kcontrol->private_value-1);
+                               hdspm_get_aes_sample_rate(hdspm,
+                                               kcontrol->private_value -
+                                               HDSPM_AES32_AUTOSYNC_FROM_AES1);
                        break;
                }
                break;
 
        case MADI:
        case MADIface:
-               {
-                       int rate = hdspm_external_sample_rate(hdspm);
-                       int i, selected_rate = 0;
-                       for (i = 1; i < 10; i++)
-                               if (HDSPM_bit2freq(i) == rate) {
-                                       selected_rate = i;
-                                       break;
-                               }
-                       ucontrol->value.enumerated.item[0] = selected_rate;
-               }
+               ucontrol->value.enumerated.item[0] =
+                       hdspm_external_rate_to_enum(hdspm);
                break;
-
        default:
                break;
        }
@@ -2359,33 +2545,17 @@ static int hdspm_system_clock_mode(struct hdspm *hdspm)
  **/
 static void hdspm_set_system_clock_mode(struct hdspm *hdspm, int mode)
 {
-       switch (hdspm->io_type) {
-       case AIO:
-       case RayDAT:
-               if (0 == mode)
-                       hdspm->settings_register |= HDSPM_c0Master;
-               else
-                       hdspm->settings_register &= ~HDSPM_c0Master;
-
-               hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register);
-               break;
-
-       default:
-               if (0 == mode)
-                       hdspm->control_register |= HDSPM_ClockModeMaster;
-               else
-                       hdspm->control_register &= ~HDSPM_ClockModeMaster;
-
-               hdspm_write(hdspm, HDSPM_controlRegister,
-                               hdspm->control_register);
-       }
+       hdspm_set_toggle_setting(hdspm,
+                       (hdspm_is_raydat_or_aio(hdspm)) ?
+                       HDSPM_c0Master : HDSPM_ClockModeMaster,
+                       (0 == mode));
 }
 
 
 static int snd_hdspm_info_system_clock_mode(struct snd_kcontrol *kcontrol,
                                            struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts[] = { "Master", "AutoSync" };
+       static const char *const texts[] = { "Master", "AutoSync" };
        ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
 }
@@ -2809,16 +2979,7 @@ static int snd_hdspm_info_pref_sync_ref(struct snd_kcontrol *kcontrol,
 {
        struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
 
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = hdspm->texts_autosync_items;
-
-       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
-               uinfo->value.enumerated.item =
-                       uinfo->value.enumerated.items - 1;
-
-       strcpy(uinfo->value.enumerated.name,
-                       hdspm->texts_autosync[uinfo->value.enumerated.item]);
+       snd_ctl_enum_info(uinfo, 1, hdspm->texts_autosync_items, hdspm->texts_autosync);
 
        return 0;
 }
@@ -2873,19 +3034,20 @@ static int snd_hdspm_put_pref_sync_ref(struct snd_kcontrol *kcontrol,
 
 static int hdspm_autosync_ref(struct hdspm *hdspm)
 {
+       /* This looks at the autosync selected sync reference */
        if (AES32 == hdspm->io_type) {
+
                unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister);
-               unsigned int syncref =
-                       (status >> HDSPM_AES32_syncref_bit) & 0xF;
-               if (syncref == 0)
-                       return HDSPM_AES32_AUTOSYNC_FROM_WORD;
-               if (syncref <= 8)
+               unsigned int syncref = (status >> HDSPM_AES32_syncref_bit) & 0xF;
+               if ((syncref >= HDSPM_AES32_AUTOSYNC_FROM_WORD) &&
+                               (syncref <= HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN)) {
                        return syncref;
+               }
                return HDSPM_AES32_AUTOSYNC_FROM_NONE;
+
        } else if (MADI == hdspm->io_type) {
-               /* This looks at the autosync selected sync reference */
-               unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
 
+               unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
                switch (status2 & HDSPM_SelSyncRefMask) {
                case HDSPM_SelSyncRef_WORD:
                        return HDSPM_AUTOSYNC_FROM_WORD;
@@ -2898,7 +3060,7 @@ static int hdspm_autosync_ref(struct hdspm *hdspm)
                case HDSPM_SelSyncRef_NVALID:
                        return HDSPM_AUTOSYNC_FROM_NONE;
                default:
-                       return 0;
+                       return HDSPM_AUTOSYNC_FROM_NONE;
                }
 
        }
@@ -2912,31 +3074,15 @@ static int snd_hdspm_info_autosync_ref(struct snd_kcontrol *kcontrol,
        struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
 
        if (AES32 == hdspm->io_type) {
-               static char *texts[] = { "WordClock", "AES1", "AES2", "AES3",
-                       "AES4", "AES5", "AES6", "AES7", "AES8", "None"};
-
-               uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-               uinfo->count = 1;
-               uinfo->value.enumerated.items = 10;
-               if (uinfo->value.enumerated.item >=
-                   uinfo->value.enumerated.items)
-                       uinfo->value.enumerated.item =
-                               uinfo->value.enumerated.items - 1;
-               strcpy(uinfo->value.enumerated.name,
-                               texts[uinfo->value.enumerated.item]);
+               static const char *const texts[] = { "WordClock", "AES1", "AES2", "AES3",
+                       "AES4", "AES5", "AES6", "AES7", "AES8", "TCO", "Sync In", "None"};
+
+               ENUMERATED_CTL_INFO(uinfo, texts);
        } else if (MADI == hdspm->io_type) {
-               static char *texts[] = {"Word Clock", "MADI", "TCO",
+               static const char *const texts[] = {"Word Clock", "MADI", "TCO",
                        "Sync In", "None" };
 
-               uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-               uinfo->count = 1;
-               uinfo->value.enumerated.items = 5;
-               if (uinfo->value.enumerated.item >=
-                               uinfo->value.enumerated.items)
-                       uinfo->value.enumerated.item =
-                               uinfo->value.enumerated.items - 1;
-               strcpy(uinfo->value.enumerated.name,
-                               texts[uinfo->value.enumerated.item]);
+               ENUMERATED_CTL_INFO(uinfo, texts);
        }
        return 0;
 }
@@ -2964,7 +3110,7 @@ static int snd_hdspm_get_autosync_ref(struct snd_kcontrol *kcontrol,
 static int snd_hdspm_info_tco_video_input_format(struct snd_kcontrol *kcontrol,
                                       struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts[] = {"No video", "NTSC", "PAL"};
+       static const char *const texts[] = {"No video", "NTSC", "PAL"};
        ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
 }
@@ -3010,7 +3156,7 @@ static int snd_hdspm_get_tco_video_input_format(struct snd_kcontrol *kcontrol,
 static int snd_hdspm_info_tco_ltc_frames(struct snd_kcontrol *kcontrol,
                                       struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts[] = {"No lock", "24 fps", "25 fps", "29.97 fps",
+       static const char *const texts[] = {"No lock", "24 fps", "25 fps", "29.97 fps",
                                "30 fps"};
        ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
@@ -3067,16 +3213,35 @@ static int snd_hdspm_get_tco_ltc_frames(struct snd_kcontrol *kcontrol,
 
 static int hdspm_toggle_setting(struct hdspm *hdspm, u32 regmask)
 {
-       return (hdspm->control_register & regmask) ? 1 : 0;
+       u32 reg;
+
+       if (hdspm_is_raydat_or_aio(hdspm))
+               reg = hdspm->settings_register;
+       else
+               reg = hdspm->control_register;
+
+       return (reg & regmask) ? 1 : 0;
 }
 
 static int hdspm_set_toggle_setting(struct hdspm *hdspm, u32 regmask, int out)
 {
+       u32 *reg;
+       u32 target_reg;
+
+       if (hdspm_is_raydat_or_aio(hdspm)) {
+               reg = &(hdspm->settings_register);
+               target_reg = HDSPM_WR_SETTINGS;
+       } else {
+               reg = &(hdspm->control_register);
+               target_reg = HDSPM_controlRegister;
+       }
+
        if (out)
-               hdspm->control_register |= regmask;
+               *reg |= regmask;
        else
-               hdspm->control_register &= ~regmask;
-       hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
+               *reg &= ~regmask;
+
+       hdspm_write(hdspm, target_reg, *reg);
 
        return 0;
 }
@@ -3141,7 +3306,7 @@ static int hdspm_set_input_select(struct hdspm * hdspm, int out)
 static int snd_hdspm_info_input_select(struct snd_kcontrol *kcontrol,
                                       struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts[] = { "optical", "coaxial" };
+       static const char *const texts[] = { "optical", "coaxial" };
        ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
 }
@@ -3203,7 +3368,7 @@ static int hdspm_set_ds_wire(struct hdspm * hdspm, int ds)
 static int snd_hdspm_info_ds_wire(struct snd_kcontrol *kcontrol,
                                  struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts[] = { "Single", "Double" };
+       static const char *const texts[] = { "Single", "Double" };
        ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
 }
@@ -3276,7 +3441,7 @@ static int hdspm_set_qs_wire(struct hdspm * hdspm, int mode)
 static int snd_hdspm_info_qs_wire(struct snd_kcontrol *kcontrol,
                                       struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts[] = { "Single", "Double", "Quad" };
+       static const char *const texts[] = { "Single", "Double", "Quad" };
        ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
 }
@@ -3313,6 +3478,84 @@ static int snd_hdspm_put_qs_wire(struct snd_kcontrol *kcontrol,
        return change;
 }
 
+#define HDSPM_CONTROL_TRISTATE(xname, xindex) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+       .name = xname, \
+       .private_value = xindex, \
+       .info = snd_hdspm_info_tristate, \
+       .get = snd_hdspm_get_tristate, \
+       .put = snd_hdspm_put_tristate \
+}
+
+static int hdspm_tristate(struct hdspm *hdspm, u32 regmask)
+{
+       u32 reg = hdspm->settings_register & (regmask * 3);
+       return reg / regmask;
+}
+
+static int hdspm_set_tristate(struct hdspm *hdspm, int mode, u32 regmask)
+{
+       hdspm->settings_register &= ~(regmask * 3);
+       hdspm->settings_register |= (regmask * mode);
+       hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register);
+
+       return 0;
+}
+
+static int snd_hdspm_info_tristate(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_info *uinfo)
+{
+       u32 regmask = kcontrol->private_value;
+
+       static const char *const texts_spdif[] = { "Optical", "Coaxial", "Internal" };
+       static const char *const texts_levels[] = { "Hi Gain", "+4 dBu", "-10 dBV" };
+
+       switch (regmask) {
+       case HDSPM_c0_Input0:
+               ENUMERATED_CTL_INFO(uinfo, texts_spdif);
+               break;
+       default:
+               ENUMERATED_CTL_INFO(uinfo, texts_levels);
+               break;
+       }
+       return 0;
+}
+
+static int snd_hdspm_get_tristate(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+       u32 regmask = kcontrol->private_value;
+
+       spin_lock_irq(&hdspm->lock);
+       ucontrol->value.enumerated.item[0] = hdspm_tristate(hdspm, regmask);
+       spin_unlock_irq(&hdspm->lock);
+       return 0;
+}
+
+static int snd_hdspm_put_tristate(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+       u32 regmask = kcontrol->private_value;
+       int change;
+       int val;
+
+       if (!snd_hdspm_use_is_exclusive(hdspm))
+               return -EBUSY;
+       val = ucontrol->value.integer.value[0];
+       if (val < 0)
+               val = 0;
+       if (val > 2)
+               val = 2;
+
+       spin_lock_irq(&hdspm->lock);
+       change = val != hdspm_tristate(hdspm, regmask);
+       hdspm_set_tristate(hdspm, val, regmask);
+       spin_unlock_irq(&hdspm->lock);
+       return change;
+}
+
 #define HDSPM_MADI_SPEEDMODE(xname, xindex) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
        .name = xname, \
@@ -3352,7 +3595,7 @@ static int hdspm_set_madi_speedmode(struct hdspm *hdspm, int mode)
 static int snd_hdspm_info_madi_speedmode(struct snd_kcontrol *kcontrol,
                                       struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts[] = { "Single", "Double", "Quad" };
+       static const char *const texts[] = { "Single", "Double", "Quad" };
        ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
 }
@@ -3587,7 +3830,7 @@ static int snd_hdspm_put_playback_mixer(struct snd_kcontrol *kcontrol,
 static int snd_hdspm_info_sync_check(struct snd_kcontrol *kcontrol,
                                     struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts[] = { "No Lock", "Lock", "Sync", "N/A" };
+       static const char *const texts[] = { "No Lock", "Lock", "Sync", "N/A" };
        ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
 }
@@ -3595,7 +3838,7 @@ static int snd_hdspm_info_sync_check(struct snd_kcontrol *kcontrol,
 static int snd_hdspm_tco_info_lock_check(struct snd_kcontrol *kcontrol,
                                     struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts[] = { "No Lock", "Lock" };
+       static const char *const texts[] = { "No Lock", "Lock" };
        ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
 }
@@ -3745,9 +3988,18 @@ static int hdspm_tco_sync_check(struct hdspm *hdspm)
        if (hdspm->tco) {
                switch (hdspm->io_type) {
                case MADI:
+                       status = hdspm_read(hdspm, HDSPM_statusRegister);
+                       if (status & HDSPM_tcoLockMadi) {
+                               if (status & HDSPM_tcoSync)
+                                       return 2;
+                               else
+                                       return 1;
+                       }
+                       return 0;
+                       break;
                case AES32:
                        status = hdspm_read(hdspm, HDSPM_statusRegister);
-                       if (status & HDSPM_tcoLock) {
+                       if (status & HDSPM_tcoLockAes) {
                                if (status & HDSPM_tcoSync)
                                        return 2;
                                else
@@ -3807,7 +4059,8 @@ static int snd_hdspm_get_sync_check(struct snd_kcontrol *kcontrol,
                case 5: /* SYNC IN */
                        val = hdspm_sync_in_sync_check(hdspm); break;
                default:
-                       val = hdspm_s1_sync_check(hdspm, ucontrol->id.index-1);
+                       val = hdspm_s1_sync_check(hdspm,
+                                       kcontrol->private_value-1);
                }
                break;
 
@@ -3975,7 +4228,8 @@ static void hdspm_tco_write(struct hdspm *hdspm)
 static int snd_hdspm_info_tco_sample_rate(struct snd_kcontrol *kcontrol,
                                          struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts[] = { "44.1 kHz", "48 kHz" };
+       /* TODO freq from app could be supported here, see tco->samplerate */
+       static const char *const texts[] = { "44.1 kHz", "48 kHz" };
        ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
 }
@@ -4021,7 +4275,8 @@ static int snd_hdspm_put_tco_sample_rate(struct snd_kcontrol *kcontrol,
 static int snd_hdspm_info_tco_pull(struct snd_kcontrol *kcontrol,
                                   struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts[] = { "0", "+ 0.1 %", "- 0.1 %", "+ 4 %", "- 4 %" };
+       static const char *const texts[] = { "0", "+ 0.1 %", "- 0.1 %",
+               "+ 4 %", "- 4 %" };
        ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
 }
@@ -4066,7 +4321,7 @@ static int snd_hdspm_put_tco_pull(struct snd_kcontrol *kcontrol,
 static int snd_hdspm_info_tco_wck_conversion(struct snd_kcontrol *kcontrol,
                                             struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts[] = { "1:1", "44.1 -> 48", "48 -> 44.1" };
+       static const char *const texts[] = { "1:1", "44.1 -> 48", "48 -> 44.1" };
        ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
 }
@@ -4112,7 +4367,7 @@ static int snd_hdspm_put_tco_wck_conversion(struct snd_kcontrol *kcontrol,
 static int snd_hdspm_info_tco_frame_rate(struct snd_kcontrol *kcontrol,
                                          struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts[] = { "24 fps", "25 fps", "29.97fps",
+       static const char *const texts[] = { "24 fps", "25 fps", "29.97fps",
                "29.97 dfps", "30 fps", "30 dfps" };
        ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
@@ -4159,7 +4414,7 @@ static int snd_hdspm_put_tco_frame_rate(struct snd_kcontrol *kcontrol,
 static int snd_hdspm_info_tco_sync_source(struct snd_kcontrol *kcontrol,
                                          struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts[] = { "LTC", "Video", "WCK" };
+       static const char *const texts[] = { "LTC", "Video", "WCK" };
        ENUMERATED_CTL_INFO(uinfo, texts);
        return 0;
 }
@@ -4284,7 +4539,6 @@ static struct snd_kcontrol_new snd_hdspm_controls_aio[] = {
        HDSPM_INTERNAL_CLOCK("Internal Clock", 0),
        HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0),
        HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0),
-       HDSPM_AUTOSYNC_REF("AutoSync Reference", 0),
        HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0),
        HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0),
        HDSPM_SYNC_CHECK("WC SyncCheck", 0),
@@ -4298,7 +4552,16 @@ static struct snd_kcontrol_new snd_hdspm_controls_aio[] = {
        HDSPM_AUTOSYNC_SAMPLE_RATE("SPDIF Frequency", 2),
        HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT Frequency", 3),
        HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 4),
-       HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 5)
+       HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 5),
+       HDSPM_CONTROL_TRISTATE("S/PDIF Input", HDSPM_c0_Input0),
+       HDSPM_TOGGLE_SETTING("S/PDIF Out Optical", HDSPM_c0_Spdif_Opt),
+       HDSPM_TOGGLE_SETTING("S/PDIF Out Professional", HDSPM_c0_Pro),
+       HDSPM_TOGGLE_SETTING("ADAT internal (AEB/TEB)", HDSPM_c0_AEB1),
+       HDSPM_TOGGLE_SETTING("XLR Breakout Cable", HDSPM_c0_Sym6db),
+       HDSPM_TOGGLE_SETTING("Single Speed WordClock Out", HDSPM_c0_Wck48),
+       HDSPM_CONTROL_TRISTATE("Input Level", HDSPM_c0_AD_GAIN0),
+       HDSPM_CONTROL_TRISTATE("Output Level", HDSPM_c0_DA_GAIN0),
+       HDSPM_CONTROL_TRISTATE("Phones Level", HDSPM_c0_PH_GAIN0)
 
                /*
                   HDSPM_INPUT_SELECT("Input Select", 0),
@@ -4335,7 +4598,9 @@ static struct snd_kcontrol_new snd_hdspm_controls_raydat[] = {
        HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT3 Frequency", 5),
        HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT4 Frequency", 6),
        HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 7),
-       HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 8)
+       HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 8),
+       HDSPM_TOGGLE_SETTING("S/PDIF Out Professional", HDSPM_c0_Pro),
+       HDSPM_TOGGLE_SETTING("Single Speed WordClock Out", HDSPM_c0_Wck48)
 };
 
 static struct snd_kcontrol_new snd_hdspm_controls_aes32[] = {
@@ -4345,7 +4610,7 @@ static struct snd_kcontrol_new snd_hdspm_controls_aes32[] = {
        HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0),
        HDSPM_AUTOSYNC_REF("AutoSync Reference", 0),
        HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0),
-       HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0),
+       HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 11),
        HDSPM_SYNC_CHECK("WC Sync Check", 0),
        HDSPM_SYNC_CHECK("AES1 Sync Check", 1),
        HDSPM_SYNC_CHECK("AES2 Sync Check", 2),
@@ -4501,77 +4766,22 @@ static int snd_hdspm_create_controls(struct snd_card *card,
  ------------------------------------------------------------*/
 
 static void
-snd_hdspm_proc_read_madi(struct snd_info_entry * entry,
-                        struct snd_info_buffer *buffer)
+snd_hdspm_proc_read_tco(struct snd_info_entry *entry,
+                                       struct snd_info_buffer *buffer)
 {
        struct hdspm *hdspm = entry->private_data;
-       unsigned int status, status2, control, freq;
-
-       char *pref_sync_ref;
-       char *autosync_ref;
-       char *system_clock_mode;
-       char *insel;
-       int x, x2;
-
-       /* TCO stuff */
+       unsigned int status, control;
        int a, ltc, frames, seconds, minutes, hours;
        unsigned int period;
        u64 freq_const = 0;
        u32 rate;
 
+       snd_iprintf(buffer, "--- TCO ---\n");
+
        status = hdspm_read(hdspm, HDSPM_statusRegister);
-       status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
        control = hdspm->control_register;
-       freq = hdspm_read(hdspm, HDSPM_timecodeRegister);
 
-       snd_iprintf(buffer, "%s (Card #%d) Rev.%x Status2first3bits: %x\n",
-                       hdspm->card_name, hdspm->card->number + 1,
-                       hdspm->firmware_rev,
-                       (status2 & HDSPM_version0) |
-                       (status2 & HDSPM_version1) | (status2 &
-                               HDSPM_version2));
-
-       snd_iprintf(buffer, "HW Serial: 0x%06x%06x\n",
-                       (hdspm_read(hdspm, HDSPM_midiStatusIn1)>>8) & 0xFFFFFF,
-                       hdspm->serial);
 
-       snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n",
-                       hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase);
-
-       snd_iprintf(buffer, "--- System ---\n");
-
-       snd_iprintf(buffer,
-               "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n",
-               status & HDSPM_audioIRQPending,
-               (status & HDSPM_midi0IRQPending) ? 1 : 0,
-               (status & HDSPM_midi1IRQPending) ? 1 : 0,
-               hdspm->irq_count);
-       snd_iprintf(buffer,
-               "HW pointer: id = %d, rawptr = %d (%d->%d) "
-               "estimated= %ld (bytes)\n",
-               ((status & HDSPM_BufferID) ? 1 : 0),
-               (status & HDSPM_BufferPositionMask),
-               (status & HDSPM_BufferPositionMask) %
-               (2 * (int)hdspm->period_bytes),
-               ((status & HDSPM_BufferPositionMask) - 64) %
-               (2 * (int)hdspm->period_bytes),
-               (long) hdspm_hw_pointer(hdspm) * 4);
-
-       snd_iprintf(buffer,
-               "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n",
-               hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF,
-               hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF,
-               hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF,
-               hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF);
-       snd_iprintf(buffer,
-               "MIDIoverMADI FIFO: In=0x%x, Out=0x%x \n",
-               hdspm_read(hdspm, HDSPM_midiStatusIn2) & 0xFF,
-               hdspm_read(hdspm, HDSPM_midiStatusOut2) & 0xFF);
-       snd_iprintf(buffer,
-               "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, "
-               "status2=0x%x\n",
-               hdspm->control_register, hdspm->control2_register,
-               status, status2);
        if (status & HDSPM_tco_detect) {
                snd_iprintf(buffer, "TCO module detected.\n");
                a = hdspm_read(hdspm, HDSPM_RD_TCO+4);
@@ -4665,6 +4875,75 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry,
        } else {
                snd_iprintf(buffer, "No TCO module detected.\n");
        }
+}
+
+static void
+snd_hdspm_proc_read_madi(struct snd_info_entry *entry,
+                        struct snd_info_buffer *buffer)
+{
+       struct hdspm *hdspm = entry->private_data;
+       unsigned int status, status2, control, freq;
+
+       char *pref_sync_ref;
+       char *autosync_ref;
+       char *system_clock_mode;
+       char *insel;
+       int x, x2;
+
+       status = hdspm_read(hdspm, HDSPM_statusRegister);
+       status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
+       control = hdspm->control_register;
+       freq = hdspm_read(hdspm, HDSPM_timecodeRegister);
+
+       snd_iprintf(buffer, "%s (Card #%d) Rev.%x Status2first3bits: %x\n",
+                       hdspm->card_name, hdspm->card->number + 1,
+                       hdspm->firmware_rev,
+                       (status2 & HDSPM_version0) |
+                       (status2 & HDSPM_version1) | (status2 &
+                               HDSPM_version2));
+
+       snd_iprintf(buffer, "HW Serial: 0x%06x%06x\n",
+                       (hdspm_read(hdspm, HDSPM_midiStatusIn1)>>8) & 0xFFFFFF,
+                       hdspm->serial);
+
+       snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n",
+                       hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase);
+
+       snd_iprintf(buffer, "--- System ---\n");
+
+       snd_iprintf(buffer,
+               "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n",
+               status & HDSPM_audioIRQPending,
+               (status & HDSPM_midi0IRQPending) ? 1 : 0,
+               (status & HDSPM_midi1IRQPending) ? 1 : 0,
+               hdspm->irq_count);
+       snd_iprintf(buffer,
+               "HW pointer: id = %d, rawptr = %d (%d->%d) "
+               "estimated= %ld (bytes)\n",
+               ((status & HDSPM_BufferID) ? 1 : 0),
+               (status & HDSPM_BufferPositionMask),
+               (status & HDSPM_BufferPositionMask) %
+               (2 * (int)hdspm->period_bytes),
+               ((status & HDSPM_BufferPositionMask) - 64) %
+               (2 * (int)hdspm->period_bytes),
+               (long) hdspm_hw_pointer(hdspm) * 4);
+
+       snd_iprintf(buffer,
+               "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n",
+               hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF,
+               hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF,
+               hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF,
+               hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF);
+       snd_iprintf(buffer,
+               "MIDIoverMADI FIFO: In=0x%x, Out=0x%x \n",
+               hdspm_read(hdspm, HDSPM_midiStatusIn2) & 0xFF,
+               hdspm_read(hdspm, HDSPM_midiStatusOut2) & 0xFF);
+       snd_iprintf(buffer,
+               "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, "
+               "status2=0x%x\n",
+               hdspm->control_register, hdspm->control2_register,
+               status, status2);
+
 
        snd_iprintf(buffer, "--- Settings ---\n");
 
@@ -4768,6 +5047,9 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry,
                (status & HDSPM_RX_64ch) ? "64 channels" :
                "56 channels");
 
+       /* call readout function for TCO specific status */
+       snd_hdspm_proc_read_tco(entry, buffer);
+
        snd_iprintf(buffer, "\n");
 }
 
@@ -4909,11 +5191,18 @@ snd_hdspm_proc_read_aes32(struct snd_info_entry * entry,
                autosync_ref = "AES7"; break;
        case HDSPM_AES32_AUTOSYNC_FROM_AES8:
                autosync_ref = "AES8"; break;
+       case HDSPM_AES32_AUTOSYNC_FROM_TCO:
+               autosync_ref = "TCO"; break;
+       case HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN:
+               autosync_ref = "Sync In"; break;
        default:
                autosync_ref = "---"; break;
        }
        snd_iprintf(buffer, "AutoSync ref = %s\n", autosync_ref);
 
+       /* call readout function for TCO specific status */
+       snd_hdspm_proc_read_tco(entry, buffer);
+
        snd_iprintf(buffer, "\n");
 }
 
@@ -5097,7 +5386,7 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm)
 
        case AES32:
                hdspm->control_register =
-                       HDSPM_ClockModeMaster | /* Master Cloack Mode on */
+                       HDSPM_ClockModeMaster | /* Master Clock Mode on */
                        hdspm_encode_latency(7) | /* latency max=8192samples */
                        HDSPM_SyncRef0 |        /* AES1 is syncclock */
                        HDSPM_LineOut | /* Analog output in */
@@ -5123,9 +5412,8 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm)
 
        all_in_all_mixer(hdspm, 0 * UNITY_GAIN);
 
-       if (hdspm->io_type == AIO || hdspm->io_type == RayDAT) {
+       if (hdspm_is_raydat_or_aio(hdspm))
                hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register);
-       }
 
        /* set a default rate so that the channel map is set up. */
        hdspm_set_rate(hdspm, 48000, 1);
@@ -5371,6 +5659,16 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
           */
 
 
+       /*  For AES cards, the float format bit is the same as the
+        *  preferred sync reference. Since we don't want to break
+        *  sync settings, we have to skip the remaining part of this
+        *  function.
+        */
+       if (hdspm->io_type == AES32) {
+               return 0;
+       }
+
+
        /* Switch to native float format if requested */
        if (SNDRV_PCM_FORMAT_FLOAT_LE == params_format(params)) {
                if (!(hdspm->control_register & HDSPe_FLOAT_FORMAT))
@@ -6479,10 +6777,6 @@ static int snd_hdspm_create(struct snd_card *card,
                break;
 
        case AIO:
-               if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBI_D)) {
-                       snd_printk(KERN_INFO "HDSPM: AEB input board found, but not supported\n");
-               }
-
                hdspm->ss_in_channels = AIO_IN_SS_CHANNELS;
                hdspm->ds_in_channels = AIO_IN_DS_CHANNELS;
                hdspm->qs_in_channels = AIO_IN_QS_CHANNELS;
@@ -6490,6 +6784,20 @@ static int snd_hdspm_create(struct snd_card *card,
                hdspm->ds_out_channels = AIO_OUT_DS_CHANNELS;
                hdspm->qs_out_channels = AIO_OUT_QS_CHANNELS;
 
+               if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBI_D)) {
+                       snd_printk(KERN_INFO "HDSPM: AEB input board found\n");
+                       hdspm->ss_in_channels += 4;
+                       hdspm->ds_in_channels += 4;
+                       hdspm->qs_in_channels += 4;
+               }
+
+               if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBO_D)) {
+                       snd_printk(KERN_INFO "HDSPM: AEB output board found\n");
+                       hdspm->ss_out_channels += 4;
+                       hdspm->ds_out_channels += 4;
+                       hdspm->qs_out_channels += 4;
+               }
+
                hdspm->channel_map_out_ss = channel_map_aio_out_ss;
                hdspm->channel_map_out_ds = channel_map_aio_out_ds;
                hdspm->channel_map_out_qs = channel_map_aio_out_qs;
@@ -6558,6 +6866,7 @@ static int snd_hdspm_create(struct snd_card *card,
                break;
 
        case MADI:
+       case AES32:
                if (hdspm_read(hdspm, HDSPM_statusRegister) & HDSPM_tco_detect) {
                        hdspm->midiPorts++;
                        hdspm->tco = kzalloc(sizeof(struct hdspm_tco),
@@ -6565,7 +6874,7 @@ static int snd_hdspm_create(struct snd_card *card,
                        if (NULL != hdspm->tco) {
                                hdspm_tco_write(hdspm);
                        }
-                       snd_printk(KERN_INFO "HDSPM: MADI TCO module found\n");
+                       snd_printk(KERN_INFO "HDSPM: MADI/AES TCO module found\n");
                } else {
                        hdspm->tco = NULL;
                }
@@ -6580,10 +6889,12 @@ static int snd_hdspm_create(struct snd_card *card,
        case AES32:
                if (hdspm->tco) {
                        hdspm->texts_autosync = texts_autosync_aes_tco;
-                       hdspm->texts_autosync_items = 10;
+                       hdspm->texts_autosync_items =
+                               ARRAY_SIZE(texts_autosync_aes_tco);
                } else {
                        hdspm->texts_autosync = texts_autosync_aes;
-                       hdspm->texts_autosync_items = 9;
+                       hdspm->texts_autosync_items =
+                               ARRAY_SIZE(texts_autosync_aes);
                }
                break;
 
index 3fdd87fa18a970db151fdadcc578ca61c87d3241..986323b4caadfbae41579af447cb33595bccd3e4 100644 (file)
@@ -13,6 +13,7 @@ config SND_ATMEL_SOC_PDC
 config SND_ATMEL_SOC_DMA
        tristate
        depends on SND_ATMEL_SOC
+       select SND_SOC_GENERIC_DMAENGINE_PCM
 
 config SND_ATMEL_SOC_SSC
        tristate
@@ -32,6 +33,16 @@ config SND_AT91_SOC_SAM9G20_WM8731
          Say Y if you want to add support for SoC audio on WM8731-based
          AT91sam9g20 evaluation board.
 
+config SND_ATMEL_SOC_WM8904
+       tristate "Atmel ASoC driver for boards using WM8904 codec"
+       depends on ARCH_AT91 && ATMEL_SSC && SND_ATMEL_SOC
+       select SND_ATMEL_SOC_SSC
+       select SND_ATMEL_SOC_DMA
+       select SND_SOC_WM8904
+       help
+         Say Y if you want to add support for Atmel ASoC driver for boards using
+         WM8904 codec.
+
 config SND_AT91_SOC_AFEB9260
        tristate "SoC Audio support for AFEB9260 board"
        depends on ARCH_AT91 && ATMEL_SSC && ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC
index 41967ccb6f41e3968753d4922ad03f2439ad81b9..922d4da5710937a06f3d574a0cadffb69ea1edb5 100644 (file)
@@ -11,6 +11,8 @@ obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel_ssc_dai.o
 
 # AT91 Machine Support
 snd-soc-sam9g20-wm8731-objs := sam9g20_wm8731.o
+snd-atmel-soc-wm8904-objs := atmel_wm8904.o
 
 obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o
+obj-$(CONFIG_SND_ATMEL_SOC_WM8904) += snd-atmel-soc-wm8904.o
 obj-$(CONFIG_SND_AT91_SOC_AFEB9260) += snd-soc-afeb9260.o
index d12826526798fc47620e4cb613df9e95da8a8f7c..06082e5e5dcb7d726e2bdba6e5f2d7f816dcf262 100644 (file)
@@ -91,138 +91,52 @@ static void atmel_pcm_dma_irq(u32 ssc_sr,
        }
 }
 
-/*--------------------------------------------------------------------------*\
- * DMAENGINE operations
-\*--------------------------------------------------------------------------*/
-static bool filter(struct dma_chan *chan, void *slave)
-{
-       struct at_dma_slave *sl = slave;
-
-       if (sl->dma_dev == chan->device->dev) {
-               chan->private = sl;
-               return true;
-       } else {
-               return false;
-       }
-}
-
 static int atmel_pcm_configure_dma(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params, struct atmel_pcm_dma_params *prtd)
+       struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config)
 {
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct atmel_pcm_dma_params *prtd;
        struct ssc_device *ssc;
-       struct dma_chan *dma_chan;
-       struct dma_slave_config slave_config;
        int ret;
 
+       prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
        ssc = prtd->ssc;
 
-       ret = snd_hwparams_to_dma_slave_config(substream, params,
-                       &slave_config);
+       ret = snd_hwparams_to_dma_slave_config(substream, params, slave_config);
        if (ret) {
                pr_err("atmel-pcm: hwparams to dma slave configure failed\n");
                return ret;
        }
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               slave_config.dst_addr = (dma_addr_t)ssc->phybase + SSC_THR;
-               slave_config.dst_maxburst = 1;
+               slave_config->dst_addr = ssc->phybase + SSC_THR;
+               slave_config->dst_maxburst = 1;
        } else {
-               slave_config.src_addr = (dma_addr_t)ssc->phybase + SSC_RHR;
-               slave_config.src_maxburst = 1;
-       }
-
-       dma_chan = snd_dmaengine_pcm_get_chan(substream);
-       if (dmaengine_slave_config(dma_chan, &slave_config)) {
-               pr_err("atmel-pcm: failed to configure dma channel\n");
-               ret = -EBUSY;
-               return ret;
-       }
-
-       return 0;
-}
-
-static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct atmel_pcm_dma_params *prtd;
-       struct ssc_device *ssc;
-       struct at_dma_slave *sdata = NULL;
-       int ret;
-
-       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-
-       prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-       ssc = prtd->ssc;
-       if (ssc->pdev)
-               sdata = ssc->pdev->dev.platform_data;
-
-       ret = snd_dmaengine_pcm_open_request_chan(substream, filter, sdata);
-       if (ret) {
-               pr_err("atmel-pcm: dmaengine pcm open failed\n");
-               return -EINVAL;
-       }
-
-       ret = atmel_pcm_configure_dma(substream, params, prtd);
-       if (ret) {
-               pr_err("atmel-pcm: failed to configure dmai\n");
-               goto err;
+               slave_config->src_addr = ssc->phybase + SSC_RHR;
+               slave_config->src_maxburst = 1;
        }
 
        prtd->dma_intr_handler = atmel_pcm_dma_irq;
 
        return 0;
-err:
-       snd_dmaengine_pcm_close_release_chan(substream);
-       return ret;
 }
 
-static int atmel_pcm_dma_prepare(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct atmel_pcm_dma_params *prtd;
-
-       prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
-       ssc_writex(prtd->ssc->regs, SSC_IER, prtd->mask->ssc_error);
-       ssc_writex(prtd->ssc->regs, SSC_CR, prtd->mask->ssc_enable);
-
-       return 0;
-}
-
-static int atmel_pcm_open(struct snd_pcm_substream *substream)
-{
-       snd_soc_set_runtime_hwparams(substream, &atmel_pcm_dma_hardware);
-
-       return 0;
-}
-
-static struct snd_pcm_ops atmel_pcm_ops = {
-       .open           = atmel_pcm_open,
-       .close          = snd_dmaengine_pcm_close_release_chan,
-       .ioctl          = snd_pcm_lib_ioctl,
-       .hw_params      = atmel_pcm_hw_params,
-       .prepare        = atmel_pcm_dma_prepare,
-       .trigger        = snd_dmaengine_pcm_trigger,
-       .pointer        = snd_dmaengine_pcm_pointer_no_residue,
-       .mmap           = atmel_pcm_mmap,
-};
-
-static struct snd_soc_platform_driver atmel_soc_platform = {
-       .ops            = &atmel_pcm_ops,
-       .pcm_new        = atmel_pcm_new,
-       .pcm_free       = atmel_pcm_free,
+static const struct snd_dmaengine_pcm_config atmel_dmaengine_pcm_config = {
+       .prepare_slave_config = atmel_pcm_configure_dma,
+       .pcm_hardware = &atmel_pcm_dma_hardware,
+       .prealloc_buffer_size = ATMEL_SSC_DMABUF_SIZE,
 };
 
 int atmel_pcm_dma_platform_register(struct device *dev)
 {
-       return snd_soc_register_platform(dev, &atmel_soc_platform);
+       return snd_dmaengine_pcm_register(dev, &atmel_dmaengine_pcm_config,
+                       SND_DMAENGINE_PCM_FLAG_NO_RESIDUE);
 }
 EXPORT_SYMBOL(atmel_pcm_dma_platform_register);
 
 void atmel_pcm_dma_platform_unregister(struct device *dev)
 {
-       snd_soc_unregister_platform(dev);
+       snd_dmaengine_pcm_unregister(dev);
 }
 EXPORT_SYMBOL(atmel_pcm_dma_platform_unregister);
 
index f3fdfa07fcb9fafa76d913b64be070b54d31486e..0ecf356027f6c1fcc91693e4c7063152fe3ac706 100644 (file)
@@ -73,6 +73,7 @@ static struct atmel_ssc_mask ssc_tx_mask = {
        .ssc_disable    = SSC_BIT(CR_TXDIS),
        .ssc_endx       = SSC_BIT(SR_ENDTX),
        .ssc_endbuf     = SSC_BIT(SR_TXBUFE),
+       .ssc_error      = SSC_BIT(SR_OVRUN),
        .pdc_enable     = ATMEL_PDC_TXTEN,
        .pdc_disable    = ATMEL_PDC_TXTDIS,
 };
@@ -82,6 +83,7 @@ static struct atmel_ssc_mask ssc_rx_mask = {
        .ssc_disable    = SSC_BIT(CR_RXDIS),
        .ssc_endx       = SSC_BIT(SR_ENDRX),
        .ssc_endbuf     = SSC_BIT(SR_RXBUFF),
+       .ssc_error      = SSC_BIT(SR_OVRUN),
        .pdc_enable     = ATMEL_PDC_RXTEN,
        .pdc_disable    = ATMEL_PDC_RXTDIS,
 };
@@ -196,15 +198,27 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
                             struct snd_soc_dai *dai)
 {
        struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
-       int dir_mask;
+       struct atmel_pcm_dma_params *dma_params;
+       int dir, dir_mask;
 
        pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n",
                ssc_readl(ssc_p->ssc->regs, SR));
 
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               dir = 0;
                dir_mask = SSC_DIR_MASK_PLAYBACK;
-       else
+       } else {
+               dir = 1;
                dir_mask = SSC_DIR_MASK_CAPTURE;
+       }
+
+       dma_params = &ssc_dma_params[dai->id][dir];
+       dma_params->ssc = ssc_p->ssc;
+       dma_params->substream = substream;
+
+       ssc_p->dma_params[dir] = dma_params;
+
+       snd_soc_dai_set_dma_data(dai, substream, dma_params);
 
        spin_lock_irq(&ssc_p->lock);
        if (ssc_p->dir_mask & dir_mask) {
@@ -325,7 +339,6 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params,
        struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
        int id = dai->id;
        struct atmel_ssc_info *ssc_p = &ssc_info[id];
        struct atmel_pcm_dma_params *dma_params;
@@ -344,19 +357,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
        else
                dir = 1;
 
-       dma_params = &ssc_dma_params[id][dir];
-       dma_params->ssc = ssc_p->ssc;
-       dma_params->substream = substream;
-
-       ssc_p->dma_params[dir] = dma_params;
-
-       /*
-        * The snd_soc_pcm_stream->dma_data field is only used to communicate
-        * the appropriate DMA parameters to the pcm driver hw_params()
-        * function.  It should not be used for other purposes
-        * as it is common to all substreams.
-        */
-       snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_params);
+       dma_params = ssc_p->dma_params[dir];
 
        channels = params_channels(params);
 
@@ -648,6 +649,7 @@ static int atmel_ssc_prepare(struct snd_pcm_substream *substream,
        dma_params = ssc_p->dma_params[dir];
 
        ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_enable);
+       ssc_writel(ssc_p->ssc->regs, IER, dma_params->mask->ssc_error);
 
        pr_debug("%s enabled SSC_SR=0x%08x\n",
                        dir ? "receive" : "transmit",
diff --git a/sound/soc/atmel/atmel_wm8904.c b/sound/soc/atmel/atmel_wm8904.c
new file mode 100644 (file)
index 0000000..7222380
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * atmel_wm8904 - Atmel ASoC driver for boards with WM8904 codec.
+ *
+ * Copyright (C) 2012 Atmel
+ *
+ * Author: Bo Shen <voice.shen@atmel.com>
+ *
+ * GPLv2 or later
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+
+#include <sound/soc.h>
+
+#include "../codecs/wm8904.h"
+#include "atmel_ssc_dai.h"
+
+#define MCLK_RATE 32768
+
+static struct clk *mclk;
+
+static const struct snd_soc_dapm_widget atmel_asoc_wm8904_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_MIC("Mic", NULL),
+       SND_SOC_DAPM_LINE("Line In Jack", NULL),
+};
+
+static int atmel_asoc_wm8904_hw_params(struct snd_pcm_substream *substream,
+               struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       int ret;
+
+       ret = snd_soc_dai_set_pll(codec_dai, WM8904_FLL_MCLK, WM8904_FLL_MCLK,
+               32768, params_rate(params) * 256);
+       if (ret < 0) {
+               pr_err("%s - failed to set wm8904 codec PLL.", __func__);
+               return ret;
+       }
+
+       /*
+        * As here wm8904 use FLL output as its system clock
+        * so calling set_sysclk won't care freq parameter
+        * then we pass 0
+        */
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8904_CLK_FLL,
+                       0, SND_SOC_CLOCK_IN);
+       if (ret < 0) {
+               pr_err("%s -failed to set wm8904 SYSCLK\n", __func__);
+               return ret;
+       }
+
+       return 0;
+}
+
+static struct snd_soc_ops atmel_asoc_wm8904_ops = {
+       .hw_params = atmel_asoc_wm8904_hw_params,
+};
+
+static int atmel_set_bias_level(struct snd_soc_card *card,
+               struct snd_soc_dapm_context *dapm,
+               enum snd_soc_bias_level level)
+{
+       if (dapm->bias_level == SND_SOC_BIAS_STANDBY) {
+               switch (level) {
+               case SND_SOC_BIAS_PREPARE:
+                       clk_prepare_enable(mclk);
+                       break;
+               case SND_SOC_BIAS_OFF:
+                       clk_disable_unprepare(mclk);
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return 0;
+};
+
+static struct snd_soc_dai_link atmel_asoc_wm8904_dailink = {
+       .name = "WM8904",
+       .stream_name = "WM8904 PCM",
+       .codec_dai_name = "wm8904-hifi",
+       .dai_fmt = SND_SOC_DAIFMT_I2S
+               | SND_SOC_DAIFMT_NB_NF
+               | SND_SOC_DAIFMT_CBM_CFM,
+       .ops = &atmel_asoc_wm8904_ops,
+};
+
+static struct snd_soc_card atmel_asoc_wm8904_card = {
+       .name = "atmel_asoc_wm8904",
+       .owner = THIS_MODULE,
+       .set_bias_level = atmel_set_bias_level,
+       .dai_link = &atmel_asoc_wm8904_dailink,
+       .num_links = 1,
+       .dapm_widgets = atmel_asoc_wm8904_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(atmel_asoc_wm8904_dapm_widgets),
+       .fully_routed = true,
+};
+
+static int atmel_asoc_wm8904_dt_init(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct device_node *codec_np, *cpu_np;
+       struct snd_soc_card *card = &atmel_asoc_wm8904_card;
+       struct snd_soc_dai_link *dailink = &atmel_asoc_wm8904_dailink;
+       int ret;
+
+       if (!np) {
+               dev_err(&pdev->dev, "only device tree supported\n");
+               return -EINVAL;
+       }
+
+       ret = snd_soc_of_parse_card_name(card, "atmel,model");
+       if (ret) {
+               dev_err(&pdev->dev, "failed to parse card name\n");
+               return ret;
+       }
+
+       ret = snd_soc_of_parse_audio_routing(card, "atmel,audio-routing");
+       if (ret) {
+               dev_err(&pdev->dev, "failed to parse audio routing\n");
+               return ret;
+       }
+
+       cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0);
+       if (!cpu_np) {
+               dev_err(&pdev->dev, "failed to get dai and pcm info\n");
+               ret = -EINVAL;
+               return ret;
+       }
+       dailink->cpu_of_node = cpu_np;
+       dailink->platform_of_node = cpu_np;
+       of_node_put(cpu_np);
+
+       codec_np = of_parse_phandle(np, "atmel,audio-codec", 0);
+       if (!codec_np) {
+               dev_err(&pdev->dev, "failed to get codec info\n");
+               ret = -EINVAL;
+               return ret;
+       }
+       dailink->codec_of_node = codec_np;
+       of_node_put(codec_np);
+
+       return 0;
+}
+
+static int atmel_asoc_wm8904_probe(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = &atmel_asoc_wm8904_card;
+       struct snd_soc_dai_link *dailink = &atmel_asoc_wm8904_dailink;
+       struct clk *clk_src;
+       struct pinctrl *pinctrl;
+       int id, ret;
+
+       pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+       if (IS_ERR(pinctrl)) {
+               dev_err(&pdev->dev, "failed to request pinctrl\n");
+               return PTR_ERR(pinctrl);
+       }
+
+       card->dev = &pdev->dev;
+       ret = atmel_asoc_wm8904_dt_init(pdev);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to init dt info\n");
+               return ret;
+       }
+
+       id = of_alias_get_id((struct device_node *)dailink->cpu_of_node, "ssc");
+       ret = atmel_ssc_set_audio(id);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "failed to set SSC %d for audio\n", id);
+               return ret;
+       }
+
+       mclk = clk_get(NULL, "pck0");
+       if (IS_ERR(mclk)) {
+               dev_err(&pdev->dev, "failed to get pck0\n");
+               ret = PTR_ERR(mclk);
+               goto err_set_audio;
+       }
+
+       clk_src = clk_get(NULL, "clk32k");
+       if (IS_ERR(clk_src)) {
+               dev_err(&pdev->dev, "failed to get clk32k\n");
+               ret = PTR_ERR(clk_src);
+               goto err_set_audio;
+       }
+
+       ret = clk_set_parent(mclk, clk_src);
+       clk_put(clk_src);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "failed to set MCLK parent\n");
+               goto err_set_audio;
+       }
+
+       dev_info(&pdev->dev, "setting pck0 to %dHz\n", MCLK_RATE);
+       clk_set_rate(mclk, MCLK_RATE);
+
+       ret = snd_soc_register_card(card);
+       if (ret) {
+               dev_err(&pdev->dev, "snd_soc_register_card failed\n");
+               goto err_set_audio;
+       }
+
+       return 0;
+
+err_set_audio:
+       atmel_ssc_put_audio(id);
+       return ret;
+}
+
+static int atmel_asoc_wm8904_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+       struct snd_soc_dai_link *dailink = &atmel_asoc_wm8904_dailink;
+       int id;
+
+       id = of_alias_get_id((struct device_node *)dailink->cpu_of_node, "ssc");
+
+       snd_soc_unregister_card(card);
+       atmel_ssc_put_audio(id);
+
+       return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id atmel_asoc_wm8904_dt_ids[] = {
+       { .compatible = "atmel,asoc-wm8904", },
+       { }
+};
+#endif
+
+static struct platform_driver atmel_asoc_wm8904_driver = {
+       .driver = {
+               .name = "atmel-wm8904-audio",
+               .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(atmel_asoc_wm8904_dt_ids),
+       },
+       .probe = atmel_asoc_wm8904_probe,
+       .remove = atmel_asoc_wm8904_remove,
+};
+
+module_platform_driver(atmel_asoc_wm8904_driver);
+
+/* Module information */
+MODULE_AUTHOR("Bo Shen <voice.shen@atmel.com>");
+MODULE_DESCRIPTION("ALSA SoC machine driver for Atmel EK with WM8904 codec");
+MODULE_LICENSE("GPL");
index d6f7694fcad4f78ae1cb300d8d9fe3a4ef3b11d1..c8a2de103c5f3b6b0cb5172f858c687795154d19 100644 (file)
@@ -341,7 +341,7 @@ static struct platform_driver au1xac97c_driver = {
        .remove         = au1xac97c_drvremove,
 };
 
-module_platform_driver(&au1xac97c_driver);
+module_platform_driver(au1xac97c_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Au1000/1500/1100 AC97C ASoC driver");
index a497a0cfeba153aa70630b0dfadc7e69bf2d0e7c..decba87a074c6267eb1bd93265fc8fc96787db7a 100644 (file)
@@ -73,12 +73,14 @@ static struct snd_soc_dai_link db1300_ac97_dai = {
 
 static struct snd_soc_card db1300_ac97_machine = {
        .name           = "DB1300_AC97",
+       .owner          = THIS_MODULE,
        .dai_link       = &db1300_ac97_dai,
        .num_links      = 1,
 };
 
 static struct snd_soc_card db1550_ac97_machine = {
        .name           = "DB1550_AC97",
+       .owner          = THIS_MODULE,
        .dai_link       = &db1200_ac97_dai,
        .num_links      = 1,
 };
@@ -145,6 +147,7 @@ static struct snd_soc_dai_link db1300_i2s_dai = {
 
 static struct snd_soc_card db1300_i2s_machine = {
        .name           = "DB1300_I2S",
+       .owner          = THIS_MODULE,
        .dai_link       = &db1300_i2s_dai,
        .num_links      = 1,
 };
@@ -161,6 +164,7 @@ static struct snd_soc_dai_link db1550_i2s_dai = {
 
 static struct snd_soc_card db1550_i2s_machine = {
        .name           = "DB1550_I2S",
+       .owner          = THIS_MODULE,
        .dai_link       = &db1550_i2s_dai,
        .num_links      = 1,
 };
index a822ab822bb7ba40f5f1ead77a04a7caa7069233..986dcec79fa02e1552fb631456878cb9dbe5f940 100644 (file)
@@ -379,9 +379,6 @@ static int au1xpsc_ac97_drvprobe(struct platform_device *pdev)
        mutex_init(&wd->lock);
 
        iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!iores)
-               return -ENODEV;
-
        wd->mmio = devm_ioremap_resource(&pdev->dev, iores);
        if (IS_ERR(wd->mmio))
                return PTR_ERR(wd->mmio);
index efb1daecd0dd6136122aa8595c145630ff102b22..e82eb373a731402cb60699881aca15a84577f72f 100644 (file)
@@ -294,11 +294,12 @@ static int asoc_bfin_ac97_probe(struct platform_device *pdev)
        /* Request PB3 as reset pin */
        ret = devm_gpio_request_one(&pdev->dev,
                                    CONFIG_SND_BF5XX_RESET_GPIO_NUM,
-                                   GPIOF_OUT_INIT_HIGH, "SND_AD198x RESET") {
+                                   GPIOF_OUT_INIT_HIGH, "SND_AD198x RESET");
+       if (ret) {
                dev_err(&pdev->dev,
                        "Failed to request GPIO_%d for reset: %d\n",
                        CONFIG_SND_BF5XX_RESET_GPIO_NUM, ret);
-               goto gpio_err;
+               return ret;
        }
 #endif
 
index 15c635e33f4d99a42b6386cbc7e7c54e2bf807ef..a680fdc9bb42012f72366a4a09f7ece684a06ce1 100644 (file)
@@ -9,8 +9,6 @@
 #ifndef _BF5XX_AC97_H
 #define _BF5XX_AC97_H
 
-extern struct snd_ac97_bus_ops bf5xx_ac97_ops;
-extern struct snd_ac97 *ac97;
 /* Frame format in memory, only support stereo currently */
 struct ac97_frame {
        u16 ac97_tag;           /* slot 0 */
index 04491f0e8d1bde2636f8772e3b7d3bb65284d44a..efa75b5086a4b00e83802d476c87aae0a6914d0e 100644 (file)
@@ -363,9 +363,6 @@ static int ep93xx_ac97_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENODEV;
-
        info->regs = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(info->regs))
                return PTR_ERR(info->regs);
index 17ad70bca9fe5828d4a8b3b5327dfc6b30bdb260..f23f331e9a974409adf876356a2f766cb81ac812 100644 (file)
@@ -376,9 +376,6 @@ static int ep93xx_i2s_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENODEV;
-
        info->regs = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(info->regs))
                return PTR_ERR(info->regs);
index badb6fbacaa66222bea9cef708c1379783746c7f..8ace02a7c18c2352dca7b4850eda0ff1759c77eb 100644 (file)
@@ -10,6 +10,7 @@ config SND_SOC_I2C_AND_SPI
 
 config SND_SOC_ALL_CODECS
        tristate "Build all ASoC CODEC drivers"
+       depends on COMPILE_TEST
        select SND_SOC_88PM860X if MFD_88PM860X
        select SND_SOC_L3
        select SND_SOC_AB8500_CODEC if ABX500_CORE
@@ -20,6 +21,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_AD73311
        select SND_SOC_ADAU1373 if I2C
        select SND_SOC_ADAV80X if SND_SOC_I2C_AND_SPI
+       select SND_SOC_ADAU1701 if I2C
        select SND_SOC_ADS117X
        select SND_SOC_AK4104 if SPI_MASTER
        select SND_SOC_AK4535 if I2C
@@ -54,6 +56,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_MC13783 if MFD_MC13XXX
        select SND_SOC_ML26124 if I2C
        select SND_SOC_HDMI_CODEC
+       select SND_SOC_PCM1681 if I2C
        select SND_SOC_PCM3008
        select SND_SOC_RT5631 if I2C
        select SND_SOC_RT5640 if I2C
@@ -198,6 +201,9 @@ config SND_SOC_AK4104
 config SND_SOC_AK4535
        tristate
 
+config SND_SOC_AK4554
+       tristate
+
 config SND_SOC_AK4641
        tristate
 
@@ -292,6 +298,9 @@ config SND_SOC_MAX9850
 config SND_SOC_HDMI_CODEC
        tristate
 
+config SND_SOC_PCM1681
+       tristate
+
 config SND_SOC_PCM3008
        tristate
 
index 70fd8066f546e9cfc39dcb024f1efa6e5ea6bf1f..d8fa18eafe4cd5a65d44b6a219eafdaedf26ee3e 100644 (file)
@@ -11,6 +11,7 @@ snd-soc-adav80x-objs := adav80x.o
 snd-soc-ads117x-objs := ads117x.o
 snd-soc-ak4104-objs := ak4104.o
 snd-soc-ak4535-objs := ak4535.o
+snd-soc-ak4554-objs := ak4554.o
 snd-soc-ak4641-objs := ak4641.o
 snd-soc-ak4642-objs := ak4642.o
 snd-soc-ak4671-objs := ak4671.o
@@ -42,6 +43,7 @@ snd-soc-max9850-objs := max9850.o
 snd-soc-mc13783-objs := mc13783.o
 snd-soc-ml26124-objs := ml26124.o
 snd-soc-hdmi-codec-objs := hdmi.o
+snd-soc-pcm1681-objs := pcm1681.o
 snd-soc-pcm3008-objs := pcm3008.o
 snd-soc-rt5631-objs := rt5631.o
 snd-soc-rt5640-objs := rt5640.o
@@ -138,6 +140,7 @@ obj-$(CONFIG_SND_SOC_ADAV80X)  += snd-soc-adav80x.o
 obj-$(CONFIG_SND_SOC_ADS117X)  += snd-soc-ads117x.o
 obj-$(CONFIG_SND_SOC_AK4104)   += snd-soc-ak4104.o
 obj-$(CONFIG_SND_SOC_AK4535)   += snd-soc-ak4535.o
+obj-$(CONFIG_SND_SOC_AK4554)   += snd-soc-ak4554.o
 obj-$(CONFIG_SND_SOC_AK4641)   += snd-soc-ak4641.o
 obj-$(CONFIG_SND_SOC_AK4642)   += snd-soc-ak4642.o
 obj-$(CONFIG_SND_SOC_AK4671)   += snd-soc-ak4671.o
@@ -171,6 +174,7 @@ obj-$(CONFIG_SND_SOC_MAX9850)       += snd-soc-max9850.o
 obj-$(CONFIG_SND_SOC_MC13783)  += snd-soc-mc13783.o
 obj-$(CONFIG_SND_SOC_ML26124)  += snd-soc-ml26124.o
 obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o
+obj-$(CONFIG_SND_SOC_PCM1681)  += snd-soc-pcm1681.o
 obj-$(CONFIG_SND_SOC_PCM3008)  += snd-soc-pcm3008.o
 obj-$(CONFIG_SND_SOC_RT5631)   += snd-soc-rt5631.o
 obj-$(CONFIG_SND_SOC_RT5640)   += snd-soc-rt5640.o
index d1124a5b34713c688d92846e25cca563ed9c20ff..2c102522bbbc5202fb94d8d119b65a782c77e035 100644 (file)
@@ -91,7 +91,7 @@
 #define ADAU1701_OSCIPOW_OPD           0x04
 #define ADAU1701_DACSET_DACINIT                1
 
-#define ADAU1707_CLKDIV_UNSET          (-1UL)
+#define ADAU1707_CLKDIV_UNSET          (-1U)
 
 #define ADAU1701_FIRMWARE "adau1701.bin"
 
@@ -734,7 +734,10 @@ static int adau1701_i2c_remove(struct i2c_client *client)
 }
 
 static const struct i2c_device_id adau1701_i2c_id[] = {
+       { "adau1401", 0 },
+       { "adau1401a", 0 },
        { "adau1701", 0 },
+       { "adau1702", 0 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, adau1701_i2c_id);
index 3c839cc4e00ecb48a5e3948567c14dbede7706a3..15b012d0f226c48a4178b1c9f4d10468708dcd1d 100644 (file)
@@ -868,6 +868,12 @@ static int adav80x_bus_remove(struct device *dev)
 }
 
 #if defined(CONFIG_SPI_MASTER)
+static const struct spi_device_id adav80x_spi_id[] = {
+       { "adav801", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(spi, adav80x_spi_id);
+
 static int adav80x_spi_probe(struct spi_device *spi)
 {
        return adav80x_bus_probe(&spi->dev, SND_SOC_SPI);
@@ -885,15 +891,16 @@ static struct spi_driver adav80x_spi_driver = {
        },
        .probe          = adav80x_spi_probe,
        .remove         = adav80x_spi_remove,
+       .id_table       = adav80x_spi_id,
 };
 #endif
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-static const struct i2c_device_id adav80x_id[] = {
+static const struct i2c_device_id adav80x_i2c_id[] = {
        { "adav803", 0 },
        { }
 };
-MODULE_DEVICE_TABLE(i2c, adav80x_id);
+MODULE_DEVICE_TABLE(i2c, adav80x_i2c_id);
 
 static int adav80x_i2c_probe(struct i2c_client *client,
                             const struct i2c_device_id *id)
@@ -913,7 +920,7 @@ static struct i2c_driver adav80x_i2c_driver = {
        },
        .probe = adav80x_i2c_probe,
        .remove = adav80x_i2c_remove,
-       .id_table = adav80x_id,
+       .id_table = adav80x_i2c_id,
 };
 #endif
 
diff --git a/sound/soc/codecs/ak4554.c b/sound/soc/codecs/ak4554.c
new file mode 100644 (file)
index 0000000..6aed9c4
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * ak4554.c
+ *
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <sound/soc.h>
+
+/*
+ * ak4554 is very simple DA/AD converter which has no setting register.
+ *
+ * CAUTION
+ *
+ * ak4554 playback format is SND_SOC_DAIFMT_RIGHT_J,
+ * and,   capture  format is SND_SOC_DAIFMT_LEFT_J
+ * on same bit clock, LR clock.
+ * But, this driver doesn't have snd_soc_dai_ops :: set_fmt
+ *
+ * CPU/Codec DAI image
+ *
+ * CPU-DAI1 (plaback only fmt = RIGHT_J) --+-- ak4554
+ *                                        |
+ * CPU-DAI2 (capture only fmt = LEFT_J) ---+
+ */
+
+static struct snd_soc_dai_driver ak4554_dai = {
+       .name = "ak4554-hifi",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .symmetric_rates = 1,
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_ak4554 = {
+};
+
+static int ak4554_soc_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev,
+                                     &soc_codec_dev_ak4554,
+                                     &ak4554_dai, 1);
+}
+
+static int ak4554_soc_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
+static struct of_device_id ak4554_of_match[] = {
+       { .compatible = "asahi-kasei,ak4554" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, ak4554_of_match);
+
+static struct platform_driver ak4554_driver = {
+       .driver = {
+               .name = "ak4554-adc-dac",
+               .owner = THIS_MODULE,
+               .of_match_table = ak4554_of_match,
+       },
+       .probe  = ak4554_soc_probe,
+       .remove = ak4554_soc_remove,
+};
+module_platform_driver(ak4554_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SoC AK4554 driver");
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
index de625813c0e65c7aff7807d6904c53d2c581249d..8dc6881496dea26942e6cf4a84b1cc68fe4cb992 100644 (file)
@@ -19,6 +19,7 @@
 #include <sound/tlv.h>
 
 #include <linux/mfd/arizona/core.h>
+#include <linux/mfd/arizona/gpio.h>
 #include <linux/mfd/arizona/registers.h>
 
 #include "arizona.h"
@@ -223,6 +224,41 @@ int arizona_init_spk(struct snd_soc_codec *codec)
 }
 EXPORT_SYMBOL_GPL(arizona_init_spk);
 
+int arizona_init_gpio(struct snd_soc_codec *codec)
+{
+       struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+       struct arizona *arizona = priv->arizona;
+       int i;
+
+       switch (arizona->type) {
+       case WM5110:
+               snd_soc_dapm_disable_pin(&codec->dapm, "DRC2 Signal Activity");
+               break;
+       default:
+               break;
+       }
+
+       snd_soc_dapm_disable_pin(&codec->dapm, "DRC1 Signal Activity");
+
+       for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
+               switch (arizona->pdata.gpio_defaults[i] & ARIZONA_GPN_FN_MASK) {
+               case ARIZONA_GP_FN_DRC1_SIGNAL_DETECT:
+                       snd_soc_dapm_enable_pin(&codec->dapm,
+                                               "DRC1 Signal Activity");
+                       break;
+               case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT:
+                       snd_soc_dapm_enable_pin(&codec->dapm,
+                                               "DRC2 Signal Activity");
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_init_gpio);
+
 const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
        "None",
        "Tone Generator 1",
index b60b08ccc1d06e54bf09579ec1ffff3640cb2d15..fe1b794bd5f044619d260bd02d641b11d0836d7c 100644 (file)
@@ -242,6 +242,7 @@ extern int arizona_set_fll(struct arizona_fll *fll, int source,
                           unsigned int Fref, unsigned int Fout);
 
 extern int arizona_init_spk(struct snd_soc_codec *codec);
+extern int arizona_init_gpio(struct snd_soc_codec *codec);
 
 extern int arizona_init_dai(struct arizona_priv *priv, int dai);
 
index 2bcae2b40c92cd48a35aaf59ad333bb689851ff2..f0986b9f193977befa154fb9dc4e4ea0269c3b9a 100644 (file)
@@ -37,6 +37,17 @@ static struct snd_soc_dai_driver hdmi_codec_dai = {
                .formats = SNDRV_PCM_FMTBIT_S16_LE |
                        SNDRV_PCM_FMTBIT_S24_LE,
        },
+       .capture = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_32000 |
+                       SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+                       SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+                       SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE |
+                       SNDRV_PCM_FMTBIT_S24_LE,
+       },
+
 };
 
 static int hdmi_codec_probe(struct platform_device *pdev)
index 9f9f59573f721344995233da13ddf875f43436fc..0e5743ea79dfdf6c4a4191694955883fbede59ca 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/i2c.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
 
 #include <sound/core.h>
 #include <sound/tlv.h>
 
 struct lm4857 {
-       struct i2c_client *i2c;
+       struct regmap *regmap;
        uint8_t mode;
 };
 
-static const uint8_t lm4857_default_regs[] = {
-       0x00, 0x00, 0x00, 0x00,
+static const struct reg_default lm4857_default_regs[] = {
+       { 0x0, 0x00 },
+       { 0x1, 0x00 },
+       { 0x2, 0x00 },
+       { 0x3, 0x00 },
 };
 
 /* The register offsets in the cache array */
@@ -42,39 +46,6 @@ static const uint8_t lm4857_default_regs[] = {
 #define LM4857_WAKEUP 5
 #define LM4857_EPGAIN 4
 
-static int lm4857_write(struct snd_soc_codec *codec, unsigned int reg,
-               unsigned int value)
-{
-       uint8_t data;
-       int ret;
-
-       ret = snd_soc_cache_write(codec, reg, value);
-       if (ret < 0)
-               return ret;
-
-       data = (reg << 6) | value;
-       ret = i2c_master_send(codec->control_data, &data, 1);
-       if (ret != 1) {
-               dev_err(codec->dev, "Failed to write register: %d\n", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-static unsigned int lm4857_read(struct snd_soc_codec *codec,
-               unsigned int reg)
-{
-       unsigned int val;
-       int ret;
-
-       ret = snd_soc_cache_read(codec, reg, &val);
-       if (ret)
-               return -1;
-
-       return val;
-}
-
 static int lm4857_get_mode(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
@@ -96,7 +67,7 @@ static int lm4857_set_mode(struct snd_kcontrol *kcontrol,
        lm4857->mode = value;
 
        if (codec->dapm.bias_level == SND_SOC_BIAS_ON)
-               snd_soc_update_bits(codec, LM4857_CTRL, 0x0F, value + 6);
+               regmap_update_bits(lm4857->regmap, LM4857_CTRL, 0x0F, value + 6);
 
        return 1;
 }
@@ -108,10 +79,11 @@ static int lm4857_set_bias_level(struct snd_soc_codec *codec,
 
        switch (level) {
        case SND_SOC_BIAS_ON:
-               snd_soc_update_bits(codec, LM4857_CTRL, 0x0F, lm4857->mode + 6);
+               regmap_update_bits(lm4857->regmap, LM4857_CTRL, 0x0F,
+                       lm4857->mode + 6);
                break;
        case SND_SOC_BIAS_STANDBY:
-               snd_soc_update_bits(codec, LM4857_CTRL, 0x0F, 0);
+               regmap_update_bits(lm4857->regmap, LM4857_CTRL, 0x0F, 0);
                break;
        default:
                break;
@@ -171,49 +143,32 @@ static const struct snd_soc_dapm_route lm4857_routes[] = {
        {"EP", NULL, "IN"},
 };
 
-static int lm4857_probe(struct snd_soc_codec *codec)
-{
-       struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec);
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-       int ret;
-
-       codec->control_data = lm4857->i2c;
-
-       ret = snd_soc_add_codec_controls(codec, lm4857_controls,
-                       ARRAY_SIZE(lm4857_controls));
-       if (ret)
-               return ret;
-
-       ret = snd_soc_dapm_new_controls(dapm, lm4857_dapm_widgets,
-                       ARRAY_SIZE(lm4857_dapm_widgets));
-       if (ret)
-               return ret;
+static struct snd_soc_codec_driver soc_codec_dev_lm4857 = {
+       .set_bias_level = lm4857_set_bias_level,
 
-       ret = snd_soc_dapm_add_routes(dapm, lm4857_routes,
-                       ARRAY_SIZE(lm4857_routes));
-       if (ret)
-               return ret;
+       .controls = lm4857_controls,
+       .num_controls = ARRAY_SIZE(lm4857_controls),
+       .dapm_widgets = lm4857_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(lm4857_dapm_widgets),
+       .dapm_routes = lm4857_routes,
+       .num_dapm_routes = ARRAY_SIZE(lm4857_routes),
+};
 
-       snd_soc_dapm_new_widgets(dapm);
+static const struct regmap_config lm4857_regmap_config = {
+       .val_bits = 6,
+       .reg_bits = 2,
 
-       return 0;
-}
+       .max_register = LM4857_CTRL,
 
-static struct snd_soc_codec_driver soc_codec_dev_lm4857 = {
-       .write = lm4857_write,
-       .read = lm4857_read,
-       .probe = lm4857_probe,
-       .reg_cache_size = ARRAY_SIZE(lm4857_default_regs),
-       .reg_word_size = sizeof(uint8_t),
-       .reg_cache_default = lm4857_default_regs,
-       .set_bias_level = lm4857_set_bias_level,
+       .cache_type = REGCACHE_FLAT,
+       .reg_defaults = lm4857_default_regs,
+       .num_reg_defaults = ARRAY_SIZE(lm4857_default_regs),
 };
 
 static int lm4857_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
        struct lm4857 *lm4857;
-       int ret;
 
        lm4857 = devm_kzalloc(&i2c->dev, sizeof(*lm4857), GFP_KERNEL);
        if (!lm4857)
@@ -221,11 +176,11 @@ static int lm4857_i2c_probe(struct i2c_client *i2c,
 
        i2c_set_clientdata(i2c, lm4857);
 
-       lm4857->i2c = i2c;
-
-       ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_lm4857, NULL, 0);
+       lm4857->regmap = devm_regmap_init_i2c(i2c, &lm4857_regmap_config);
+       if (IS_ERR(lm4857->regmap))
+               return PTR_ERR(lm4857->regmap);
 
-       return ret;
+       return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_lm4857, NULL, 0);
 }
 
 static int lm4857_i2c_remove(struct i2c_client *i2c)
index ad5313f98f286b8f95223b56ef88ae4718f7a73d..0569a4c3ae00e7ce8b8fb27952387d87913f4098 100644 (file)
@@ -2084,8 +2084,9 @@ static irqreturn_t max98090_interrupt(int irq, void *data)
 
                pm_wakeup_event(codec->dev, 100);
 
-               schedule_delayed_work(&max98090->jack_work,
-                       msecs_to_jiffies(100));
+               queue_delayed_work(system_power_efficient_wq,
+                                  &max98090->jack_work,
+                                  msecs_to_jiffies(100));
        }
 
        if (active & M98090_DRCACT_MASK)
@@ -2132,8 +2133,9 @@ int max98090_mic_detect(struct snd_soc_codec *codec,
        snd_soc_jack_report(max98090->jack, 0,
                            SND_JACK_HEADSET | SND_JACK_BTN_0);
 
-       schedule_delayed_work(&max98090->jack_work,
-               msecs_to_jiffies(100));
+       queue_delayed_work(system_power_efficient_wq,
+                          &max98090->jack_work,
+                          msecs_to_jiffies(100));
 
        return 0;
 }
diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c
new file mode 100644 (file)
index 0000000..27da41b
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+ * PCM1681 ASoC codec driver
+ *
+ * Copyright (c) StreamUnlimited GmbH 2013
+ *     Marek Belisko <marek.belisko@streamunlimited.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#define PCM1681_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE  |                \
+                            SNDRV_PCM_FMTBIT_S24_LE)
+
+#define PCM1681_PCM_RATES   (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \
+                            SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100  | \
+                            SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200  | \
+                            SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+
+#define PCM1681_SOFT_MUTE_ALL          0xff
+#define PCM1681_DEEMPH_RATE_MASK       0x18
+#define PCM1681_DEEMPH_MASK            0x01
+
+#define PCM1681_ATT_CONTROL(X) (X <= 6 ? X : X + 9) /* Attenuation level */
+#define PCM1681_SOFT_MUTE      0x07    /* Soft mute control register */
+#define PCM1681_DAC_CONTROL    0x08    /* DAC operation control */
+#define PCM1681_FMT_CONTROL    0x09    /* Audio interface data format */
+#define PCM1681_DEEMPH_CONTROL 0x0a    /* De-emphasis control */
+#define PCM1681_ZERO_DETECT_STATUS     0x0e    /* Zero detect status reg */
+
+static const struct reg_default pcm1681_reg_defaults[] = {
+       { 0x01, 0xff },
+       { 0x02, 0xff },
+       { 0x03, 0xff },
+       { 0x04, 0xff },
+       { 0x05, 0xff },
+       { 0x06, 0xff },
+       { 0x07, 0x00 },
+       { 0x08, 0x00 },
+       { 0x09, 0x06 },
+       { 0x0A, 0x00 },
+       { 0x0B, 0xff },
+       { 0x0C, 0x0f },
+       { 0x0D, 0x00 },
+       { 0x10, 0xff },
+       { 0x11, 0xff },
+       { 0x12, 0x00 },
+       { 0x13, 0x00 },
+};
+
+static bool pcm1681_accessible_reg(struct device *dev, unsigned int reg)
+{
+       return !((reg == 0x00) || (reg == 0x0f));
+}
+
+static bool pcm1681_writeable_reg(struct device *dev, unsigned register reg)
+{
+       return pcm1681_accessible_reg(dev, reg) &&
+               (reg != PCM1681_ZERO_DETECT_STATUS);
+}
+
+struct pcm1681_private {
+       struct regmap *regmap;
+       unsigned int format;
+       /* Current deemphasis status */
+       unsigned int deemph;
+       /* Current rate for deemphasis control */
+       unsigned int rate;
+};
+
+static const int pcm1681_deemph[] = { 44100, 48000, 32000 };
+
+static int pcm1681_set_deemph(struct snd_soc_codec *codec)
+{
+       struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
+       int i = 0, val = -1, enable = 0;
+
+       if (priv->deemph)
+               for (i = 0; i < ARRAY_SIZE(pcm1681_deemph); i++)
+                       if (pcm1681_deemph[i] == priv->rate)
+                               val = i;
+
+       if (val != -1) {
+               regmap_update_bits(priv->regmap, PCM1681_DEEMPH_CONTROL,
+                                       PCM1681_DEEMPH_RATE_MASK, val);
+               enable = 1;
+       } else
+               enable = 0;
+
+       /* enable/disable deemphasis functionality */
+       return regmap_update_bits(priv->regmap, PCM1681_DEEMPH_CONTROL,
+                                       PCM1681_DEEMPH_MASK, enable);
+}
+
+static int pcm1681_get_deemph(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.enumerated.item[0] = priv->deemph;
+
+       return 0;
+}
+
+static int pcm1681_put_deemph(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
+
+       priv->deemph = ucontrol->value.enumerated.item[0];
+
+       return pcm1681_set_deemph(codec);
+}
+
+static int pcm1681_set_dai_fmt(struct snd_soc_dai *codec_dai,
+                             unsigned int format)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
+
+       /* The PCM1681 can only be slave to all clocks */
+       if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
+               dev_err(codec->dev, "Invalid clocking mode\n");
+               return -EINVAL;
+       }
+
+       priv->format = format;
+
+       return 0;
+}
+
+static int pcm1681_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
+       int val;
+
+       if (mute)
+               val = PCM1681_SOFT_MUTE_ALL;
+       else
+               val = 0;
+
+       return regmap_write(priv->regmap, PCM1681_SOFT_MUTE, val);
+}
+
+static int pcm1681_hw_params(struct snd_pcm_substream *substream,
+                            struct snd_pcm_hw_params *params,
+                            struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
+       int val = 0, ret;
+       int pcm_format = params_format(params);
+
+       priv->rate = params_rate(params);
+
+       switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_RIGHT_J:
+               if (pcm_format == SNDRV_PCM_FORMAT_S24_LE)
+                       val = 0x00;
+               else if (pcm_format == SNDRV_PCM_FORMAT_S16_LE)
+                       val = 0x03;
+               break;
+       case SND_SOC_DAIFMT_I2S:
+               val = 0x04;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               val = 0x05;
+               break;
+       default:
+               dev_err(codec->dev, "Invalid DAI format\n");
+               return -EINVAL;
+       }
+
+       ret = regmap_update_bits(priv->regmap, PCM1681_FMT_CONTROL, 0x0f, val);
+       if (ret < 0)
+               return ret;
+
+       return pcm1681_set_deemph(codec);
+}
+
+static const struct snd_soc_dai_ops pcm1681_dai_ops = {
+       .set_fmt        = pcm1681_set_dai_fmt,
+       .hw_params      = pcm1681_hw_params,
+       .digital_mute   = pcm1681_digital_mute,
+};
+
+static const DECLARE_TLV_DB_SCALE(pcm1681_dac_tlv, -6350, 50, 1);
+
+static const struct snd_kcontrol_new pcm1681_controls[] = {
+       SOC_DOUBLE_R_TLV("Channel 1/2 Playback Volume",
+                       PCM1681_ATT_CONTROL(1), PCM1681_ATT_CONTROL(2), 0,
+                       0x7f, 0, pcm1681_dac_tlv),
+       SOC_DOUBLE_R_TLV("Channel 3/4 Playback Volume",
+                       PCM1681_ATT_CONTROL(3), PCM1681_ATT_CONTROL(4), 0,
+                       0x7f, 0, pcm1681_dac_tlv),
+       SOC_DOUBLE_R_TLV("Channel 5/6 Playback Volume",
+                       PCM1681_ATT_CONTROL(5), PCM1681_ATT_CONTROL(6), 0,
+                       0x7f, 0, pcm1681_dac_tlv),
+       SOC_DOUBLE_R_TLV("Channel 7/8 Playback Volume",
+                       PCM1681_ATT_CONTROL(7), PCM1681_ATT_CONTROL(8), 0,
+                       0x7f, 0, pcm1681_dac_tlv),
+       SOC_SINGLE_BOOL_EXT("De-emphasis Switch", 0,
+                           pcm1681_get_deemph, pcm1681_put_deemph),
+};
+
+struct snd_soc_dai_driver pcm1681_dai = {
+       .name = "pcm1681-hifi",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 8,
+               .rates = PCM1681_PCM_RATES,
+               .formats = PCM1681_PCM_FORMATS,
+       },
+       .ops = &pcm1681_dai_ops,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id pcm1681_dt_ids[] = {
+       { .compatible = "ti,pcm1681", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, pcm1681_dt_ids);
+#endif
+
+static const struct regmap_config pcm1681_regmap = {
+       .reg_bits               = 8,
+       .val_bits               = 8,
+       .max_register           = ARRAY_SIZE(pcm1681_reg_defaults) + 1,
+       .reg_defaults           = pcm1681_reg_defaults,
+       .num_reg_defaults       = ARRAY_SIZE(pcm1681_reg_defaults),
+       .writeable_reg          = pcm1681_writeable_reg,
+       .readable_reg           = pcm1681_accessible_reg,
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_pcm1681 = {
+       .controls               = pcm1681_controls,
+       .num_controls           = ARRAY_SIZE(pcm1681_controls),
+};
+
+static const struct i2c_device_id pcm1681_i2c_id[] = {
+       {"pcm1681", 0},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, pcm1681_i2c_id);
+
+static int pcm1681_i2c_probe(struct i2c_client *client,
+                             const struct i2c_device_id *id)
+{
+       int ret;
+       struct pcm1681_private *priv;
+
+       priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->regmap = devm_regmap_init_i2c(client, &pcm1681_regmap);
+       if (IS_ERR(priv->regmap)) {
+               ret = PTR_ERR(priv->regmap);
+               dev_err(&client->dev, "Failed to create regmap: %d\n", ret);
+               return ret;
+       }
+
+       i2c_set_clientdata(client, priv);
+
+       return snd_soc_register_codec(&client->dev, &soc_codec_dev_pcm1681,
+               &pcm1681_dai, 1);
+}
+
+static int pcm1681_i2c_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+       return 0;
+}
+
+static struct i2c_driver pcm1681_i2c_driver = {
+       .driver = {
+               .name   = "pcm1681",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(pcm1681_dt_ids),
+       },
+       .id_table       = pcm1681_i2c_id,
+       .probe          = pcm1681_i2c_probe,
+       .remove         = pcm1681_i2c_remove,
+};
+
+module_i2c_driver(pcm1681_i2c_driver);
+
+MODULE_DESCRIPTION("Texas Instruments PCM1681 ALSA SoC Codec Driver");
+MODULE_AUTHOR("Marek Belisko <marek.belisko@streamunlimited.com>");
+MODULE_LICENSE("GPL");
index f2a6282b41f4e07a1627463222b4ba9d091a7cf1..b883f99d6f9f18f09621b38d9b006c7b2bcc64b1 100644 (file)
@@ -28,8 +28,6 @@
 
 #include "pcm3008.h"
 
-#define PCM3008_VERSION "0.2"
-
 #define PCM3008_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |   \
                       SNDRV_PCM_RATE_48000)
 
@@ -51,72 +49,6 @@ static struct snd_soc_dai_driver pcm3008_dai = {
        },
 };
 
-static void pcm3008_gpio_free(struct pcm3008_setup_data *setup)
-{
-       gpio_free(setup->dem0_pin);
-       gpio_free(setup->dem1_pin);
-       gpio_free(setup->pdad_pin);
-       gpio_free(setup->pdda_pin);
-}
-
-static int pcm3008_soc_probe(struct snd_soc_codec *codec)
-{
-       struct pcm3008_setup_data *setup = codec->dev->platform_data;
-       int ret = 0;
-
-       printk(KERN_INFO "PCM3008 SoC Audio Codec %s\n", PCM3008_VERSION);
-
-       /* DEM1  DEM0  DE-EMPHASIS_MODE
-        * Low   Low   De-emphasis 44.1 kHz ON
-        * Low   High  De-emphasis OFF
-        * High  Low   De-emphasis 48 kHz ON
-        * High  High  De-emphasis 32 kHz ON
-        */
-
-       /* Configure DEM0 GPIO (turning OFF DAC De-emphasis). */
-       ret = gpio_request(setup->dem0_pin, "codec_dem0");
-       if (ret == 0)
-               ret = gpio_direction_output(setup->dem0_pin, 1);
-       if (ret != 0)
-               goto gpio_err;
-
-       /* Configure DEM1 GPIO (turning OFF DAC De-emphasis). */
-       ret = gpio_request(setup->dem1_pin, "codec_dem1");
-       if (ret == 0)
-               ret = gpio_direction_output(setup->dem1_pin, 0);
-       if (ret != 0)
-               goto gpio_err;
-
-       /* Configure PDAD GPIO. */
-       ret = gpio_request(setup->pdad_pin, "codec_pdad");
-       if (ret == 0)
-               ret = gpio_direction_output(setup->pdad_pin, 1);
-       if (ret != 0)
-               goto gpio_err;
-
-       /* Configure PDDA GPIO. */
-       ret = gpio_request(setup->pdda_pin, "codec_pdda");
-       if (ret == 0)
-               ret = gpio_direction_output(setup->pdda_pin, 1);
-       if (ret != 0)
-               goto gpio_err;
-
-       return ret;
-
-gpio_err:
-       pcm3008_gpio_free(setup);
-
-       return ret;
-}
-
-static int pcm3008_soc_remove(struct snd_soc_codec *codec)
-{
-       struct pcm3008_setup_data *setup = codec->dev->platform_data;
-
-       pcm3008_gpio_free(setup);
-       return 0;
-}
-
 #ifdef CONFIG_PM
 static int pcm3008_soc_suspend(struct snd_soc_codec *codec)
 {
@@ -143,14 +75,49 @@ static int pcm3008_soc_resume(struct snd_soc_codec *codec)
 #endif
 
 static struct snd_soc_codec_driver soc_codec_dev_pcm3008 = {
-       .probe =        pcm3008_soc_probe,
-       .remove =       pcm3008_soc_remove,
        .suspend =      pcm3008_soc_suspend,
        .resume =       pcm3008_soc_resume,
 };
 
 static int pcm3008_codec_probe(struct platform_device *pdev)
 {
+       struct pcm3008_setup_data *setup = pdev->dev.platform_data;
+       int ret;
+
+       if (!setup)
+               return -EINVAL;
+
+       /* DEM1  DEM0  DE-EMPHASIS_MODE
+        * Low   Low   De-emphasis 44.1 kHz ON
+        * Low   High  De-emphasis OFF
+        * High  Low   De-emphasis 48 kHz ON
+        * High  High  De-emphasis 32 kHz ON
+        */
+
+       /* Configure DEM0 GPIO (turning OFF DAC De-emphasis). */
+       ret = devm_gpio_request_one(&pdev->dev, setup->dem0_pin,
+                                   GPIOF_OUT_INIT_HIGH, "codec_dem0");
+       if (ret != 0)
+               return ret;
+
+       /* Configure DEM1 GPIO (turning OFF DAC De-emphasis). */
+       ret = devm_gpio_request_one(&pdev->dev, setup->dem1_pin,
+                                   GPIOF_OUT_INIT_LOW, "codec_dem1");
+       if (ret != 0)
+               return ret;
+
+       /* Configure PDAD GPIO. */
+       ret = devm_gpio_request_one(&pdev->dev, setup->pdad_pin,
+                                   GPIOF_OUT_INIT_HIGH, "codec_pdad");
+       if (ret != 0)
+               return ret;
+
+       /* Configure PDDA GPIO. */
+       ret = devm_gpio_request_one(&pdev->dev, setup->pdda_pin,
+                                   GPIOF_OUT_INIT_HIGH, "codec_pdda");
+       if (ret != 0)
+               return ret;
+
        return snd_soc_register_codec(&pdev->dev,
                        &soc_codec_dev_pcm3008, &pcm3008_dai, 1);
 }
@@ -158,6 +125,7 @@ static int pcm3008_codec_probe(struct platform_device *pdev)
 static int pcm3008_codec_remove(struct platform_device *pdev)
 {
        snd_soc_unregister_codec(&pdev->dev);
+
        return 0;
 }
 
index 6c8a9e7bee25c837cd35dc260847e1c778a811b6..c8b9090e69783b8d017659f227f152a57f1c9122 100644 (file)
@@ -1470,6 +1470,7 @@ static struct snd_soc_codec_driver sgtl5000_driver = {
 static const struct regmap_config sgtl5000_regmap = {
        .reg_bits = 16,
        .val_bits = 16,
+       .reg_stride = 2,
 
        .max_register = SGTL5000_MAX_REG_OFFSET,
        .volatile_reg = sgtl5000_volatile,
index e9d7881ed2c8272c2c64c7255e60728356aab009..26d34744c677651a407909c3c18f61128d583199 100644 (file)
@@ -25,6 +25,8 @@
 
 #define STUB_RATES     SNDRV_PCM_RATE_8000_192000
 #define STUB_FORMATS   (SNDRV_PCM_FMTBIT_S16_LE | \
+                       SNDRV_PCM_FMTBIT_S20_3LE | \
+                       SNDRV_PCM_FMTBIT_S24_LE | \
                        SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
 
 static struct snd_soc_codec_driver soc_codec_spdif_dir;
index 18280499fd554ee13ca7f9c17d86c8594a40d8bb..efc3d88d7f8c0c6520a601c0e545f02d21fca0a8 100644 (file)
@@ -25,8 +25,9 @@
 #define DRV_NAME "spdif-dit"
 
 #define STUB_RATES     SNDRV_PCM_RATE_8000_96000
-#define STUB_FORMATS   SNDRV_PCM_FMTBIT_S16_LE
-
+#define STUB_FORMATS   (SNDRV_PCM_FMTBIT_S16_LE | \
+                       SNDRV_PCM_FMTBIT_S20_3LE | \
+                       SNDRV_PCM_FMTBIT_S24_LE)
 
 static struct snd_soc_codec_driver soc_codec_spdif_dit;
 
index cfb55fe35e98691cbaf7b18404b93e02c1cce73c..06edb396e733f1ad2ef26698a41b4eb1fdc18ea6 100644 (file)
@@ -363,16 +363,18 @@ static void sta32x_watchdog(struct work_struct *work)
        }
 
        if (!sta32x->shutdown)
-               schedule_delayed_work(&sta32x->watchdog_work,
-                                     round_jiffies_relative(HZ));
+               queue_delayed_work(system_power_efficient_wq,
+                                  &sta32x->watchdog_work,
+                                  round_jiffies_relative(HZ));
 }
 
 static void sta32x_watchdog_start(struct sta32x_priv *sta32x)
 {
        if (sta32x->pdata->needs_esd_watchdog) {
                sta32x->shutdown = 0;
-               schedule_delayed_work(&sta32x->watchdog_work,
-                                     round_jiffies_relative(HZ));
+               queue_delayed_work(system_power_efficient_wq,
+                                  &sta32x->watchdog_work,
+                                  round_jiffies_relative(HZ));
        }
 }
 
index e5b926883131180c71cfe6239d1bca3be8fcf674..6e3f269243e050fe5149e60807c0e41cbf6e4147 100644 (file)
@@ -138,8 +138,7 @@ static const u8 aic3x_reg[AIC3X_CACHEREGNUM] = {
 static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
                                        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+       struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
        unsigned int reg = mc->reg;
@@ -147,10 +146,9 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
        int max = mc->max;
        unsigned int mask = (1 << fls(max)) - 1;
        unsigned int invert = mc->invert;
-       unsigned short val, val_mask;
-       int ret;
-       struct snd_soc_dapm_path *path;
-       int found = 0;
+       unsigned short val;
+       struct snd_soc_dapm_update update;
+       int connect, change;
 
        val = (ucontrol->value.integer.value[0] & mask);
 
@@ -158,42 +156,26 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
        if (val)
                val = mask;
 
+       connect = !!val;
+
        if (invert)
                val = mask - val;
-       val_mask = mask << shift;
-       val = val << shift;
-
-       mutex_lock(&widget->codec->mutex);
 
-       if (snd_soc_test_bits(widget->codec, reg, val_mask, val)) {
-               /* find dapm widget path assoc with kcontrol */
-               list_for_each_entry(path, &widget->dapm->card->paths, list) {
-                       if (path->kcontrol != kcontrol)
-                               continue;
+       mask <<= shift;
+       val <<= shift;
 
-                       /* found, now check type */
-                       found = 1;
-                       if (val)
-                               /* new connection */
-                               path->connect = invert ? 0 : 1;
-                       else
-                               /* old connection must be powered down */
-                               path->connect = invert ? 1 : 0;
+       change = snd_soc_test_bits(codec, val, mask, reg);
+       if (change) {
+               update.kcontrol = kcontrol;
+               update.reg = reg;
+               update.mask = mask;
+               update.val = val;
 
-                       dapm_mark_dirty(path->source, "tlv320aic3x source");
-                       dapm_mark_dirty(path->sink, "tlv320aic3x sink");
-
-                       break;
-               }
+               snd_soc_dapm_mixer_update_power(&codec->dapm, kcontrol, connect,
+                       &update);
        }
 
-       mutex_unlock(&widget->codec->mutex);
-
-       if (found)
-               snd_soc_dapm_sync(widget->dapm);
-
-       ret = snd_soc_update_bits_locked(widget->codec, reg, val_mask, val);
-       return ret;
+       return change;
 }
 
 /*
@@ -1492,6 +1474,7 @@ static const struct i2c_device_id aic3x_i2c_id[] = {
        { "tlv320aic3x", AIC3X_MODEL_3X },
        { "tlv320aic33", AIC3X_MODEL_33 },
        { "tlv320aic3007", AIC3X_MODEL_3007 },
+       { "tlv320aic3106", AIC3X_MODEL_3X },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id);
@@ -1582,6 +1565,9 @@ static int aic3x_i2c_remove(struct i2c_client *client)
 #if defined(CONFIG_OF)
 static const struct of_device_id tlv320aic3x_of_match[] = {
        { .compatible = "ti,tlv320aic3x", },
+       { .compatible = "ti,tlv320aic33" },
+       { .compatible = "ti,tlv320aic3007" },
+       { .compatible = "ti,tlv320aic3106" },
        {},
 };
 MODULE_DEVICE_TABLE(of, tlv320aic3x_of_match);
index 44621ddc332d881b5e4b05a58507060259446e55..3c79dbb6c32323b36bc974616c5ff1157498f281 100644 (file)
@@ -429,7 +429,8 @@ static irqreturn_t twl6040_audio_handler(int irq, void *data)
        struct snd_soc_codec *codec = data;
        struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
 
-       schedule_delayed_work(&priv->hs_jack.work, msecs_to_jiffies(200));
+       queue_delayed_work(system_power_efficient_wq,
+                          &priv->hs_jack.work, msecs_to_jiffies(200));
 
        return IRQ_HANDLED;
 }
@@ -437,9 +438,7 @@ static irqreturn_t twl6040_audio_handler(int irq, void *data)
 static int twl6040_soc_dapm_put_vibra_enum(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-       struct snd_soc_codec *codec = widget->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int val;
 
index 6d0aa44c375755fb8715c2089d27d4a3686598f1..c94d4c1e3dacc1d7a51f2c6708848d56af6ecf9e 100644 (file)
@@ -325,7 +325,6 @@ static int uda134x_set_dai_fmt(struct snd_soc_dai *codec_dai,
 static int uda134x_set_bias_level(struct snd_soc_codec *codec,
                                  enum snd_soc_bias_level level)
 {
-       u8 reg;
        struct uda134x_platform_data *pd = codec->control_data;
        int i;
        u8 *cache = codec->reg_cache;
@@ -334,23 +333,6 @@ static int uda134x_set_bias_level(struct snd_soc_codec *codec,
 
        switch (level) {
        case SND_SOC_BIAS_ON:
-               /* ADC, DAC on */
-               switch (pd->model) {
-               case UDA134X_UDA1340:
-               case UDA134X_UDA1344:
-               case UDA134X_UDA1345:
-                       reg = uda134x_read_reg_cache(codec, UDA134X_DATA011);
-                       uda134x_write(codec, UDA134X_DATA011, reg | 0x03);
-                       break;
-               case UDA134X_UDA1341:
-                       reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1);
-                       uda134x_write(codec, UDA134X_STATUS1, reg | 0x03);
-                       break;
-               default:
-                       printk(KERN_ERR "UDA134X SoC codec: "
-                              "unsupported model %d\n", pd->model);
-                       return -EINVAL;
-               }
                break;
        case SND_SOC_BIAS_PREPARE:
                /* power on */
@@ -362,23 +344,6 @@ static int uda134x_set_bias_level(struct snd_soc_codec *codec,
                }
                break;
        case SND_SOC_BIAS_STANDBY:
-               /* ADC, DAC power off */
-               switch (pd->model) {
-               case UDA134X_UDA1340:
-               case UDA134X_UDA1344:
-               case UDA134X_UDA1345:
-                       reg = uda134x_read_reg_cache(codec, UDA134X_DATA011);
-                       uda134x_write(codec, UDA134X_DATA011, reg & ~(0x03));
-                       break;
-               case UDA134X_UDA1341:
-                       reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1);
-                       uda134x_write(codec, UDA134X_STATUS1, reg & ~(0x03));
-                       break;
-               default:
-                       printk(KERN_ERR "UDA134X SoC codec: "
-                              "unsupported model %d\n", pd->model);
-                       return -EINVAL;
-               }
                break;
        case SND_SOC_BIAS_OFF:
                /* power off */
@@ -450,6 +415,37 @@ SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]),
 SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0),
 };
 
+/* UDA1341 has the DAC/ADC power down in STATUS1 */
+static const struct snd_soc_dapm_widget uda1341_dapm_widgets[] = {
+       SND_SOC_DAPM_DAC("DAC", "Playback", UDA134X_STATUS1, 0, 0),
+       SND_SOC_DAPM_ADC("ADC", "Capture", UDA134X_STATUS1, 1, 0),
+};
+
+/* UDA1340/4/5 has the DAC/ADC pwoer down in DATA0 11 */
+static const struct snd_soc_dapm_widget uda1340_dapm_widgets[] = {
+       SND_SOC_DAPM_DAC("DAC", "Playback", UDA134X_DATA011, 0, 0),
+       SND_SOC_DAPM_ADC("ADC", "Capture", UDA134X_DATA011, 1, 0),
+};
+
+/* Common DAPM widgets */
+static const struct snd_soc_dapm_widget uda134x_dapm_widgets[] = {
+       SND_SOC_DAPM_INPUT("VINL1"),
+       SND_SOC_DAPM_INPUT("VINR1"),
+       SND_SOC_DAPM_INPUT("VINL2"),
+       SND_SOC_DAPM_INPUT("VINR2"),
+       SND_SOC_DAPM_OUTPUT("VOUTL"),
+       SND_SOC_DAPM_OUTPUT("VOUTR"),
+};
+
+static const struct snd_soc_dapm_route uda134x_dapm_routes[] = {
+       { "ADC", NULL, "VINL1" },
+       { "ADC", NULL, "VINR1" },
+       { "ADC", NULL, "VINL2" },
+       { "ADC", NULL, "VINR2" },
+       { "VOUTL", NULL, "DAC" },
+       { "VOUTR", NULL, "DAC" },
+};
+
 static const struct snd_soc_dai_ops uda134x_dai_ops = {
        .startup        = uda134x_startup,
        .shutdown       = uda134x_shutdown,
@@ -485,6 +481,8 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec)
 {
        struct uda134x_priv *uda134x;
        struct uda134x_platform_data *pd = codec->card->dev->platform_data;
+       const struct snd_soc_dapm_widget *widgets;
+       unsigned num_widgets;
 
        int ret;
 
@@ -526,6 +524,22 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec)
        else
                uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
+       if (pd->model == UDA134X_UDA1341) {
+               widgets = uda1341_dapm_widgets;
+               num_widgets = ARRAY_SIZE(uda1341_dapm_widgets);
+       } else {
+               widgets = uda1340_dapm_widgets;
+               num_widgets = ARRAY_SIZE(uda1340_dapm_widgets);
+       }
+
+       ret = snd_soc_dapm_new_controls(&codec->dapm, widgets, num_widgets);
+       if (ret) {
+               printk(KERN_ERR "%s failed to register dapm controls: %d",
+                       __func__, ret);
+               kfree(uda134x);
+               return ret;
+       }
+
        switch (pd->model) {
        case UDA134X_UDA1340:
        case UDA134X_UDA1344:
@@ -599,6 +613,10 @@ static struct snd_soc_codec_driver soc_codec_dev_uda134x = {
        .read = uda134x_read_reg_cache,
        .write = uda134x_write,
        .set_bias_level = uda134x_set_bias_level,
+       .dapm_widgets = uda134x_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(uda134x_dapm_widgets),
+       .dapm_routes = uda134x_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(uda134x_dapm_routes),
 };
 
 static int uda134x_codec_probe(struct platform_device *pdev)
index f5e835662cdca30477738e39ffe7d57f6305db78..d5ebcb00019b7b807d9ad7e3940333c5ad2a4c4f 100644 (file)
@@ -410,39 +410,39 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_codec *codec)
                        rec->command, rec->length);
                len = rec->length + 8;
 
-               out = kzalloc(len, GFP_KERNEL);
+               xfer = kzalloc(sizeof(*xfer), GFP_KERNEL);
+               if (!xfer) {
+                       dev_err(codec->dev, "Failed to allocate xfer\n");
+                       ret = -ENOMEM;
+                       goto abort;
+               }
+
+               xfer->codec = codec;
+               list_add_tail(&xfer->list, &xfer_list);
+
+               out = kzalloc(len, GFP_KERNEL | GFP_DMA);
                if (!out) {
                        dev_err(codec->dev,
                                "Failed to allocate RX buffer\n");
                        ret = -ENOMEM;
                        goto abort1;
                }
+               xfer->t.rx_buf = out;
 
-               img = kzalloc(len, GFP_KERNEL);
+               img = kzalloc(len, GFP_KERNEL | GFP_DMA);
                if (!img) {
                        dev_err(codec->dev,
                                "Failed to allocate image buffer\n");
                        ret = -ENOMEM;
                        goto abort1;
                }
+               xfer->t.tx_buf = img;
 
                byte_swap_64((u64 *)&rec->command, img, len);
 
-               xfer = kzalloc(sizeof(*xfer), GFP_KERNEL);
-               if (!xfer) {
-                       dev_err(codec->dev, "Failed to allocate xfer\n");
-                       ret = -ENOMEM;
-                       goto abort1;
-               }
-
-               xfer->codec = codec;
-               list_add_tail(&xfer->list, &xfer_list);
-
                spi_message_init(&xfer->m);
                xfer->m.complete = wm0010_boot_xfer_complete;
                xfer->m.context = xfer;
-               xfer->t.tx_buf = img;
-               xfer->t.rx_buf = out;
                xfer->t.len = len;
                xfer->t.bits_per_word = 8;
 
@@ -523,14 +523,14 @@ static int wm0010_stage2_load(struct snd_soc_codec *codec)
        dev_dbg(codec->dev, "Downloading %zu byte stage 2 loader\n", fw->size);
 
        /* Copy to local buffer first as vmalloc causes problems for dma */
-       img = kzalloc(fw->size, GFP_KERNEL);
+       img = kzalloc(fw->size, GFP_KERNEL | GFP_DMA);
        if (!img) {
                dev_err(codec->dev, "Failed to allocate image buffer\n");
                ret = -ENOMEM;
                goto abort2;
        }
 
-       out = kzalloc(fw->size, GFP_KERNEL);
+       out = kzalloc(fw->size, GFP_KERNEL | GFP_DMA);
        if (!out) {
                dev_err(codec->dev, "Failed to allocate output buffer\n");
                ret = -ENOMEM;
@@ -670,14 +670,14 @@ static int wm0010_boot(struct snd_soc_codec *codec)
 
                ret = -ENOMEM;
                len = pll_rec.length + 8;
-               out = kzalloc(len, GFP_KERNEL);
+               out = kzalloc(len, GFP_KERNEL | GFP_DMA);
                if (!out) {
                        dev_err(codec->dev,
                                "Failed to allocate RX buffer\n");
                        goto abort;
                }
 
-               img_swap = kzalloc(len, GFP_KERNEL);
+               img_swap = kzalloc(len, GFP_KERNEL | GFP_DMA);
                if (!img_swap) {
                        dev_err(codec->dev,
                                "Failed to allocate image buffer\n");
index 282fd232cdf7cf62ce6d836578e3c518cd839d59..a6cbdb4b5c0fc85b298fbea852a3b644879995ab 100644 (file)
@@ -998,6 +998,8 @@ SND_SOC_DAPM_INPUT("IN2R"),
 SND_SOC_DAPM_INPUT("IN3L"),
 SND_SOC_DAPM_INPUT("IN3R"),
 
+SND_SOC_DAPM_OUTPUT("DRC1 Signal Activity"),
+
 SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT,
                   0, NULL, 0, arizona_in_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
@@ -1614,6 +1616,9 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = {
        { "SPKDAT1R", NULL, "OUT5R" },
 
        { "MICSUPP", NULL, "SYSCLK" },
+
+       { "DRC1 Signal Activity", NULL, "DRC1L" },
+       { "DRC1 Signal Activity", NULL, "DRC1R" },
 };
 
 static int wm5102_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
@@ -1781,6 +1786,7 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec)
                return ret;
 
        arizona_init_spk(codec);
+       arizona_init_gpio(codec);
 
        snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS");
 
index 2e7cb4ba161a5fa2a6980ec59eae33eb9c49ad18..fc410377277fa482b1f7cec4949e7545ffa511fe 100644 (file)
@@ -432,6 +432,9 @@ SND_SOC_DAPM_INPUT("IN3R"),
 SND_SOC_DAPM_INPUT("IN4L"),
 SND_SOC_DAPM_INPUT("IN4R"),
 
+SND_SOC_DAPM_OUTPUT("DRC1 Signal Activity"),
+SND_SOC_DAPM_OUTPUT("DRC2 Signal Activity"),
+
 SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT,
                   0, NULL, 0, arizona_in_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
@@ -1006,6 +1009,11 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
        { "SPKDAT2R", NULL, "OUT6R" },
 
        { "MICSUPP", NULL, "SYSCLK" },
+
+       { "DRC1 Signal Activity", NULL, "DRC1L" },
+       { "DRC1 Signal Activity", NULL, "DRC1R" },
+       { "DRC2 Signal Activity", NULL, "DRC2L" },
+       { "DRC2 Signal Activity", NULL, "DRC2R" },
 };
 
 static int wm5110_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
@@ -1170,6 +1178,7 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec)
                return ret;
 
        arizona_init_spk(codec);
+       arizona_init_gpio(codec);
 
        snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS");
 
index 0e8b3aaf6c8d698e9dad1f25fdccbabc9ee9f1ef..af1318ddb0620e8425b5606a3d794c2b57918078 100644 (file)
@@ -1301,7 +1301,8 @@ static irqreturn_t wm8350_hpl_jack_handler(int irq, void *data)
        if (device_may_wakeup(wm8350->dev))
                pm_wakeup_event(wm8350->dev, 250);
 
-       schedule_delayed_work(&priv->hpl.work, msecs_to_jiffies(200));
+       queue_delayed_work(system_power_efficient_wq,
+                          &priv->hpl.work, msecs_to_jiffies(200));
 
        return IRQ_HANDLED;
 }
@@ -1318,7 +1319,8 @@ static irqreturn_t wm8350_hpr_jack_handler(int irq, void *data)
        if (device_may_wakeup(wm8350->dev))
                pm_wakeup_event(wm8350->dev, 250);
 
-       schedule_delayed_work(&priv->hpr.work, msecs_to_jiffies(200));
+       queue_delayed_work(system_power_efficient_wq,
+                          &priv->hpr.work, msecs_to_jiffies(200));
 
        return IRQ_HANDLED;
 }
index 5276062d6c79fa59d0c2c0992a5f9b52993fa156..456bb8c6d759176a3bf31c5f7003a6e8cfc2d799 100644 (file)
@@ -45,6 +45,7 @@ static const char *wm8731_supply_names[WM8731_NUM_SUPPLIES] = {
 struct wm8731_priv {
        struct regmap *regmap;
        struct regulator_bulk_data supplies[WM8731_NUM_SUPPLIES];
+       const struct snd_pcm_hw_constraint_list *constraints;
        unsigned int sysclk;
        int sysclk_type;
        int playback_fs;
@@ -290,6 +291,36 @@ static const struct _coeff_div coeff_div[] = {
        {12000000, 88200, 136, 0xf, 0x1, 0x1},
 };
 
+/* rates constraints */
+static const unsigned int wm8731_rates_12000000[] = {
+       8000, 32000, 44100, 48000, 96000, 88200,
+};
+
+static const unsigned int wm8731_rates_12288000_18432000[] = {
+       8000, 32000, 48000, 96000,
+};
+
+static const unsigned int wm8731_rates_11289600_16934400[] = {
+       8000, 44100, 88200,
+};
+
+static const struct snd_pcm_hw_constraint_list wm8731_constraints_12000000 = {
+       .list = wm8731_rates_12000000,
+       .count = ARRAY_SIZE(wm8731_rates_12000000),
+};
+
+static const
+struct snd_pcm_hw_constraint_list wm8731_constraints_12288000_18432000 = {
+       .list = wm8731_rates_12288000_18432000,
+       .count = ARRAY_SIZE(wm8731_rates_12288000_18432000),
+};
+
+static const
+struct snd_pcm_hw_constraint_list wm8731_constraints_11289600_16934400 = {
+       .list = wm8731_rates_11289600_16934400,
+       .count = ARRAY_SIZE(wm8731_rates_11289600_16934400),
+};
+
 static inline int get_coeff(int mclk, int rate)
 {
        int i;
@@ -362,17 +393,26 @@ static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai,
        }
 
        switch (freq) {
-       case 11289600:
+       case 0:
+               wm8731->constraints = NULL;
+               break;
        case 12000000:
+               wm8731->constraints = &wm8731_constraints_12000000;
+               break;
        case 12288000:
-       case 16934400:
        case 18432000:
-               wm8731->sysclk = freq;
+               wm8731->constraints = &wm8731_constraints_12288000_18432000;
+               break;
+       case 16934400:
+       case 11289600:
+               wm8731->constraints = &wm8731_constraints_11289600_16934400;
                break;
        default:
                return -EINVAL;
        }
 
+       wm8731->sysclk = freq;
+
        snd_soc_dapm_sync(&codec->dapm);
 
        return 0;
@@ -475,12 +515,26 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
+static int wm8731_startup(struct snd_pcm_substream *substream,
+       struct snd_soc_dai *dai)
+{
+       struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(dai->codec);
+
+       if (wm8731->constraints)
+               snd_pcm_hw_constraint_list(substream->runtime, 0,
+                                          SNDRV_PCM_HW_PARAM_RATE,
+                                          wm8731->constraints);
+
+       return 0;
+}
+
 #define WM8731_RATES SNDRV_PCM_RATE_8000_96000
 
 #define WM8731_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
        SNDRV_PCM_FMTBIT_S24_LE)
 
 static const struct snd_soc_dai_ops wm8731_dai_ops = {
+       .startup        = wm8731_startup,
        .hw_params      = wm8731_hw_params,
        .digital_mute   = wm8731_mute,
        .set_sysclk     = wm8731_set_dai_sysclk,
index 0a4ab4c423d123f0bf1ce0e16ed6d261c4b5a52d..d96ebf52d953e850016184f4615f2faf979a738d 100644 (file)
@@ -1456,8 +1456,9 @@ static int wm8753_resume(struct snd_soc_codec *codec)
        if (codec->dapm.suspend_bias_level == SND_SOC_BIAS_ON) {
                wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
                codec->dapm.bias_level = SND_SOC_BIAS_ON;
-               schedule_delayed_work(&codec->dapm.delayed_work,
-                       msecs_to_jiffies(caps_charge));
+               queue_delayed_work(system_power_efficient_wq,
+                                  &codec->dapm.delayed_work,
+                                  msecs_to_jiffies(caps_charge));
        }
 
        return 0;
index fa24cedee68769f2b723e2fb8b25c03869ee286a..eebcb1da3b7b10769f0e265f95c90a6638266f71 100644 (file)
@@ -364,9 +364,7 @@ static void wm8903_seq_notifier(struct snd_soc_dapm_context *dapm,
 static int wm8903_class_w_put(struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-       struct snd_soc_codec *codec = widget->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
        struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
        u16 reg;
        int ret;
index 4c9fb142cb2d21d18ac90dd1b6e0272bf48c7e24..91dfbfeda6f81763c8afff38cc567b93b33bb218 100644 (file)
@@ -1012,7 +1012,7 @@ static const struct soc_enum liner_enum =
        SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 0, 2, out_mux_text);
 
 static const struct snd_kcontrol_new liner_mux =
-       SOC_DAPM_ENUM("LINEL Mux", liner_enum);
+       SOC_DAPM_ENUM("LINER Mux", liner_enum);
 
 static const char *sidetone_text[] = {
        "None", "Left", "Right"
index e2de9ecfd6417146dc9976f85017bd34be9aef4b..11d80f3b61372d357870b44432d5e1f1c9f6e25c 100644 (file)
@@ -2621,8 +2621,6 @@ static int wm8962_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
 
        wm8962->sysclk_rate = freq;
 
-       wm8962_configure_bclk(codec);
-
        return 0;
 }
 
@@ -3046,8 +3044,9 @@ static irqreturn_t wm8962_irq(int irq, void *data)
 
                pm_wakeup_event(dev, 300);
 
-               schedule_delayed_work(&wm8962->mic_work,
-                                     msecs_to_jiffies(250));
+               queue_delayed_work(system_power_efficient_wq,
+                                  &wm8962->mic_work,
+                                  msecs_to_jiffies(250));
        }
 
        return IRQ_HANDLED;
@@ -3175,7 +3174,7 @@ static ssize_t wm8962_beep_set(struct device *dev,
        long int time;
        int ret;
 
-       ret = strict_strtol(buf, 10, &time);
+       ret = kstrtol(buf, 10, &time);
        if (ret != 0)
                return ret;
 
index ba832b77c543af1cbdd13f2618836186c399f789..d76b056528107a0c4e9ce72e023e60312ad1d077 100644 (file)
@@ -819,8 +819,9 @@ static int clk_sys_event(struct snd_soc_dapm_widget *w,
                 * don't want false reports.
                 */
                if (wm8994->jackdet && !wm8994->clk_has_run) {
-                       schedule_delayed_work(&wm8994->jackdet_bootstrap,
-                                             msecs_to_jiffies(1000));
+                       queue_delayed_work(system_power_efficient_wq,
+                                          &wm8994->jackdet_bootstrap,
+                                          msecs_to_jiffies(1000));
                        wm8994->clk_has_run = true;
                }
                break;
@@ -1437,9 +1438,7 @@ SOC_DAPM_SINGLE("AIF1.1 Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING,
 static int wm8994_put_class_w(struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_widget *w = wlist->widgets[0];
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
        int ret;
 
        ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
@@ -3487,7 +3486,8 @@ static irqreturn_t wm8994_mic_irq(int irq, void *data)
 
        pm_wakeup_event(codec->dev, 300);
 
-       schedule_delayed_work(&priv->mic_work, msecs_to_jiffies(250));
+       queue_delayed_work(system_power_efficient_wq,
+                          &priv->mic_work, msecs_to_jiffies(250));
 
        return IRQ_HANDLED;
 }
@@ -3575,8 +3575,9 @@ static void wm8958_mic_id(void *data, u16 status)
                /* If nothing present then clear our statuses */
                dev_dbg(codec->dev, "Detected open circuit\n");
 
-               schedule_delayed_work(&wm8994->open_circuit_work,
-                                     msecs_to_jiffies(2500));
+               queue_delayed_work(system_power_efficient_wq,
+                                  &wm8994->open_circuit_work,
+                                  msecs_to_jiffies(2500));
                return;
        }
 
@@ -3690,8 +3691,9 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
                                    WM1811_JACKDET_DB, 0);
 
                delay = control->pdata.micdet_delay;
-               schedule_delayed_work(&wm8994->mic_work,
-                                     msecs_to_jiffies(delay));
+               queue_delayed_work(system_power_efficient_wq,
+                                  &wm8994->mic_work,
+                                  msecs_to_jiffies(delay));
        } else {
                dev_dbg(codec->dev, "Jack not detected\n");
 
@@ -3936,8 +3938,9 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
        id_delay = wm8994->wm8994->pdata.mic_id_delay;
 
        if (wm8994->mic_detecting)
-               schedule_delayed_work(&wm8994->mic_complete_work,
-                                     msecs_to_jiffies(id_delay));
+               queue_delayed_work(system_power_efficient_wq,
+                                  &wm8994->mic_complete_work,
+                                  msecs_to_jiffies(id_delay));
        else
                wm8958_button_det(codec, reg);
 
@@ -4010,9 +4013,6 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 
        wm8994->micdet_irq = control->pdata.micdet_irq;
 
-       pm_runtime_enable(codec->dev);
-       pm_runtime_idle(codec->dev);
-
        /* By default use idle_bias_off, will override for WM8994 */
        codec->dapm.idle_bias_off = 1;
 
@@ -4385,8 +4385,6 @@ static int wm8994_codec_remove(struct snd_soc_codec *codec)
 
        wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
-       pm_runtime_disable(codec->dev);
-
        for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++)
                wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_FLL1_LOCK + i,
                                &wm8994->fll_locked[i]);
@@ -4445,6 +4443,9 @@ static int wm8994_probe(struct platform_device *pdev)
 
        wm8994->wm8994 = dev_get_drvdata(pdev->dev.parent);
 
+       pm_runtime_enable(&pdev->dev);
+       pm_runtime_idle(&pdev->dev);
+
        return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8994,
                        wm8994_dai, ARRAY_SIZE(wm8994_dai));
 }
@@ -4452,6 +4453,8 @@ static int wm8994_probe(struct platform_device *pdev)
 static int wm8994_remove(struct platform_device *pdev)
 {
        snd_soc_unregister_codec(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+
        return 0;
 }
 
index 90a65c427541fb9290616379f7b53bc17c01d0ea..da2899e6c4018fae6cd0a2411b58027f4048b6e4 100644 (file)
@@ -549,12 +549,9 @@ static int check_clk_sys(struct snd_soc_dapm_widget *source,
 static int wm8995_put_class_w(struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_widget *w = wlist->widgets[0];
-       struct snd_soc_codec *codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
        int ret;
 
-       codec = w->codec;
        ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
        wm8995_update_class_w(codec);
        return ret;
index 05252ac936a369cb210a9043105d9d95cb614679..b38f3506418ff0d43dc927fe45424e3d9d998d75 100644 (file)
@@ -225,15 +225,8 @@ struct wm_coeff_ctl_ops {
                     struct snd_ctl_elem_info *uinfo);
 };
 
-struct wm_coeff {
-       struct device *dev;
-       struct list_head ctl_list;
-       struct regmap *regmap;
-};
-
 struct wm_coeff_ctl {
        const char *name;
-       struct snd_card *card;
        struct wm_adsp_alg_region region;
        struct wm_coeff_ctl_ops ops;
        struct wm_adsp *adsp;
@@ -378,7 +371,6 @@ static int wm_coeff_info(struct snd_kcontrol *kcontrol,
 static int wm_coeff_write_control(struct snd_kcontrol *kcontrol,
                                  const void *buf, size_t len)
 {
-       struct wm_coeff *wm_coeff= snd_kcontrol_chip(kcontrol);
        struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
        struct wm_adsp_alg_region *region = &ctl->region;
        const struct wm_adsp_region *mem;
@@ -401,7 +393,7 @@ static int wm_coeff_write_control(struct snd_kcontrol *kcontrol,
        if (!scratch)
                return -ENOMEM;
 
-       ret = regmap_raw_write(wm_coeff->regmap, reg, scratch,
+       ret = regmap_raw_write(adsp->regmap, reg, scratch,
                               ctl->len);
        if (ret) {
                adsp_err(adsp, "Failed to write %zu bytes to %x\n",
@@ -434,7 +426,6 @@ static int wm_coeff_put(struct snd_kcontrol *kcontrol,
 static int wm_coeff_read_control(struct snd_kcontrol *kcontrol,
                                 void *buf, size_t len)
 {
-       struct wm_coeff *wm_coeff= snd_kcontrol_chip(kcontrol);
        struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
        struct wm_adsp_alg_region *region = &ctl->region;
        const struct wm_adsp_region *mem;
@@ -457,7 +448,7 @@ static int wm_coeff_read_control(struct snd_kcontrol *kcontrol,
        if (!scratch)
                return -ENOMEM;
 
-       ret = regmap_raw_read(wm_coeff->regmap, reg, scratch, ctl->len);
+       ret = regmap_raw_read(adsp->regmap, reg, scratch, ctl->len);
        if (ret) {
                adsp_err(adsp, "Failed to read %zu bytes from %x\n",
                         ctl->len, reg);
@@ -481,37 +472,18 @@ static int wm_coeff_get(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
-static int wm_coeff_add_kcontrol(struct wm_coeff *wm_coeff,
-                                struct wm_coeff_ctl *ctl,
-                                const struct snd_kcontrol_new *kctl)
-{
-       int ret;
-       struct snd_kcontrol *kcontrol;
-
-       kcontrol = snd_ctl_new1(kctl, wm_coeff);
-       ret = snd_ctl_add(ctl->card, kcontrol);
-       if (ret < 0) {
-               dev_err(wm_coeff->dev, "Failed to add %s: %d\n",
-                       kctl->name, ret);
-               return ret;
-       }
-       ctl->kcontrol = kcontrol;
-       return 0;
-}
-
 struct wmfw_ctl_work {
-       struct wm_coeff *wm_coeff;
+       struct wm_adsp *adsp;
        struct wm_coeff_ctl *ctl;
        struct work_struct work;
 };
 
-static int wmfw_add_ctl(struct wm_coeff *wm_coeff,
-                       struct wm_coeff_ctl *ctl)
+static int wmfw_add_ctl(struct wm_adsp *adsp, struct wm_coeff_ctl *ctl)
 {
        struct snd_kcontrol_new *kcontrol;
        int ret;
 
-       if (!wm_coeff || !ctl || !ctl->name || !ctl->card)
+       if (!ctl || !ctl->name)
                return -EINVAL;
 
        kcontrol = kzalloc(sizeof(*kcontrol), GFP_KERNEL);
@@ -525,14 +497,17 @@ static int wmfw_add_ctl(struct wm_coeff *wm_coeff,
        kcontrol->put = wm_coeff_put;
        kcontrol->private_value = (unsigned long)ctl;
 
-       ret = wm_coeff_add_kcontrol(wm_coeff,
-                                   ctl, kcontrol);
+       ret = snd_soc_add_card_controls(adsp->card,
+                                       kcontrol, 1);
        if (ret < 0)
                goto err_kcontrol;
 
        kfree(kcontrol);
 
-       list_add(&ctl->list, &wm_coeff->ctl_list);
+       ctl->kcontrol = snd_soc_card_get_kcontrol(adsp->card,
+                                                 ctl->name);
+
+       list_add(&ctl->list, &adsp->ctl_list);
        return 0;
 
 err_kcontrol:
@@ -753,13 +728,12 @@ out:
        return ret;
 }
 
-static int wm_coeff_init_control_caches(struct wm_coeff *wm_coeff)
+static int wm_coeff_init_control_caches(struct wm_adsp *adsp)
 {
        struct wm_coeff_ctl *ctl;
        int ret;
 
-       list_for_each_entry(ctl, &wm_coeff->ctl_list,
-                           list) {
+       list_for_each_entry(ctl, &adsp->ctl_list, list) {
                if (!ctl->enabled || ctl->set)
                        continue;
                ret = wm_coeff_read_control(ctl->kcontrol,
@@ -772,13 +746,12 @@ static int wm_coeff_init_control_caches(struct wm_coeff *wm_coeff)
        return 0;
 }
 
-static int wm_coeff_sync_controls(struct wm_coeff *wm_coeff)
+static int wm_coeff_sync_controls(struct wm_adsp *adsp)
 {
        struct wm_coeff_ctl *ctl;
        int ret;
 
-       list_for_each_entry(ctl, &wm_coeff->ctl_list,
-                           list) {
+       list_for_each_entry(ctl, &adsp->ctl_list, list) {
                if (!ctl->enabled)
                        continue;
                if (ctl->set) {
@@ -799,15 +772,14 @@ static void wm_adsp_ctl_work(struct work_struct *work)
                                                      struct wmfw_ctl_work,
                                                      work);
 
-       wmfw_add_ctl(ctl_work->wm_coeff, ctl_work->ctl);
+       wmfw_add_ctl(ctl_work->adsp, ctl_work->ctl);
        kfree(ctl_work);
 }
 
-static int wm_adsp_create_control(struct snd_soc_codec *codec,
+static int wm_adsp_create_control(struct wm_adsp *dsp,
                                  const struct wm_adsp_alg_region *region)
 
 {
-       struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
        struct wm_coeff_ctl *ctl;
        struct wmfw_ctl_work *ctl_work;
        char *name;
@@ -842,7 +814,7 @@ static int wm_adsp_create_control(struct snd_soc_codec *codec,
        snprintf(name, PAGE_SIZE, "DSP%d %s %x",
                 dsp->num, region_name, region->alg);
 
-       list_for_each_entry(ctl, &dsp->wm_coeff->ctl_list,
+       list_for_each_entry(ctl, &dsp->ctl_list,
                            list) {
                if (!strcmp(ctl->name, name)) {
                        if (!ctl->enabled)
@@ -866,7 +838,6 @@ static int wm_adsp_create_control(struct snd_soc_codec *codec,
        ctl->set = 0;
        ctl->ops.xget = wm_coeff_get;
        ctl->ops.xput = wm_coeff_put;
-       ctl->card = codec->card->snd_card;
        ctl->adsp = dsp;
 
        ctl->len = region->len;
@@ -882,7 +853,7 @@ static int wm_adsp_create_control(struct snd_soc_codec *codec,
                goto err_ctl_cache;
        }
 
-       ctl_work->wm_coeff = dsp->wm_coeff;
+       ctl_work->adsp = dsp;
        ctl_work->ctl = ctl;
        INIT_WORK(&ctl_work->work, wm_adsp_ctl_work);
        schedule_work(&ctl_work->work);
@@ -903,7 +874,7 @@ err_name:
        return ret;
 }
 
-static int wm_adsp_setup_algs(struct wm_adsp *dsp, struct snd_soc_codec *codec)
+static int wm_adsp_setup_algs(struct wm_adsp *dsp)
 {
        struct regmap *regmap = dsp->regmap;
        struct wmfw_adsp1_id_hdr adsp1_id;
@@ -1091,7 +1062,7 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp, struct snd_soc_codec *codec)
                        if (i + 1 < algs) {
                                region->len = be32_to_cpu(adsp1_alg[i + 1].dm);
                                region->len -= be32_to_cpu(adsp1_alg[i].dm);
-                               wm_adsp_create_control(codec, region);
+                               wm_adsp_create_control(dsp, region);
                        } else {
                                adsp_warn(dsp, "Missing length info for region DM with ID %x\n",
                                          be32_to_cpu(adsp1_alg[i].alg.id));
@@ -1108,7 +1079,7 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp, struct snd_soc_codec *codec)
                        if (i + 1 < algs) {
                                region->len = be32_to_cpu(adsp1_alg[i + 1].zm);
                                region->len -= be32_to_cpu(adsp1_alg[i].zm);
-                               wm_adsp_create_control(codec, region);
+                               wm_adsp_create_control(dsp, region);
                        } else {
                                adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
                                          be32_to_cpu(adsp1_alg[i].alg.id));
@@ -1137,7 +1108,7 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp, struct snd_soc_codec *codec)
                        if (i + 1 < algs) {
                                region->len = be32_to_cpu(adsp2_alg[i + 1].xm);
                                region->len -= be32_to_cpu(adsp2_alg[i].xm);
-                               wm_adsp_create_control(codec, region);
+                               wm_adsp_create_control(dsp, region);
                        } else {
                                adsp_warn(dsp, "Missing length info for region XM with ID %x\n",
                                          be32_to_cpu(adsp2_alg[i].alg.id));
@@ -1154,7 +1125,7 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp, struct snd_soc_codec *codec)
                        if (i + 1 < algs) {
                                region->len = be32_to_cpu(adsp2_alg[i + 1].ym);
                                region->len -= be32_to_cpu(adsp2_alg[i].ym);
-                               wm_adsp_create_control(codec, region);
+                               wm_adsp_create_control(dsp, region);
                        } else {
                                adsp_warn(dsp, "Missing length info for region YM with ID %x\n",
                                          be32_to_cpu(adsp2_alg[i].alg.id));
@@ -1171,7 +1142,7 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp, struct snd_soc_codec *codec)
                        if (i + 1 < algs) {
                                region->len = be32_to_cpu(adsp2_alg[i + 1].zm);
                                region->len -= be32_to_cpu(adsp2_alg[i].zm);
-                               wm_adsp_create_control(codec, region);
+                               wm_adsp_create_control(dsp, region);
                        } else {
                                adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
                                          be32_to_cpu(adsp2_alg[i].alg.id));
@@ -1391,6 +1362,8 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
        int ret;
        int val;
 
+       dsp->card = codec->card;
+
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
                regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
@@ -1425,7 +1398,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
                if (ret != 0)
                        goto err;
 
-               ret = wm_adsp_setup_algs(dsp, codec);
+               ret = wm_adsp_setup_algs(dsp);
                if (ret != 0)
                        goto err;
 
@@ -1434,12 +1407,12 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
                        goto err;
 
                /* Initialize caches for enabled and unset controls */
-               ret = wm_coeff_init_control_caches(dsp->wm_coeff);
+               ret = wm_coeff_init_control_caches(dsp);
                if (ret != 0)
                        goto err;
 
                /* Sync set controls */
-               ret = wm_coeff_sync_controls(dsp->wm_coeff);
+               ret = wm_coeff_sync_controls(dsp);
                if (ret != 0)
                        goto err;
 
@@ -1460,10 +1433,8 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
                regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
                                   ADSP1_SYS_ENA, 0);
 
-               list_for_each_entry(ctl, &dsp->wm_coeff->ctl_list,
-                                   list) {
+               list_for_each_entry(ctl, &dsp->ctl_list, list)
                        ctl->enabled = 0;
-               }
                break;
 
        default:
@@ -1520,6 +1491,8 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
        unsigned int val;
        int ret;
 
+       dsp->card = codec->card;
+
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
                /*
@@ -1582,7 +1555,7 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
                if (ret != 0)
                        goto err;
 
-               ret = wm_adsp_setup_algs(dsp, codec);
+               ret = wm_adsp_setup_algs(dsp);
                if (ret != 0)
                        goto err;
 
@@ -1591,12 +1564,12 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
                        goto err;
 
                /* Initialize caches for enabled and unset controls */
-               ret = wm_coeff_init_control_caches(dsp->wm_coeff);
+               ret = wm_coeff_init_control_caches(dsp);
                if (ret != 0)
                        goto err;
 
                /* Sync set controls */
-               ret = wm_coeff_sync_controls(dsp->wm_coeff);
+               ret = wm_coeff_sync_controls(dsp);
                if (ret != 0)
                        goto err;
 
@@ -1637,10 +1610,8 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
                                        ret);
                }
 
-               list_for_each_entry(ctl, &dsp->wm_coeff->ctl_list,
-                                   list) {
+               list_for_each_entry(ctl, &dsp->ctl_list, list)
                        ctl->enabled = 0;
-               }
 
                while (!list_empty(&dsp->alg_regions)) {
                        alg_region = list_first_entry(&dsp->alg_regions,
@@ -1679,49 +1650,38 @@ int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs)
        }
 
        INIT_LIST_HEAD(&adsp->alg_regions);
-
-       adsp->wm_coeff = kzalloc(sizeof(*adsp->wm_coeff),
-                                GFP_KERNEL);
-       if (!adsp->wm_coeff)
-               return -ENOMEM;
-       adsp->wm_coeff->regmap = adsp->regmap;
-       adsp->wm_coeff->dev = adsp->dev;
-       INIT_LIST_HEAD(&adsp->wm_coeff->ctl_list);
+       INIT_LIST_HEAD(&adsp->ctl_list);
 
        if (dvfs) {
                adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD");
                if (IS_ERR(adsp->dvfs)) {
                        ret = PTR_ERR(adsp->dvfs);
                        dev_err(adsp->dev, "Failed to get DCVDD: %d\n", ret);
-                       goto out_coeff;
+                       return ret;
                }
 
                ret = regulator_enable(adsp->dvfs);
                if (ret != 0) {
                        dev_err(adsp->dev, "Failed to enable DCVDD: %d\n",
                                ret);
-                       goto out_coeff;
+                       return ret;
                }
 
                ret = regulator_set_voltage(adsp->dvfs, 1200000, 1800000);
                if (ret != 0) {
                        dev_err(adsp->dev, "Failed to initialise DVFS: %d\n",
                                ret);
-                       goto out_coeff;
+                       return ret;
                }
 
                ret = regulator_disable(adsp->dvfs);
                if (ret != 0) {
                        dev_err(adsp->dev, "Failed to disable DCVDD: %d\n",
                                ret);
-                       goto out_coeff;
+                       return ret;
                }
        }
 
        return 0;
-
-out_coeff:
-       kfree(adsp->wm_coeff);
-       return ret;
 }
 EXPORT_SYMBOL_GPL(wm_adsp2_init);
index 9f922c82536c52f8939db5834bbcfda80e1c5b59..d018dea6254de44c5997813fcb9b958eeca09706 100644 (file)
@@ -39,6 +39,7 @@ struct wm_adsp {
        int type;
        struct device *dev;
        struct regmap *regmap;
+       struct snd_soc_card *card;
 
        int base;
        int sysclk_reg;
@@ -57,7 +58,7 @@ struct wm_adsp {
 
        struct regulator *dvfs;
 
-       struct wm_coeff *wm_coeff;
+       struct list_head ctl_list;
 };
 
 #define WM_ADSP1(wname, num) \
index 2d9e099415a58cbe353c99f32f6f089a200db2de..8b50e5958de5a43030ac854d18c046cf903e5841 100644 (file)
@@ -699,9 +699,7 @@ EXPORT_SYMBOL_GPL(wm_hubs_update_class_w);
 static int class_w_put_volsw(struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-       struct snd_soc_codec *codec = widget->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
        int ret;
 
        ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
@@ -721,9 +719,7 @@ static int class_w_put_volsw(struct snd_kcontrol *kcontrol,
 static int class_w_put_double(struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-       struct snd_soc_codec *codec = widget->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
        int ret;
 
        ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
index aa438546c91271f69c26beb1646b85f4b34357cf..c26449b54270e50f04c3550db8d7aecbe817bd4a 100644 (file)
@@ -98,7 +98,7 @@ endif # SND_POWERPC_SOC
 
 menuconfig SND_IMX_SOC
        tristate "SoC Audio for Freescale i.MX CPUs"
-       depends on ARCH_MXC
+       depends on ARCH_MXC || COMPILE_TEST
        help
          Say Y or M if you want to add support for codecs attached to
          the i.MX CPUs.
@@ -109,11 +109,11 @@ config SND_SOC_IMX_SSI
        tristate
 
 config SND_SOC_IMX_PCM_FIQ
-       bool
+       tristate
        select FIQ
 
 config SND_SOC_IMX_PCM_DMA
-       bool
+       tristate
        select SND_SOC_GENERIC_DMAENGINE_PCM
 
 config SND_SOC_IMX_AUDMUX
@@ -194,7 +194,7 @@ config SND_SOC_IMX_SGTL5000
 
 config SND_SOC_IMX_MC13783
        tristate "SoC Audio support for I.MX boards with mc13783"
-       depends on MFD_MC13783
+       depends on MFD_MC13783 && ARCH_ARM
        select SND_SOC_IMX_SSI
        select SND_SOC_IMX_AUDMUX
        select SND_SOC_MC13783
index 2f2d837df07f078e5b60da38308cbdb8d53b9969..4d78df7d7f3491fa5d2d187a1df9ee6d53510d82 100644 (file)
@@ -36,7 +36,7 @@
 #define read_ssi(addr)                  in_be32(addr)
 #define write_ssi(val, addr)            out_be32(addr, val)
 #define write_ssi_mask(addr, clear, set) clrsetbits_be32(addr, clear, set)
-#elif defined ARM
+#else
 #define read_ssi(addr)                  readl(addr)
 #define write_ssi(val, addr)            writel(val, addr)
 /*
@@ -510,6 +510,9 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
                        write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_TE, 0);
                else
                        write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_RE, 0);
+
+               if ((read_ssi(&ssi->scr) & (CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE)) == 0)
+                       write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0);
                break;
 
        default:
@@ -534,15 +537,6 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
                ssi_private->first_stream = ssi_private->second_stream;
 
        ssi_private->second_stream = NULL;
-
-       /*
-        * If this is the last active substream, disable the SSI.
-        */
-       if (!ssi_private->first_stream) {
-               struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
-
-               write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0);
-       }
 }
 
 static int fsl_ssi_dai_probe(struct snd_soc_dai *dai)
@@ -680,7 +674,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
 
        /* The DAI name is the last part of the full name of the node. */
        p = strrchr(np->full_name, '/') + 1;
-       ssi_private = kzalloc(sizeof(struct fsl_ssi_private) + strlen(p),
+       ssi_private = devm_kzalloc(&pdev->dev, sizeof(*ssi_private) + strlen(p),
                              GFP_KERNEL);
        if (!ssi_private) {
                dev_err(&pdev->dev, "could not allocate DAI object\n");
@@ -698,26 +692,24 @@ static int fsl_ssi_probe(struct platform_device *pdev)
        ret = of_address_to_resource(np, 0, &res);
        if (ret) {
                dev_err(&pdev->dev, "could not determine device resources\n");
-               goto error_kmalloc;
+               return ret;
        }
        ssi_private->ssi = of_iomap(np, 0);
        if (!ssi_private->ssi) {
                dev_err(&pdev->dev, "could not map device resources\n");
-               ret = -ENOMEM;
-               goto error_kmalloc;
+               return -ENOMEM;
        }
        ssi_private->ssi_phys = res.start;
 
        ssi_private->irq = irq_of_parse_and_map(np, 0);
        if (ssi_private->irq == NO_IRQ) {
                dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
-               ret = -ENXIO;
-               goto error_iomap;
+               return -ENXIO;
        }
 
        /* The 'name' should not have any slashes in it. */
-       ret = request_irq(ssi_private->irq, fsl_ssi_isr, 0, ssi_private->name,
-                         ssi_private);
+       ret = devm_request_irq(&pdev->dev, ssi_private->irq, fsl_ssi_isr, 0,
+                              ssi_private->name, ssi_private);
        if (ret < 0) {
                dev_err(&pdev->dev, "could not claim irq %u\n", ssi_private->irq);
                goto error_irqmap;
@@ -739,13 +731,18 @@ static int fsl_ssi_probe(struct platform_device *pdev)
                u32 dma_events[2];
                ssi_private->ssi_on_imx = true;
 
-               ssi_private->clk = clk_get(&pdev->dev, NULL);
+               ssi_private->clk = devm_clk_get(&pdev->dev, NULL);
                if (IS_ERR(ssi_private->clk)) {
                        ret = PTR_ERR(ssi_private->clk);
                        dev_err(&pdev->dev, "could not get clock: %d\n", ret);
-                       goto error_irq;
+                       goto error_irqmap;
+               }
+               ret = clk_prepare_enable(ssi_private->clk);
+               if (ret) {
+                       dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n",
+                               ret);
+                       goto error_irqmap;
                }
-               clk_prepare_enable(ssi_private->clk);
 
                /*
                 * We have burstsize be "fifo_depth - 2" to match the SSI
@@ -778,9 +775,9 @@ static int fsl_ssi_probe(struct platform_device *pdev)
                            "fsl,spba-bus");
 
                imx_pcm_dma_params_init_data(&ssi_private->filter_data_tx,
-                       dma_events[0], shared);
+                       dma_events[0], shared ? IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI);
                imx_pcm_dma_params_init_data(&ssi_private->filter_data_rx,
-                       dma_events[1], shared);
+                       dma_events[1], shared ? IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI);
        }
 
        /* Initialize the the device_attribute structure */
@@ -794,7 +791,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
        if (ret) {
                dev_err(&pdev->dev, "could not create sysfs %s file\n",
                        ssi_private->dev_attr.attr.name);
-               goto error_irq;
+               goto error_clk;
        }
 
        /* Register with ASoC */
@@ -857,23 +854,12 @@ error_dev:
        device_remove_file(&pdev->dev, dev_attr);
 
 error_clk:
-       if (ssi_private->ssi_on_imx) {
+       if (ssi_private->ssi_on_imx)
                clk_disable_unprepare(ssi_private->clk);
-               clk_put(ssi_private->clk);
-       }
-
-error_irq:
-       free_irq(ssi_private->irq, ssi_private);
 
 error_irqmap:
        irq_dispose_mapping(ssi_private->irq);
 
-error_iomap:
-       iounmap(ssi_private->ssi);
-
-error_kmalloc:
-       kfree(ssi_private);
-
        return ret;
 }
 
@@ -886,15 +872,10 @@ static int fsl_ssi_remove(struct platform_device *pdev)
        if (ssi_private->ssi_on_imx) {
                imx_pcm_dma_exit(pdev);
                clk_disable_unprepare(ssi_private->clk);
-               clk_put(ssi_private->clk);
        }
        snd_soc_unregister_component(&pdev->dev);
        device_remove_file(&pdev->dev, &ssi_private->dev_attr);
-
-       free_irq(ssi_private->irq, ssi_private);
        irq_dispose_mapping(ssi_private->irq);
-
-       kfree(ssi_private);
        dev_set_drvdata(&pdev->dev, NULL);
 
        return 0;
@@ -919,6 +900,7 @@ static struct platform_driver fsl_ssi_driver = {
 
 module_platform_driver(fsl_ssi_driver);
 
+MODULE_ALIAS("platform:fsl-ssi-dai");
 MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
 MODULE_DESCRIPTION("Freescale Synchronous Serial Interface (SSI) ASoC Driver");
 MODULE_LICENSE("GPL v2");
index e260f1f899dbb132135cb6745376f5dad8891fb9..1a5da1e13077f85986052cac2ba41004a31d0020 100644 (file)
@@ -73,8 +73,11 @@ static ssize_t audmux_read_file(struct file *file, char __user *user_buf,
        if (!buf)
                return -ENOMEM;
 
-       if (audmux_clk)
-               clk_prepare_enable(audmux_clk);
+       if (audmux_clk) {
+               ret = clk_prepare_enable(audmux_clk);
+               if (ret)
+                       return ret;
+       }
 
        ptcr = readl(audmux_base + IMX_AUDMUX_V2_PTCR(port));
        pdcr = readl(audmux_base + IMX_AUDMUX_V2_PDCR(port));
@@ -224,14 +227,19 @@ EXPORT_SYMBOL_GPL(imx_audmux_v1_configure_port);
 int imx_audmux_v2_configure_port(unsigned int port, unsigned int ptcr,
                unsigned int pdcr)
 {
+       int ret;
+
        if (audmux_type != IMX31_AUDMUX)
                return -EINVAL;
 
        if (!audmux_base)
                return -ENOSYS;
 
-       if (audmux_clk)
-               clk_prepare_enable(audmux_clk);
+       if (audmux_clk) {
+               ret = clk_prepare_enable(audmux_clk);
+               if (ret)
+                       return ret;
+       }
 
        writel(ptcr, audmux_base + IMX_AUDMUX_V2_PTCR(port));
        writel(pdcr, audmux_base + IMX_AUDMUX_V2_PDCR(port));
index 9df173c091a66b4fbb676036b9a66cacfe2eff17..a3d60d4bea4ce8ace84d2860921b5c46d3f00895 100644 (file)
@@ -90,6 +90,7 @@ static const struct snd_soc_dapm_route imx_mc13783_routes[] = {
 
 static struct snd_soc_card imx_mc13783 = {
        .name           = "imx_mc13783",
+       .owner          = THIS_MODULE,
        .dai_link       = imx_mc13783_dai_mc13783,
        .num_links      = ARRAY_SIZE(imx_mc13783_dai_mc13783),
        .dapm_widgets   = imx_mc13783_widget,
index fde4d2ea68c88afb32275963ae0b51e81be9112a..f323ce09f881d76e762c73391c7724354b5d82b1 100644 (file)
@@ -64,7 +64,6 @@ int imx_pcm_dma_init(struct platform_device *pdev)
 {
        return snd_dmaengine_pcm_register(&pdev->dev, &imx_dmaengine_pcm_config,
                SND_DMAENGINE_PCM_FLAG_NO_RESIDUE |
-               SND_DMAENGINE_PCM_FLAG_NO_DT |
                SND_DMAENGINE_PCM_FLAG_COMPAT);
 }
 EXPORT_SYMBOL_GPL(imx_pcm_dma_init);
index 310d90290320c751b572f2a409f8c4800f6c60b2..3b2ba994beeef321dea1d002d5494b4b2d690950 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/slab.h>
 
 #include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
 #include <sound/initval.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -32,6 +33,7 @@
 #include <linux/platform_data/asoc-imx-ssi.h>
 
 #include "imx-ssi.h"
+#include "imx-pcm.h"
 
 struct imx_pcm_runtime_data {
        unsigned int period;
@@ -366,9 +368,9 @@ static struct snd_soc_platform_driver imx_soc_platform_fiq = {
        .pcm_free       = imx_pcm_fiq_free,
 };
 
-int imx_pcm_fiq_init(struct platform_device *pdev)
+int imx_pcm_fiq_init(struct platform_device *pdev,
+               struct imx_pcm_fiq_params *params)
 {
-       struct imx_ssi *ssi = platform_get_drvdata(pdev);
        int ret;
 
        ret = claim_fiq(&fh);
@@ -377,15 +379,15 @@ int imx_pcm_fiq_init(struct platform_device *pdev)
                return ret;
        }
 
-       mxc_set_irq_fiq(ssi->irq, 1);
-       ssi_irq = ssi->irq;
+       mxc_set_irq_fiq(params->irq, 1);
+       ssi_irq = params->irq;
 
-       imx_pcm_fiq = ssi->irq;
+       imx_pcm_fiq = params->irq;
 
-       imx_ssi_fiq_base = (unsigned long)ssi->base;
+       imx_ssi_fiq_base = (unsigned long)params->base;
 
-       ssi->dma_params_tx.maxburst = 4;
-       ssi->dma_params_rx.maxburst = 6;
+       params->dma_params_tx->maxburst = 4;
+       params->dma_params_rx->maxburst = 6;
 
        ret = snd_soc_register_platform(&pdev->dev, &imx_soc_platform_fiq);
        if (ret)
index 67f656c7c320744334d4ca5d8233d36eacbe6d4d..5d5b73303e1169b7f6c2254e06d66a87409050cc 100644 (file)
 
 static inline void
 imx_pcm_dma_params_init_data(struct imx_dma_data *dma_data,
-       int dma, bool shared)
+       int dma, enum sdma_peripheral_type peripheral_type)
 {
        dma_data->dma_request = dma;
        dma_data->priority = DMA_PRIO_HIGH;
-       if (shared)
-               dma_data->peripheral_type = IMX_DMATYPE_SSI_SP;
-       else
-               dma_data->peripheral_type = IMX_DMATYPE_SSI;
+       dma_data->peripheral_type = peripheral_type;
 }
 
-#ifdef CONFIG_SND_SOC_IMX_PCM_DMA
+struct imx_pcm_fiq_params {
+       int irq;
+       void __iomem *base;
+
+       /* Pointer to original ssi driver to setup tx rx sizes */
+       struct snd_dmaengine_dai_dma_data *dma_params_rx;
+       struct snd_dmaengine_dai_dma_data *dma_params_tx;
+};
+
+#if IS_ENABLED(CONFIG_SND_SOC_IMX_PCM_DMA)
 int imx_pcm_dma_init(struct platform_device *pdev);
 void imx_pcm_dma_exit(struct platform_device *pdev);
 #else
@@ -46,11 +52,13 @@ static inline void imx_pcm_dma_exit(struct platform_device *pdev)
 }
 #endif
 
-#ifdef CONFIG_SND_SOC_IMX_PCM_FIQ
-int imx_pcm_fiq_init(struct platform_device *pdev);
+#if IS_ENABLED(CONFIG_SND_SOC_IMX_PCM_FIQ)
+int imx_pcm_fiq_init(struct platform_device *pdev,
+               struct imx_pcm_fiq_params *params);
 void imx_pcm_fiq_exit(struct platform_device *pdev);
 #else
-static inline int imx_pcm_fiq_init(struct platform_device *pdev)
+static inline int imx_pcm_fiq_init(struct platform_device *pdev,
+               struct imx_pcm_fiq_params *params)
 {
        return -ENODEV;
 }
index 3f726e4f88db8c2900840819e5d86ede5e9415d1..389cbfa6dca79d6100b34e64f57d6bc2514d20f8 100644 (file)
@@ -129,8 +129,10 @@ static int imx_sgtl5000_probe(struct platform_device *pdev)
        }
 
        data->codec_clk = devm_clk_get(&codec_dev->dev, NULL);
-       if (IS_ERR(data->codec_clk))
+       if (IS_ERR(data->codec_clk)) {
+               ret = PTR_ERR(data->codec_clk);
                goto fail;
+       }
 
        data->clk_frequency = clk_get_rate(data->codec_clk);
 
index 51be3772cba901bc17d245ab0077ec744fcf64b2..f58bcd85c07fbd8b302c0c3bcd97fd3cf6ed4d0c 100644 (file)
@@ -571,13 +571,13 @@ static int imx_ssi_probe(struct platform_device *pdev)
        res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx0");
        if (res) {
                imx_pcm_dma_params_init_data(&ssi->filter_data_tx, res->start,
-                       false);
+                       IMX_DMATYPE_SSI);
        }
 
        res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx0");
        if (res) {
                imx_pcm_dma_params_init_data(&ssi->filter_data_rx, res->start,
-                       false);
+                       IMX_DMATYPE_SSI);
        }
 
        platform_set_drvdata(pdev, ssi);
@@ -595,7 +595,12 @@ static int imx_ssi_probe(struct platform_device *pdev)
                goto failed_register;
        }
 
-       ret = imx_pcm_fiq_init(pdev);
+       ssi->fiq_params.irq = ssi->irq;
+       ssi->fiq_params.base = ssi->base;
+       ssi->fiq_params.dma_params_rx = &ssi->dma_params_rx;
+       ssi->fiq_params.dma_params_tx = &ssi->dma_params_tx;
+
+       ret = imx_pcm_fiq_init(pdev, &ssi->fiq_params);
        if (ret)
                goto failed_pcm_fiq;
 
index d5003cefca8decee028d937a9a9a975bb703102d..fb1616ba8c5967e1892b4ff6c7e180b2b9447047 100644 (file)
@@ -209,6 +209,7 @@ struct imx_ssi {
        struct snd_dmaengine_dai_dma_data dma_params_tx;
        struct imx_dma_data filter_data_tx;
        struct imx_dma_data filter_data_rx;
+       struct imx_pcm_fiq_params fiq_params;
 
        int enabled;
 };
index 52a36a90f4f4eb19c4739fda1714f48e715d1c68..1d70e278e9154e7f21d1ba230b4f573ad5b31f95 100644 (file)
@@ -217,7 +217,8 @@ static int imx_wm8962_probe(struct platform_device *pdev)
        codec_dev = of_find_i2c_device_by_node(codec_np);
        if (!codec_dev || !codec_dev->driver) {
                dev_err(&pdev->dev, "failed to find codec platform device\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto fail;
        }
 
        data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
index c62d715235e29ac5fa20639271d79958a57fd853..59085ad6c41a3ca51c39e841a4f3cd8b8a2598e1 100644 (file)
@@ -1,6 +1,6 @@
 config SND_KIRKWOOD_SOC
        tristate "SoC Audio for the Marvell Kirkwood chip"
-       depends on ARCH_KIRKWOOD
+       depends on ARCH_KIRKWOOD || COMPILE_TEST
        help
          Say Y or M if you want to add support for codecs attached to
          the Kirkwood I2S interface. You will also need to select the
@@ -11,7 +11,7 @@ config SND_KIRKWOOD_SOC_I2S
 
 config SND_KIRKWOOD_SOC_OPENRD
        tristate "SoC Audio support for Kirkwood Openrd Client"
-       depends on SND_KIRKWOOD_SOC && (MACH_OPENRD_CLIENT || MACH_OPENRD_ULTIMATE)
+       depends on SND_KIRKWOOD_SOC && (MACH_OPENRD_CLIENT || MACH_OPENRD_ULTIMATE || COMPILE_TEST)
        depends on I2C
        select SND_KIRKWOOD_SOC_I2S
        select SND_SOC_CS42L51
@@ -21,7 +21,7 @@ config SND_KIRKWOOD_SOC_OPENRD
 
 config SND_KIRKWOOD_SOC_T5325
        tristate "SoC Audio support for HP t5325"
-       depends on SND_KIRKWOOD_SOC && MACH_T5325 && I2C
+       depends on SND_KIRKWOOD_SOC && (MACH_T5325 || COMPILE_TEST) && I2C
        select SND_KIRKWOOD_SOC_I2S
        select SND_SOC_ALC5623
        help
index 4c9dad3263c5f7b754d108b3bf66a3ebdb6d67f3..ba720399536934d6df8f82e2266cd1bbb600d03d 100644 (file)
@@ -26,9 +26,6 @@
 
 #define DRV_NAME       "kirkwood-i2s"
 
-#define KIRKWOOD_I2S_RATES \
-       (SNDRV_PCM_RATE_44100 | \
-        SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
 #define KIRKWOOD_I2S_FORMATS \
        (SNDRV_PCM_FMTBIT_S16_LE | \
         SNDRV_PCM_FMTBIT_S24_LE | \
@@ -105,14 +102,16 @@ static void kirkwood_set_rate(struct snd_soc_dai *dai,
        uint32_t clks_ctrl;
 
        if (rate == 44100 || rate == 48000 || rate == 96000) {
-               /* use internal dco for supported rates */
+               /* use internal dco for the supported rates
+                * defined in kirkwood_i2s_dai */
                dev_dbg(dai->dev, "%s: dco set rate = %lu\n",
                        __func__, rate);
                kirkwood_set_dco(priv->io, rate);
 
                clks_ctrl = KIRKWOOD_MCLK_SOURCE_DCO;
-       } else if (!IS_ERR(priv->extclk)) {
-               /* use optional external clk for other rates */
+       } else {
+               /* use the external clock for the other rates
+                * defined in kirkwood_i2s_dai_extclk */
                dev_dbg(dai->dev, "%s: extclk set rate = %lu -> %lu\n",
                        __func__, rate, 256 * rate);
                clk_set_rate(priv->extclk, 256 * rate);
@@ -398,11 +397,6 @@ static int kirkwood_i2s_probe(struct snd_soc_dai *dai)
 
 }
 
-static int kirkwood_i2s_remove(struct snd_soc_dai *dai)
-{
-       return 0;
-}
-
 static const struct snd_soc_dai_ops kirkwood_i2s_dai_ops = {
        .startup        = kirkwood_i2s_startup,
        .trigger        = kirkwood_i2s_trigger,
@@ -413,17 +407,18 @@ static const struct snd_soc_dai_ops kirkwood_i2s_dai_ops = {
 
 static struct snd_soc_dai_driver kirkwood_i2s_dai = {
        .probe = kirkwood_i2s_probe,
-       .remove = kirkwood_i2s_remove,
        .playback = {
                .channels_min = 1,
                .channels_max = 2,
-               .rates = KIRKWOOD_I2S_RATES,
+               .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+                               SNDRV_PCM_RATE_96000,
                .formats = KIRKWOOD_I2S_FORMATS,
        },
        .capture = {
                .channels_min = 1,
                .channels_max = 2,
-               .rates = KIRKWOOD_I2S_RATES,
+               .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+                               SNDRV_PCM_RATE_96000,
                .formats = KIRKWOOD_I2S_FORMATS,
        },
        .ops = &kirkwood_i2s_dai_ops,
@@ -431,7 +426,6 @@ static struct snd_soc_dai_driver kirkwood_i2s_dai = {
 
 static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk = {
        .probe = kirkwood_i2s_probe,
-       .remove = kirkwood_i2s_remove,
        .playback = {
                .channels_min = 1,
                .channels_max = 2,
@@ -498,10 +492,9 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
        if (err < 0)
                return err;
 
-       priv->extclk = clk_get(&pdev->dev, "extclk");
+       priv->extclk = devm_clk_get(&pdev->dev, "extclk");
        if (!IS_ERR(priv->extclk)) {
                if (priv->extclk == priv->clk) {
-                       clk_put(priv->extclk);
                        priv->extclk = ERR_PTR(-EINVAL);
                } else {
                        dev_info(&pdev->dev, "found external clock\n");
@@ -529,10 +522,8 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
                return 0;
        dev_err(&pdev->dev, "snd_soc_register_component failed\n");
 
-       if (!IS_ERR(priv->extclk)) {
+       if (!IS_ERR(priv->extclk))
                clk_disable_unprepare(priv->extclk);
-               clk_put(priv->extclk);
-       }
        clk_disable_unprepare(priv->clk);
 
        return err;
@@ -544,10 +535,8 @@ static int kirkwood_i2s_dev_remove(struct platform_device *pdev)
 
        snd_soc_unregister_component(&pdev->dev);
 
-       if (!IS_ERR(priv->extclk)) {
+       if (!IS_ERR(priv->extclk))
                clk_disable_unprepare(priv->extclk);
-               clk_put(priv->extclk);
-       }
        clk_disable_unprepare(priv->clk);
 
        return 0;
index b979c7154715a0ee9407c908f76f9f1ca9f91748..addbebc2b3fa6587b2fd7c525306a2164a7b95fd 100644 (file)
@@ -16,9 +16,7 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <sound/soc.h>
-#include <mach/kirkwood.h>
 #include <linux/platform_data/asoc-kirkwood.h>
-#include <asm/mach-types.h>
 #include "../codecs/cs42l51.h"
 
 static int openrd_client_hw_params(struct snd_pcm_substream *substream,
index 1d0ed6f8add7ba5a7236f428476ab6f981522ab6..4f4cb56f765ad945585528ced66e8c3ff44f4a02 100644 (file)
@@ -15,9 +15,7 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <sound/soc.h>
-#include <mach/kirkwood.h>
 #include <linux/platform_data/asoc-kirkwood.h>
-#include <asm/mach-types.h>
 #include "../codecs/alc5623.h"
 
 static int t5325_hw_params(struct snd_pcm_substream *substream,
index 78d321cbe8b44ab0b06c9142da04d47d725dedf4..219235c022125d84a7565a4c9c962dd5098990d0 100644 (file)
@@ -1,6 +1,7 @@
 menuconfig SND_MXS_SOC
        tristate "SoC Audio for Freescale MXS CPUs"
-       depends on ARCH_MXS
+       depends on ARCH_MXS || COMPILE_TEST
+       depends on COMMON_CLK
        select SND_SOC_GENERIC_DMAENGINE_PCM
        help
          Say Y or M if you want to add support for codecs attached to
index 54511c5e6a7ce8a75a2bc5897dd6a7d6085e007d..b56b8a0e8deb43b6fdca0668fb43677bb1ce47ba 100644 (file)
@@ -31,7 +31,6 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
-#include <asm/mach-types.h>
 
 #include "mxs-saif.h"
 
index 1b134d72f120a60b5956032986b964c6f659ab0e..b2e372dd02ebce693b5ed6289cf8cac4b8bef019 100644 (file)
@@ -25,7 +25,6 @@
 #include <sound/soc.h>
 #include <sound/jack.h>
 #include <sound/soc-dapm.h>
-#include <asm/mach-types.h>
 
 #include "../codecs/sgtl5000.h"
 #include "mxs-saif.h"
index f4c2417a8730bcf0ae99c37fe1bfcc76a685cb51..8987bf987e584f6ba7a53b93516056dfbf5bc9b5 100644 (file)
@@ -333,9 +333,6 @@ static int nuc900_ac97_drvprobe(struct platform_device *pdev)
        spin_lock_init(&nuc900_audio->lock);
 
        nuc900_audio->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!nuc900_audio->res)
-               return ret;
-
        nuc900_audio->mmio = devm_ioremap_resource(&pdev->dev,
                                                   nuc900_audio->res);
        if (IS_ERR(nuc900_audio->mmio))
index 9f5d55e6b17a53d7e50f2a3c392f565b0fb2e014..44b5acf01f3fe0c5826cdff803fe19cd54d59e62 100644 (file)
@@ -1,6 +1,6 @@
 config SND_OMAP_SOC
        tristate "SoC Audio for the Texas Instruments OMAP chips"
-       depends on ARCH_OMAP && DMA_OMAP
+       depends on (ARCH_OMAP && DMA_OMAP) || (ARCH_ARM && COMPILE_TEST)
        select SND_SOC_DMAENGINE_PCM
 
 config SND_OMAP_SOC_DMIC
@@ -26,7 +26,7 @@ config SND_OMAP_SOC_N810
 
 config SND_OMAP_SOC_RX51
        tristate "SoC Audio support for Nokia RX-51"
-       depends on SND_OMAP_SOC && MACH_NOKIA_RX51
+       depends on SND_OMAP_SOC && ARCH_ARM && (MACH_NOKIA_RX51 || COMPILE_TEST)
        select SND_OMAP_SOC_MCBSP
        select SND_SOC_TLV320AIC3X
        select SND_SOC_TPA6130A2
@@ -87,7 +87,7 @@ config SND_OMAP_SOC_OMAP_TWL4030
 
 config SND_OMAP_SOC_OMAP_ABE_TWL6040
        tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec"
-       depends on TWL6040_CORE && SND_OMAP_SOC && ARCH_OMAP4
+       depends on TWL6040_CORE && SND_OMAP_SOC && (ARCH_OMAP4 || COMPILE_TEST)
        select SND_OMAP_SOC_DMIC
        select SND_OMAP_SOC_MCPDM
        select SND_SOC_TWL6040
index 361e4c03646e32a9b73d76122a13e3e071c7a9b0..83433fdea32ad790f839edd357c14824def13c07 100644 (file)
@@ -781,7 +781,7 @@ static ssize_t prop##_store(struct device *dev,                             \
        unsigned long val;                                              \
        int status;                                                     \
                                                                        \
-       status = strict_strtoul(buf, 0, &val);                          \
+       status = kstrtoul(buf, 0, &val);                                \
        if (status)                                                     \
                return status;                                          \
                                                                        \
index 70cd5c7b2e145622b031ffd320786599738091de..ebb13906b3a0b41b4d3c20509c613378da5ae248 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/clk.h>
 #include <linux/platform_device.h>
 #include <linux/mfd/twl6040.h>
-#include <linux/platform_data/omap-abe-twl6040.h>
 #include <linux/module.h>
 #include <linux/of.h>
 
@@ -166,19 +165,10 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"AFMR", NULL, "Line In"},
 };
 
-static inline void twl6040_disconnect_pin(struct snd_soc_dapm_context *dapm,
-                                         int connected, char *pin)
-{
-       if (!connected)
-               snd_soc_dapm_disable_pin(dapm, pin);
-}
-
 static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
        struct snd_soc_card *card = codec->card;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-       struct omap_abe_twl6040_data *pdata = dev_get_platdata(card->dev);
        struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card);
        int hs_trim;
        int ret = 0;
@@ -203,24 +193,6 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd)
                twl6040_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET);
        }
 
-       /*
-        * NULL pdata means we booted with DT. In this case the routing is
-        * provided and the card is fully routed, no need to mark pins.
-        */
-       if (!pdata)
-               return ret;
-
-       /* Disable not connected paths if not used */
-       twl6040_disconnect_pin(dapm, pdata->has_hs, "Headset Stereophone");
-       twl6040_disconnect_pin(dapm, pdata->has_hf, "Ext Spk");
-       twl6040_disconnect_pin(dapm, pdata->has_ep, "Earphone Spk");
-       twl6040_disconnect_pin(dapm, pdata->has_aux, "Line Out");
-       twl6040_disconnect_pin(dapm, pdata->has_vibra, "Vibrator");
-       twl6040_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic");
-       twl6040_disconnect_pin(dapm, pdata->has_mainmic, "Main Handset Mic");
-       twl6040_disconnect_pin(dapm, pdata->has_submic, "Sub Handset Mic");
-       twl6040_disconnect_pin(dapm, pdata->has_afm, "Line In");
-
        return ret;
 }
 
@@ -274,13 +246,18 @@ static struct snd_soc_card omap_abe_card = {
 
 static int omap_abe_probe(struct platform_device *pdev)
 {
-       struct omap_abe_twl6040_data *pdata = dev_get_platdata(&pdev->dev);
        struct device_node *node = pdev->dev.of_node;
        struct snd_soc_card *card = &omap_abe_card;
+       struct device_node *dai_node;
        struct abe_twl6040 *priv;
        int num_links = 0;
        int ret = 0;
 
+       if (!node) {
+               dev_err(&pdev->dev, "of node is missing.\n");
+               return -ENODEV;
+       }
+
        card->dev = &pdev->dev;
 
        priv = devm_kzalloc(&pdev->dev, sizeof(struct abe_twl6040), GFP_KERNEL);
@@ -289,78 +266,50 @@ static int omap_abe_probe(struct platform_device *pdev)
 
        priv->dmic_codec_dev = ERR_PTR(-EINVAL);
 
-       if (node) {
-               struct device_node *dai_node;
-
-               if (snd_soc_of_parse_card_name(card, "ti,model")) {
-                       dev_err(&pdev->dev, "Card name is not provided\n");
-                       return -ENODEV;
-               }
+       if (snd_soc_of_parse_card_name(card, "ti,model")) {
+               dev_err(&pdev->dev, "Card name is not provided\n");
+               return -ENODEV;
+       }
 
-               ret = snd_soc_of_parse_audio_routing(card,
-                                               "ti,audio-routing");
-               if (ret) {
-                       dev_err(&pdev->dev,
-                               "Error while parsing DAPM routing\n");
-                       return ret;
-               }
+       ret = snd_soc_of_parse_audio_routing(card, "ti,audio-routing");
+       if (ret) {
+               dev_err(&pdev->dev, "Error while parsing DAPM routing\n");
+               return ret;
+       }
 
-               dai_node = of_parse_phandle(node, "ti,mcpdm", 0);
-               if (!dai_node) {
-                       dev_err(&pdev->dev, "McPDM node is not provided\n");
-                       return -EINVAL;
-               }
-               abe_twl6040_dai_links[0].cpu_dai_name  = NULL;
-               abe_twl6040_dai_links[0].cpu_of_node = dai_node;
+       dai_node = of_parse_phandle(node, "ti,mcpdm", 0);
+       if (!dai_node) {
+               dev_err(&pdev->dev, "McPDM node is not provided\n");
+               return -EINVAL;
+       }
+       abe_twl6040_dai_links[0].cpu_dai_name  = NULL;
+       abe_twl6040_dai_links[0].cpu_of_node = dai_node;
 
-               dai_node = of_parse_phandle(node, "ti,dmic", 0);
-               if (dai_node) {
-                       num_links = 2;
-                       abe_twl6040_dai_links[1].cpu_dai_name  = NULL;
-                       abe_twl6040_dai_links[1].cpu_of_node = dai_node;
+       dai_node = of_parse_phandle(node, "ti,dmic", 0);
+       if (dai_node) {
+               num_links = 2;
+               abe_twl6040_dai_links[1].cpu_dai_name  = NULL;
+               abe_twl6040_dai_links[1].cpu_of_node = dai_node;
 
-                       priv->dmic_codec_dev = platform_device_register_simple(
+               priv->dmic_codec_dev = platform_device_register_simple(
                                                "dmic-codec", -1, NULL, 0);
-                       if (IS_ERR(priv->dmic_codec_dev)) {
-                               dev_err(&pdev->dev,
-                                       "Can't instantiate dmic-codec\n");
-                               return PTR_ERR(priv->dmic_codec_dev);
-                       }
-               } else {
-                       num_links = 1;
-               }
-
-               priv->jack_detection = of_property_read_bool(node,
-                                                          "ti,jack-detection");
-               of_property_read_u32(node, "ti,mclk-freq",
-                                    &priv->mclk_freq);
-               if (!priv->mclk_freq) {
-                       dev_err(&pdev->dev, "MCLK frequency not provided\n");
-                       ret = -EINVAL;
-                       goto err_unregister;
+               if (IS_ERR(priv->dmic_codec_dev)) {
+                       dev_err(&pdev->dev, "Can't instantiate dmic-codec\n");
+                       return PTR_ERR(priv->dmic_codec_dev);
                }
-
-               omap_abe_card.fully_routed = 1;
-       } else if (pdata) {
-               if (pdata->card_name) {
-                       card->name = pdata->card_name;
-               } else {
-                       dev_err(&pdev->dev, "Card name is not provided\n");
-                       return -ENODEV;
-               }
-
-               if (pdata->has_dmic)
-                       num_links = 2;
-               else
-                       num_links = 1;
-
-               priv->jack_detection = pdata->jack_detection;
-               priv->mclk_freq = pdata->mclk_freq;
        } else {
-               dev_err(&pdev->dev, "Missing pdata\n");
-               return -ENODEV;
+               num_links = 1;
+       }
+
+       priv->jack_detection = of_property_read_bool(node, "ti,jack-detection");
+       of_property_read_u32(node, "ti,mclk-freq", &priv->mclk_freq);
+       if (!priv->mclk_freq) {
+               dev_err(&pdev->dev, "MCLK frequency not provided\n");
+               ret = -EINVAL;
+               goto err_unregister;
        }
 
+       card->fully_routed = 1;
 
        if (!priv->mclk_freq) {
                dev_err(&pdev->dev, "MCLK frequency missing\n");
index 7483efb6dc674e9bdb90e9ea3bd39a7505a9c34b..6c19bba2357004903477a7300582d193b26f2962 100644 (file)
@@ -433,6 +433,11 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                /* Sample rate generator drives the FS */
                regs->srgr2     |= FSGM;
                break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+               /* McBSP slave. FS clock as output */
+               regs->srgr2     |= FSGM;
+               regs->pcr0      |= FSXM;
+               break;
        case SND_SOC_DAIFMT_CBM_CFM:
                /* McBSP slave */
                break;
index 4ad76099dd43fdec0d9e7262db77f1e07cd20713..5b7d969f89a96eebd418687ef5b7abc79d74ee97 100644 (file)
@@ -129,6 +129,7 @@ static struct snd_soc_dai_link brownstone_wm8994_dai[] = {
 /* audio machine driver */
 static struct snd_soc_card brownstone = {
        .name         = "brownstone",
+       .owner        = THIS_MODULE,
        .dai_link     = brownstone_wm8994_dai,
        .num_links    = ARRAY_SIZE(brownstone_wm8994_dai),
 
index 62142ce367c7e68fcffbe7b34b92b7364d7a0af3..1605934d525eca7e35f1bfdd4cadd3302aef3276 100644 (file)
@@ -430,9 +430,6 @@ static int asoc_mmp_sspa_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (res == NULL)
-               return -ENOMEM;
-
        priv->sspa->mmio_base = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(priv->sspa->mmio_base))
                return PTR_ERR(priv->sspa->mmio_base);
index f4ea4f6663a2c0d396997d7aef5cc1871f6ea6e5..13c9ee0cb83b988b06cb9b84963128b1cd703032 100644 (file)
@@ -122,6 +122,7 @@ static struct snd_soc_dai_link ttc_pm860x_hifi_dai[] = {
 /* ttc/td audio machine driver */
 static struct snd_soc_card ttc_dkb_card = {
        .name = "ttc-dkb-hifi",
+       .owner = THIS_MODULE,
        .dai_link = ttc_pm860x_hifi_dai,
        .num_links = ARRAY_SIZE(ttc_pm860x_hifi_dai),
 
index c0e6d9a19efc72562c31157acf776f1e24e57085..30513b7ede3a39e0583e1782c128bfa48fea643a 100644 (file)
 #define MOD_RXONLY             (1 << 8)
 #define MOD_TXRX               (2 << 8)
 #define MOD_MASK               (3 << 8)
-#define MOD_LR_LLOW            (0 << 7)
-#define MOD_LR_RLOW            (1 << 7)
-#define MOD_SDF_IIS            (0 << 5)
-#define MOD_SDF_MSB            (1 << 5)
-#define MOD_SDF_LSB            (2 << 5)
-#define MOD_SDF_MASK           (3 << 5)
-#define MOD_RCLK_256FS         (0 << 3)
-#define MOD_RCLK_512FS         (1 << 3)
-#define MOD_RCLK_384FS         (2 << 3)
-#define MOD_RCLK_768FS         (3 << 3)
-#define MOD_RCLK_MASK          (3 << 3)
-#define MOD_BCLK_32FS          (0 << 1)
-#define MOD_BCLK_48FS          (1 << 1)
-#define MOD_BCLK_16FS          (2 << 1)
-#define MOD_BCLK_24FS          (3 << 1)
-#define MOD_BCLK_MASK          (3 << 1)
+#define MOD_LRP_SHIFT          7
+#define MOD_LR_LLOW            0
+#define MOD_LR_RLOW            1
+#define MOD_SDF_SHIFT          5
+#define MOD_SDF_IIS            0
+#define MOD_SDF_MSB            1
+#define MOD_SDF_LSB            2
+#define MOD_SDF_MASK           3
+#define MOD_RCLK_SHIFT         3
+#define MOD_RCLK_256FS         0
+#define MOD_RCLK_512FS         1
+#define MOD_RCLK_384FS         2
+#define MOD_RCLK_768FS         3
+#define MOD_RCLK_MASK          3
+#define MOD_BCLK_SHIFT         1
+#define MOD_BCLK_32FS          0
+#define MOD_BCLK_48FS          1
+#define MOD_BCLK_16FS          2
+#define MOD_BCLK_24FS          3
+#define MOD_BCLK_MASK          3
 #define MOD_8BIT               (1 << 0)
 
 #define MOD_CDCLKCON           (1 << 12)
index 959c702235c8c6028d0946f29b622266f043ab2f..a3e4b49957854a5490e8f4810464388acab984b2 100644 (file)
@@ -198,7 +198,8 @@ static inline bool is_manager(struct i2s_dai *i2s)
 /* Read RCLK of I2S (in multiples of LRCLK) */
 static inline unsigned get_rfs(struct i2s_dai *i2s)
 {
-       u32 rfs = (readl(i2s->addr + I2SMOD) >> 3) & 0x3;
+       u32 rfs = (readl(i2s->addr + I2SMOD) >> MOD_RCLK_SHIFT);
+       rfs &= MOD_RCLK_MASK;
 
        switch (rfs) {
        case 3: return 768;
@@ -212,21 +213,22 @@ static inline unsigned get_rfs(struct i2s_dai *i2s)
 static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs)
 {
        u32 mod = readl(i2s->addr + I2SMOD);
+       int rfs_shift =  MOD_RCLK_SHIFT;
 
-       mod &= ~MOD_RCLK_MASK;
+       mod &= ~(MOD_RCLK_MASK << rfs_shift);
 
        switch (rfs) {
        case 768:
-               mod |= MOD_RCLK_768FS;
+               mod |= (MOD_RCLK_768FS << rfs_shift);
                break;
        case 512:
-               mod |= MOD_RCLK_512FS;
+               mod |= (MOD_RCLK_512FS << rfs_shift);
                break;
        case 384:
-               mod |= MOD_RCLK_384FS;
+               mod |= (MOD_RCLK_384FS << rfs_shift);
                break;
        default:
-               mod |= MOD_RCLK_256FS;
+               mod |= (MOD_RCLK_256FS << rfs_shift);
                break;
        }
 
@@ -236,7 +238,8 @@ static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs)
 /* Read Bit-Clock of I2S (in multiples of LRCLK) */
 static inline unsigned get_bfs(struct i2s_dai *i2s)
 {
-       u32 bfs = (readl(i2s->addr + I2SMOD) >> 1) & 0x3;
+       u32 bfs =  readl(i2s->addr + I2SMOD) >> MOD_BCLK_SHIFT;
+       bfs &= MOD_BCLK_MASK;
 
        switch (bfs) {
        case 3: return 24;
@@ -250,21 +253,22 @@ static inline unsigned get_bfs(struct i2s_dai *i2s)
 static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs)
 {
        u32 mod = readl(i2s->addr + I2SMOD);
+       int bfs_shift = MOD_BCLK_SHIFT;
 
-       mod &= ~MOD_BCLK_MASK;
+       mod &= ~(MOD_BCLK_MASK << bfs_shift);
 
        switch (bfs) {
        case 48:
-               mod |= MOD_BCLK_48FS;
+               mod |= (MOD_BCLK_48FS << bfs_shift);
                break;
        case 32:
-               mod |= MOD_BCLK_32FS;
+               mod |= (MOD_BCLK_32FS << bfs_shift);
                break;
        case 24:
-               mod |= MOD_BCLK_24FS;
+               mod |= (MOD_BCLK_24FS << bfs_shift);
                break;
        case 16:
-               mod |= MOD_BCLK_16FS;
+               mod |= (MOD_BCLK_16FS << bfs_shift);
                break;
        default:
                dev_err(&i2s->pdev->dev, "Wrong BCLK Divider!\n");
@@ -491,20 +495,25 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
 {
        struct i2s_dai *i2s = to_info(dai);
        u32 mod = readl(i2s->addr + I2SMOD);
+       int lrp_shift = MOD_LRP_SHIFT, sdf_shift = MOD_SDF_SHIFT;
+       int sdf_mask, lrp_rlow;
        u32 tmp = 0;
 
+       sdf_mask = MOD_SDF_MASK << sdf_shift;
+       lrp_rlow = MOD_LR_RLOW << lrp_shift;
+
        /* Format is priority */
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_RIGHT_J:
-               tmp |= MOD_LR_RLOW;
-               tmp |= MOD_SDF_MSB;
+               tmp |= lrp_rlow;
+               tmp |= (MOD_SDF_MSB << sdf_shift);
                break;
        case SND_SOC_DAIFMT_LEFT_J:
-               tmp |= MOD_LR_RLOW;
-               tmp |= MOD_SDF_LSB;
+               tmp |= lrp_rlow;
+               tmp |= (MOD_SDF_LSB << sdf_shift);
                break;
        case SND_SOC_DAIFMT_I2S:
-               tmp |= MOD_SDF_IIS;
+               tmp |= (MOD_SDF_IIS << sdf_shift);
                break;
        default:
                dev_err(&i2s->pdev->dev, "Format not supported\n");
@@ -519,10 +528,10 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
        case SND_SOC_DAIFMT_NB_NF:
                break;
        case SND_SOC_DAIFMT_NB_IF:
-               if (tmp & MOD_LR_RLOW)
-                       tmp &= ~MOD_LR_RLOW;
+               if (tmp & lrp_rlow)
+                       tmp &= ~lrp_rlow;
                else
-                       tmp |= MOD_LR_RLOW;
+                       tmp |= lrp_rlow;
                break;
        default:
                dev_err(&i2s->pdev->dev, "Polarity not supported\n");
@@ -544,15 +553,18 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
                return -EINVAL;
        }
 
+       /*
+        * Don't change the I2S mode if any controller is active on this
+        * channel.
+        */
        if (any_active(i2s) &&
-                       ((mod & (MOD_SDF_MASK | MOD_LR_RLOW
-                               | MOD_SLAVE)) != tmp)) {
+               ((mod & (sdf_mask | lrp_rlow | MOD_SLAVE)) != tmp)) {
                dev_err(&i2s->pdev->dev,
                                "%s:%d Other DAI busy\n", __func__, __LINE__);
                return -EAGAIN;
        }
 
-       mod &= ~(MOD_SDF_MASK | MOD_LR_RLOW | MOD_SLAVE);
+       mod &= ~(sdf_mask | lrp_rlow | MOD_SLAVE);
        mod |= tmp;
        writel(mod, i2s->addr + I2SMOD);
 
index 581ea4a06fc684d1e3f677477326426d7334b427..5fd7a05a9b9e2fe9730a962bcdca73482a9e5d71 100644 (file)
@@ -11,6 +11,7 @@
 #include <sound/pcm_params.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 
  /*
   * Default CFG switch settings to use this driver:
 /* SMDK has a 16.934MHZ crystal attached to WM8994 */
 #define SMDK_WM8994_FREQ 16934000
 
+struct smdk_wm8994_data {
+       int mclk1_rate;
+};
+
+/* Default SMDKs */
+static struct smdk_wm8994_data smdk_board_data = {
+       .mclk1_rate = SMDK_WM8994_FREQ,
+};
+
 static int smdk_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
        unsigned int pll_out;
        int ret;
@@ -54,18 +63,6 @@ static int smdk_hw_params(struct snd_pcm_substream *substream,
        else
                pll_out = params_rate(params) * 256;
 
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
-                                        | SND_SOC_DAIFMT_NB_NF
-                                        | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S
-                                        | SND_SOC_DAIFMT_NB_NF
-                                        | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
        ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, WM8994_FLL_SRC_MCLK1,
                                        SMDK_WM8994_FREQ, pll_out);
        if (ret < 0)
@@ -131,6 +128,8 @@ static struct snd_soc_dai_link smdk_dai[] = {
                .platform_name = "samsung-i2s.0",
                .codec_name = "wm8994-codec",
                .init = smdk_wm8994_init_paiftx,
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                       SND_SOC_DAIFMT_CBM_CFM,
                .ops = &smdk_ops,
        }, { /* Sec_Fifo Playback i/f */
                .name = "Sec_FIFO TX",
@@ -139,6 +138,8 @@ static struct snd_soc_dai_link smdk_dai[] = {
                .codec_dai_name = "wm8994-aif1",
                .platform_name = "samsung-i2s-sec",
                .codec_name = "wm8994-codec",
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                       SND_SOC_DAIFMT_CBM_CFM,
                .ops = &smdk_ops,
        },
 };
@@ -150,15 +151,28 @@ static struct snd_soc_card smdk = {
        .num_links = ARRAY_SIZE(smdk_dai),
 };
 
+#ifdef CONFIG_OF
+static const struct of_device_id samsung_wm8994_of_match[] = {
+       { .compatible = "samsung,smdk-wm8994", .data = &smdk_board_data },
+       {},
+};
+MODULE_DEVICE_TABLE(of, samsung_wm8994_of_match);
+#endif /* CONFIG_OF */
 
 static int smdk_audio_probe(struct platform_device *pdev)
 {
        int ret;
        struct device_node *np = pdev->dev.of_node;
        struct snd_soc_card *card = &smdk;
+       struct smdk_wm8994_data *board;
+       const struct of_device_id *id;
 
        card->dev = &pdev->dev;
 
+       board = devm_kzalloc(&pdev->dev, sizeof(*board), GFP_KERNEL);
+       if (!board)
+               return -ENOMEM;
+
        if (np) {
                smdk_dai[0].cpu_dai_name = NULL;
                smdk_dai[0].cpu_of_node = of_parse_phandle(np,
@@ -173,6 +187,12 @@ static int smdk_audio_probe(struct platform_device *pdev)
                smdk_dai[0].platform_of_node = smdk_dai[0].cpu_of_node;
        }
 
+       id = of_match_device(samsung_wm8994_of_match, &pdev->dev);
+       if (id)
+               *board = *((struct smdk_wm8994_data *)id->data);
+
+       platform_set_drvdata(pdev, board);
+
        ret = snd_soc_register_card(card);
 
        if (ret)
@@ -190,17 +210,9 @@ static int smdk_audio_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_OF
-static const struct of_device_id samsung_wm8994_of_match[] = {
-       { .compatible = "samsung,smdk-wm8994", },
-       {},
-};
-MODULE_DEVICE_TABLE(of, samsung_wm8994_of_match);
-#endif /* CONFIG_OF */
-
 static struct platform_driver smdk_audio_driver = {
        .driver         = {
-               .name   = "smdk-audio",
+               .name   = "smdk-audio-wm8894",
                .owner  = THIS_MODULE,
                .of_match_table = of_match_ptr(samsung_wm8994_of_match),
        },
@@ -212,4 +224,4 @@ module_platform_driver(smdk_audio_driver);
 
 MODULE_DESCRIPTION("ALSA SoC SMDK WM8994");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:smdk-audio");
+MODULE_ALIAS("platform:smdk-audio-wm8994");
index 2e5ebb2f1982c2e849e8a8adc7924034a6931675..5ea70ab0ecb5897aab234b5b06de7f465d9a0f39 100644 (file)
@@ -395,7 +395,7 @@ static int spdif_probe(struct platform_device *pdev)
 
        spin_lock_init(&spdif->lock);
 
-       spdif->pclk = clk_get(&pdev->dev, "spdif");
+       spdif->pclk = devm_clk_get(&pdev->dev, "spdif");
        if (IS_ERR(spdif->pclk)) {
                dev_err(&pdev->dev, "failed to get peri-clock\n");
                ret = -ENOENT;
@@ -403,7 +403,7 @@ static int spdif_probe(struct platform_device *pdev)
        }
        clk_prepare_enable(spdif->pclk);
 
-       spdif->sclk = clk_get(&pdev->dev, "sclk_spdif");
+       spdif->sclk = devm_clk_get(&pdev->dev, "sclk_spdif");
        if (IS_ERR(spdif->sclk)) {
                dev_err(&pdev->dev, "failed to get internal source clock\n");
                ret = -ENOENT;
@@ -457,10 +457,8 @@ err3:
        release_mem_region(mem_res->start, resource_size(mem_res));
 err2:
        clk_disable_unprepare(spdif->sclk);
-       clk_put(spdif->sclk);
 err1:
        clk_disable_unprepare(spdif->pclk);
-       clk_put(spdif->pclk);
 err0:
        return ret;
 }
@@ -480,9 +478,7 @@ static int spdif_remove(struct platform_device *pdev)
                release_mem_region(mem_res->start, resource_size(mem_res));
 
        clk_disable_unprepare(spdif->sclk);
-       clk_put(spdif->sclk);
        clk_disable_unprepare(spdif->pclk);
-       clk_put(spdif->pclk);
 
        return 0;
 }
index 6bcb1164d599d61bec029fdb94d3f00495b8f66c..56d8ff6a402d2eaffdb4aeb5bc65faa5b815678a 100644 (file)
@@ -34,6 +34,13 @@ config SND_SOC_SH4_SIU
        select SH_DMAE
        select FW_LOADER
 
+config SND_SOC_RCAR
+       tristate "R-Car series SRU/SCU/SSIU/SSI support"
+       select SND_SIMPLE_CARD
+       select RCAR_CLK_ADG
+       help
+         This option enables R-Car SUR/SCU/SSIU/SSI sound support
+
 ##
 ## Boards
 ##
index 849b387d17d99a7d91b21bd1f64adc228341cfb9..aaf3dcd1ee2a197fae36c1f577443a386e8371a1 100644 (file)
@@ -12,6 +12,9 @@ obj-$(CONFIG_SND_SOC_SH4_SSI) += snd-soc-ssi.o
 obj-$(CONFIG_SND_SOC_SH4_FSI)  += snd-soc-fsi.o
 obj-$(CONFIG_SND_SOC_SH4_SIU)  += snd-soc-siu.o
 
+## audio units for R-Car
+obj-$(CONFIG_SND_SOC_RCAR)     += rcar/
+
 ## boards
 snd-soc-sh7760-ac97-objs       := sh7760-ac97.o
 snd-soc-migor-objs             := migor.o
diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile
new file mode 100644 (file)
index 0000000..0ff492d
--- /dev/null
@@ -0,0 +1,2 @@
+snd-soc-rcar-objs      := core.o gen.o scu.o adg.o ssi.o
+obj-$(CONFIG_SND_SOC_RCAR)     += snd-soc-rcar.o
\ No newline at end of file
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
new file mode 100644 (file)
index 0000000..d80deb7
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * Helper routines for R-Car sound ADG.
+ *
+ *  Copyright (C) 2013  Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/sh_clk.h>
+#include <mach/clock.h>
+#include "rsnd.h"
+
+#define CLKA   0
+#define CLKB   1
+#define CLKC   2
+#define CLKI   3
+#define CLKMAX 4
+
+struct rsnd_adg {
+       struct clk *clk[CLKMAX];
+
+       int rate_of_441khz_div_6;
+       int rate_of_48khz_div_6;
+};
+
+#define for_each_rsnd_clk(pos, adg, i)         \
+       for (i = 0, (pos) = adg->clk[i];        \
+            i < CLKMAX;                        \
+            i++, (pos) = adg->clk[i])
+#define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg)
+
+static enum rsnd_reg rsnd_adg_ssi_reg_get(int id)
+{
+       enum rsnd_reg reg;
+
+       /*
+        * SSI 8 is not connected to ADG.
+        * it works with SSI 7
+        */
+       if (id == 8)
+               return RSND_REG_MAX;
+
+       if (0 <= id && id <= 3)
+               reg = RSND_REG_AUDIO_CLK_SEL0;
+       else if (4 <= id && id <= 7)
+               reg = RSND_REG_AUDIO_CLK_SEL1;
+       else
+               reg = RSND_REG_AUDIO_CLK_SEL2;
+
+       return reg;
+}
+
+int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       enum rsnd_reg reg;
+       int id;
+
+       /*
+        * "mod" = "ssi" here.
+        * we can get "ssi id" from mod
+        */
+       id  = rsnd_mod_id(mod);
+       reg = rsnd_adg_ssi_reg_get(id);
+
+       rsnd_write(priv, mod, reg, 0);
+
+       return 0;
+}
+
+int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct clk *clk;
+       enum rsnd_reg reg;
+       int id, shift, i;
+       u32 data;
+       int sel_table[] = {
+               [CLKA] = 0x1,
+               [CLKB] = 0x2,
+               [CLKC] = 0x3,
+               [CLKI] = 0x0,
+       };
+
+       dev_dbg(dev, "request clock = %d\n", rate);
+
+       /*
+        * find suitable clock from
+        * AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC/AUDIO_CLKI.
+        */
+       data = 0;
+       for_each_rsnd_clk(clk, adg, i) {
+               if (rate == clk_get_rate(clk)) {
+                       data = sel_table[i];
+                       goto found_clock;
+               }
+       }
+
+       /*
+        * find 1/6 clock from BRGA/BRGB
+        */
+       if (rate == adg->rate_of_441khz_div_6) {
+               data = 0x10;
+               goto found_clock;
+       }
+
+       if (rate == adg->rate_of_48khz_div_6) {
+               data = 0x20;
+               goto found_clock;
+       }
+
+       return -EIO;
+
+found_clock:
+
+       /*
+        * This "mod" = "ssi" here.
+        * we can get "ssi id" from mod
+        */
+       id  = rsnd_mod_id(mod);
+       reg = rsnd_adg_ssi_reg_get(id);
+
+       dev_dbg(dev, "ADG: ssi%d selects clk%d = %d", id, i, rate);
+
+       /*
+        * Enable SSIx clock
+        */
+       shift = (id % 4) * 8;
+
+       rsnd_bset(priv, mod, reg,
+                  0xFF << shift,
+                  data << shift);
+
+       return 0;
+}
+
+static void rsnd_adg_ssi_clk_init(struct rsnd_priv *priv, struct rsnd_adg *adg)
+{
+       struct clk *clk;
+       unsigned long rate;
+       u32 ckr;
+       int i;
+       int brg_table[] = {
+               [CLKA] = 0x0,
+               [CLKB] = 0x1,
+               [CLKC] = 0x4,
+               [CLKI] = 0x2,
+       };
+
+       /*
+        * This driver is assuming that AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC
+        * have 44.1kHz or 48kHz base clocks for now.
+        *
+        * SSI itself can divide parent clock by 1/1 - 1/16
+        * So,  BRGA outputs 44.1kHz base parent clock 1/32,
+        * and, BRGB outputs 48.0kHz base parent clock 1/32 here.
+        * see
+        *      rsnd_adg_ssi_clk_try_start()
+        */
+       ckr = 0;
+       adg->rate_of_441khz_div_6 = 0;
+       adg->rate_of_48khz_div_6  = 0;
+       for_each_rsnd_clk(clk, adg, i) {
+               rate = clk_get_rate(clk);
+
+               if (0 == rate) /* not used */
+                       continue;
+
+               /* RBGA */
+               if (!adg->rate_of_441khz_div_6 && (0 == rate % 44100)) {
+                       adg->rate_of_441khz_div_6 = rate / 6;
+                       ckr |= brg_table[i] << 20;
+               }
+
+               /* RBGB */
+               if (!adg->rate_of_48khz_div_6 && (0 == rate % 48000)) {
+                       adg->rate_of_48khz_div_6 = rate / 6;
+                       ckr |= brg_table[i] << 16;
+               }
+       }
+
+       rsnd_priv_bset(priv, SSICKR, 0x00FF0000, ckr);
+       rsnd_priv_write(priv, BRRA,  0x00000002); /* 1/6 */
+       rsnd_priv_write(priv, BRRB,  0x00000002); /* 1/6 */
+}
+
+int rsnd_adg_probe(struct platform_device *pdev,
+                  struct rcar_snd_info *info,
+                  struct rsnd_priv *priv)
+{
+       struct rsnd_adg *adg;
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct clk *clk;
+       int i;
+
+       adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL);
+       if (!adg) {
+               dev_err(dev, "ADG allocate failed\n");
+               return -ENOMEM;
+       }
+
+       adg->clk[CLKA] = clk_get(NULL, "audio_clk_a");
+       adg->clk[CLKB] = clk_get(NULL, "audio_clk_b");
+       adg->clk[CLKC] = clk_get(NULL, "audio_clk_c");
+       adg->clk[CLKI] = clk_get(NULL, "audio_clk_internal");
+       for_each_rsnd_clk(clk, adg, i) {
+               if (IS_ERR(clk)) {
+                       dev_err(dev, "Audio clock failed\n");
+                       return -EIO;
+               }
+       }
+
+       rsnd_adg_ssi_clk_init(priv, adg);
+
+       priv->adg = adg;
+
+       dev_dbg(dev, "adg probed\n");
+
+       return 0;
+}
+
+void rsnd_adg_remove(struct platform_device *pdev,
+                    struct rsnd_priv *priv)
+{
+       struct rsnd_adg *adg = priv->adg;
+       struct clk *clk;
+       int i;
+
+       for_each_rsnd_clk(clk, adg, i)
+               clk_put(clk);
+}
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
new file mode 100644 (file)
index 0000000..9a5469d
--- /dev/null
@@ -0,0 +1,705 @@
+/*
+ * Renesas R-Car SRU/SCU/SSIU/SSI support
+ *
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * Based on fsi.c
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * Renesas R-Car sound device structure
+ *
+ * Gen1
+ *
+ * SRU         : Sound Routing Unit
+ *  - SRC      : Sampling Rate Converter
+ *  - CMD
+ *    - CTU    : Channel Count Conversion Unit
+ *    - MIX    : Mixer
+ *    - DVC    : Digital Volume and Mute Function
+ *  - SSI      : Serial Sound Interface
+ *
+ * Gen2
+ *
+ * SCU         : Sampling Rate Converter Unit
+ *  - SRC      : Sampling Rate Converter
+ *  - CMD
+ *   - CTU     : Channel Count Conversion Unit
+ *   - MIX     : Mixer
+ *   - DVC     : Digital Volume and Mute Function
+ * SSIU                : Serial Sound Interface Unit
+ *  - SSI      : Serial Sound Interface
+ */
+
+/*
+ *     driver data Image
+ *
+ * rsnd_priv
+ *   |
+ *   | ** this depends on Gen1/Gen2
+ *   |
+ *   +- gen
+ *   |
+ *   | ** these depend on data path
+ *   | ** gen and platform data control it
+ *   |
+ *   +- rdai[0]
+ *   |   |              sru     ssiu      ssi
+ *   |   +- playback -> [mod] -> [mod] -> [mod] -> ...
+ *   |   |
+ *   |   |              sru     ssiu      ssi
+ *   |   +- capture  -> [mod] -> [mod] -> [mod] -> ...
+ *   |
+ *   +- rdai[1]
+ *   |   |              sru     ssiu      ssi
+ *   |   +- playback -> [mod] -> [mod] -> [mod] -> ...
+ *   |   |
+ *   |   |              sru     ssiu      ssi
+ *   |   +- capture  -> [mod] -> [mod] -> [mod] -> ...
+ *   ...
+ *   |
+ *   | ** these control ssi
+ *   |
+ *   +- ssi
+ *   |  |
+ *   |  +- ssi[0]
+ *   |  +- ssi[1]
+ *   |  +- ssi[2]
+ *   |  ...
+ *   |
+ *   | ** these control scu
+ *   |
+ *   +- scu
+ *      |
+ *      +- scu[0]
+ *      +- scu[1]
+ *      +- scu[2]
+ *      ...
+ *
+ *
+ * for_each_rsnd_dai(xx, priv, xx)
+ *  rdai[0] => rdai[1] => rdai[2] => ...
+ *
+ * for_each_rsnd_mod(xx, rdai, xx)
+ *  [mod] => [mod] => [mod] => ...
+ *
+ * rsnd_dai_call(xxx, fn )
+ *  [mod]->fn() -> [mod]->fn() -> [mod]->fn()...
+ *
+ */
+#include <linux/pm_runtime.h>
+#include "rsnd.h"
+
+#define RSND_RATES SNDRV_PCM_RATE_8000_96000
+#define RSND_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
+
+/*
+ *     rsnd_platform functions
+ */
+#define rsnd_platform_call(priv, dai, func, param...)  \
+       (!(priv->info->func) ? -ENODEV :                \
+        priv->info->func(param))
+
+
+/*
+ *     basic function
+ */
+u32 rsnd_read(struct rsnd_priv *priv,
+             struct rsnd_mod *mod, enum rsnd_reg reg)
+{
+       void __iomem *base = rsnd_gen_reg_get(priv, mod, reg);
+
+       BUG_ON(!base);
+
+       return ioread32(base);
+}
+
+void rsnd_write(struct rsnd_priv *priv,
+               struct rsnd_mod *mod,
+               enum rsnd_reg reg, u32 data)
+{
+       void __iomem *base = rsnd_gen_reg_get(priv, mod, reg);
+       struct device *dev = rsnd_priv_to_dev(priv);
+
+       BUG_ON(!base);
+
+       dev_dbg(dev, "w %p : %08x\n", base, data);
+
+       iowrite32(data, base);
+}
+
+void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
+              enum rsnd_reg reg, u32 mask, u32 data)
+{
+       void __iomem *base = rsnd_gen_reg_get(priv, mod, reg);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       u32 val;
+
+       BUG_ON(!base);
+
+       val = ioread32(base);
+       val &= ~mask;
+       val |= data & mask;
+       iowrite32(val, base);
+
+       dev_dbg(dev, "s %p : %08x\n", base, val);
+}
+
+/*
+ *     rsnd_mod functions
+ */
+char *rsnd_mod_name(struct rsnd_mod *mod)
+{
+       if (!mod || !mod->ops)
+               return "unknown";
+
+       return mod->ops->name;
+}
+
+void rsnd_mod_init(struct rsnd_priv *priv,
+                  struct rsnd_mod *mod,
+                  struct rsnd_mod_ops *ops,
+                  int id)
+{
+       mod->priv       = priv;
+       mod->id         = id;
+       mod->ops        = ops;
+       INIT_LIST_HEAD(&mod->list);
+}
+
+/*
+ *     rsnd_dai functions
+ */
+#define rsnd_dai_call(rdai, io, fn)                    \
+({                                                     \
+       struct rsnd_mod *mod, *n;                       \
+       int ret = 0;                                    \
+       for_each_rsnd_mod(mod, n, io) {                 \
+               ret = rsnd_mod_call(mod, fn, rdai, io); \
+               if (ret < 0)                            \
+                       break;                          \
+       }                                               \
+       ret;                                            \
+})
+
+int rsnd_dai_connect(struct rsnd_dai *rdai,
+                    struct rsnd_mod *mod,
+                    struct rsnd_dai_stream *io)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+
+       if (!mod) {
+               dev_err(dev, "NULL mod\n");
+               return -EIO;
+       }
+
+       if (!list_empty(&mod->list)) {
+               dev_err(dev, "%s%d is not empty\n",
+                       rsnd_mod_name(mod),
+                       rsnd_mod_id(mod));
+               return -EIO;
+       }
+
+       list_add_tail(&mod->list, &io->head);
+
+       return 0;
+}
+
+int rsnd_dai_disconnect(struct rsnd_mod *mod)
+{
+       list_del_init(&mod->list);
+
+       return 0;
+}
+
+struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id)
+{
+       return priv->rdai + id;
+}
+
+static struct rsnd_dai *rsnd_dai_to_rdai(struct snd_soc_dai *dai)
+{
+       struct rsnd_priv *priv = snd_soc_dai_get_drvdata(dai);
+
+       return rsnd_dai_get(priv, dai->id);
+}
+
+int rsnd_dai_is_play(struct rsnd_dai *rdai, struct rsnd_dai_stream *io)
+{
+       return &rdai->playback == io;
+}
+
+/*
+ *     rsnd_soc_dai functions
+ */
+int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional)
+{
+       struct snd_pcm_substream *substream = io->substream;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int pos = io->byte_pos + additional;
+
+       pos %= (runtime->periods * io->byte_per_period);
+
+       return pos;
+}
+
+void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int byte)
+{
+       io->byte_pos += byte;
+
+       if (io->byte_pos >= io->next_period_byte) {
+               struct snd_pcm_substream *substream = io->substream;
+               struct snd_pcm_runtime *runtime = substream->runtime;
+
+               io->period_pos++;
+               io->next_period_byte += io->byte_per_period;
+
+               if (io->period_pos >= runtime->periods) {
+                       io->byte_pos = 0;
+                       io->period_pos = 0;
+                       io->next_period_byte = io->byte_per_period;
+               }
+
+               snd_pcm_period_elapsed(substream);
+       }
+}
+
+static int rsnd_dai_stream_init(struct rsnd_dai_stream *io,
+                               struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       if (!list_empty(&io->head))
+               return -EIO;
+
+       INIT_LIST_HEAD(&io->head);
+       io->substream           = substream;
+       io->byte_pos            = 0;
+       io->period_pos          = 0;
+       io->byte_per_period     = runtime->period_size *
+                                 runtime->channels *
+                                 samples_to_bytes(runtime, 1);
+       io->next_period_byte    = io->byte_per_period;
+
+       return 0;
+}
+
+static
+struct snd_soc_dai *rsnd_substream_to_dai(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+       return  rtd->cpu_dai;
+}
+
+static
+struct rsnd_dai_stream *rsnd_rdai_to_io(struct rsnd_dai *rdai,
+                                       struct snd_pcm_substream *substream)
+{
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               return &rdai->playback;
+       else
+               return &rdai->capture;
+}
+
+static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+                           struct snd_soc_dai *dai)
+{
+       struct rsnd_priv *priv = snd_soc_dai_get_drvdata(dai);
+       struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
+       struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
+       struct rsnd_dai_platform_info *info = rsnd_dai_get_platform_info(rdai);
+       int ssi_id = rsnd_dai_is_play(rdai, io) ?       info->ssi_id_playback :
+                                                       info->ssi_id_capture;
+       int ret;
+       unsigned long flags;
+
+       rsnd_lock(priv, flags);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               ret = rsnd_dai_stream_init(io, substream);
+               if (ret < 0)
+                       goto dai_trigger_end;
+
+               ret = rsnd_platform_call(priv, dai, start, ssi_id);
+               if (ret < 0)
+                       goto dai_trigger_end;
+
+               ret = rsnd_gen_path_init(priv, rdai, io);
+               if (ret < 0)
+                       goto dai_trigger_end;
+
+               ret = rsnd_dai_call(rdai, io, init);
+               if (ret < 0)
+                       goto dai_trigger_end;
+
+               ret = rsnd_dai_call(rdai, io, start);
+               if (ret < 0)
+                       goto dai_trigger_end;
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               ret = rsnd_dai_call(rdai, io, stop);
+               if (ret < 0)
+                       goto dai_trigger_end;
+
+               ret = rsnd_dai_call(rdai, io, quit);
+               if (ret < 0)
+                       goto dai_trigger_end;
+
+               ret = rsnd_gen_path_exit(priv, rdai, io);
+               if (ret < 0)
+                       goto dai_trigger_end;
+
+               ret = rsnd_platform_call(priv, dai, stop, ssi_id);
+               if (ret < 0)
+                       goto dai_trigger_end;
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+dai_trigger_end:
+       rsnd_unlock(priv, flags);
+
+       return ret;
+}
+
+static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
+
+       /* set master/slave audio interface */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               rdai->clk_master = 1;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               rdai->clk_master = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* set clock inversion */
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_IF:
+               rdai->bit_clk_inv = 0;
+               rdai->frm_clk_inv = 1;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               rdai->bit_clk_inv = 1;
+               rdai->frm_clk_inv = 0;
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               rdai->bit_clk_inv = 1;
+               rdai->frm_clk_inv = 1;
+               break;
+       case SND_SOC_DAIFMT_NB_NF:
+       default:
+               rdai->bit_clk_inv = 0;
+               rdai->frm_clk_inv = 0;
+               break;
+       }
+
+       /* set format */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               rdai->sys_delay = 0;
+               rdai->data_alignment = 0;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               rdai->sys_delay = 1;
+               rdai->data_alignment = 0;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               rdai->sys_delay = 1;
+               rdai->data_alignment = 1;
+               break;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
+       .trigger        = rsnd_soc_dai_trigger,
+       .set_fmt        = rsnd_soc_dai_set_fmt,
+};
+
+static int rsnd_dai_probe(struct platform_device *pdev,
+                         struct rcar_snd_info *info,
+                         struct rsnd_priv *priv)
+{
+       struct snd_soc_dai_driver *drv;
+       struct rsnd_dai *rdai;
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_dai_platform_info *dai_info;
+       int dai_nr = info->dai_info_nr;
+       int i, pid, cid;
+
+       drv  = devm_kzalloc(dev, sizeof(*drv)  * dai_nr, GFP_KERNEL);
+       rdai = devm_kzalloc(dev, sizeof(*rdai) * dai_nr, GFP_KERNEL);
+       if (!drv || !rdai) {
+               dev_err(dev, "dai allocate failed\n");
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < dai_nr; i++) {
+               dai_info = &info->dai_info[i];
+
+               pid = dai_info->ssi_id_playback;
+               cid = dai_info->ssi_id_capture;
+
+               /*
+                *      init rsnd_dai
+                */
+               INIT_LIST_HEAD(&rdai[i].playback.head);
+               INIT_LIST_HEAD(&rdai[i].capture.head);
+
+               rdai[i].info = dai_info;
+
+               snprintf(rdai[i].name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", i);
+
+               /*
+                *      init snd_soc_dai_driver
+                */
+               drv[i].name     = rdai[i].name;
+               drv[i].ops      = &rsnd_soc_dai_ops;
+               if (pid >= 0) {
+                       drv[i].playback.rates           = RSND_RATES;
+                       drv[i].playback.formats         = RSND_FMTS;
+                       drv[i].playback.channels_min    = 2;
+                       drv[i].playback.channels_max    = 2;
+               }
+               if (cid >= 0) {
+                       drv[i].capture.rates            = RSND_RATES;
+                       drv[i].capture.formats          = RSND_FMTS;
+                       drv[i].capture.channels_min     = 2;
+                       drv[i].capture.channels_max     = 2;
+               }
+
+               dev_dbg(dev, "%s (%d, %d) probed", rdai[i].name, pid, cid);
+       }
+
+       priv->dai_nr    = dai_nr;
+       priv->daidrv    = drv;
+       priv->rdai      = rdai;
+
+       return 0;
+}
+
+static void rsnd_dai_remove(struct platform_device *pdev,
+                         struct rsnd_priv *priv)
+{
+}
+
+/*
+ *             pcm ops
+ */
+static struct snd_pcm_hardware rsnd_pcm_hardware = {
+       .info =         SNDRV_PCM_INFO_INTERLEAVED      |
+                       SNDRV_PCM_INFO_MMAP             |
+                       SNDRV_PCM_INFO_MMAP_VALID       |
+                       SNDRV_PCM_INFO_PAUSE,
+       .formats                = RSND_FMTS,
+       .rates                  = RSND_RATES,
+       .rate_min               = 8000,
+       .rate_max               = 192000,
+       .channels_min           = 2,
+       .channels_max           = 2,
+       .buffer_bytes_max       = 64 * 1024,
+       .period_bytes_min       = 32,
+       .period_bytes_max       = 8192,
+       .periods_min            = 1,
+       .periods_max            = 32,
+       .fifo_size              = 256,
+};
+
+static int rsnd_pcm_open(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int ret = 0;
+
+       snd_soc_set_runtime_hwparams(substream, &rsnd_pcm_hardware);
+
+       ret = snd_pcm_hw_constraint_integer(runtime,
+                                           SNDRV_PCM_HW_PARAM_PERIODS);
+
+       return ret;
+}
+
+static int rsnd_hw_params(struct snd_pcm_substream *substream,
+                        struct snd_pcm_hw_params *hw_params)
+{
+       return snd_pcm_lib_malloc_pages(substream,
+                                       params_buffer_bytes(hw_params));
+}
+
+static snd_pcm_uframes_t rsnd_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_dai *dai = rsnd_substream_to_dai(substream);
+       struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
+       struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
+
+       return bytes_to_frames(runtime, io->byte_pos);
+}
+
+static struct snd_pcm_ops rsnd_pcm_ops = {
+       .open           = rsnd_pcm_open,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = rsnd_hw_params,
+       .hw_free        = snd_pcm_lib_free_pages,
+       .pointer        = rsnd_pointer,
+};
+
+/*
+ *             snd_soc_platform
+ */
+
+#define PREALLOC_BUFFER                (32 * 1024)
+#define PREALLOC_BUFFER_MAX    (32 * 1024)
+
+static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+       return snd_pcm_lib_preallocate_pages_for_all(
+               rtd->pcm,
+               SNDRV_DMA_TYPE_DEV,
+               rtd->card->snd_card->dev,
+               PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
+}
+
+static void rsnd_pcm_free(struct snd_pcm *pcm)
+{
+       snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static struct snd_soc_platform_driver rsnd_soc_platform = {
+       .ops            = &rsnd_pcm_ops,
+       .pcm_new        = rsnd_pcm_new,
+       .pcm_free       = rsnd_pcm_free,
+};
+
+static const struct snd_soc_component_driver rsnd_soc_component = {
+       .name           = "rsnd",
+};
+
+/*
+ *     rsnd probe
+ */
+static int rsnd_probe(struct platform_device *pdev)
+{
+       struct rcar_snd_info *info;
+       struct rsnd_priv *priv;
+       struct device *dev = &pdev->dev;
+       int ret;
+
+       info = pdev->dev.platform_data;
+       if (!info) {
+               dev_err(dev, "driver needs R-Car sound information\n");
+               return -ENODEV;
+       }
+
+       /*
+        *      init priv data
+        */
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv) {
+               dev_err(dev, "priv allocate failed\n");
+               return -ENODEV;
+       }
+
+       priv->dev       = dev;
+       priv->info      = info;
+       spin_lock_init(&priv->lock);
+
+       /*
+        *      init each module
+        */
+       ret = rsnd_gen_probe(pdev, info, priv);
+       if (ret < 0)
+               return ret;
+
+       ret = rsnd_dai_probe(pdev, info, priv);
+       if (ret < 0)
+               return ret;
+
+       ret = rsnd_scu_probe(pdev, info, priv);
+       if (ret < 0)
+               return ret;
+
+       ret = rsnd_adg_probe(pdev, info, priv);
+       if (ret < 0)
+               return ret;
+
+       ret = rsnd_ssi_probe(pdev, info, priv);
+       if (ret < 0)
+               return ret;
+
+       /*
+        *      asoc register
+        */
+       ret = snd_soc_register_platform(dev, &rsnd_soc_platform);
+       if (ret < 0) {
+               dev_err(dev, "cannot snd soc register\n");
+               return ret;
+       }
+
+       ret = snd_soc_register_component(dev, &rsnd_soc_component,
+                                        priv->daidrv, rsnd_dai_nr(priv));
+       if (ret < 0) {
+               dev_err(dev, "cannot snd dai register\n");
+               goto exit_snd_soc;
+       }
+
+       dev_set_drvdata(dev, priv);
+
+       pm_runtime_enable(dev);
+
+       dev_info(dev, "probed\n");
+       return ret;
+
+exit_snd_soc:
+       snd_soc_unregister_platform(dev);
+
+       return ret;
+}
+
+static int rsnd_remove(struct platform_device *pdev)
+{
+       struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev);
+
+       pm_runtime_disable(&pdev->dev);
+
+       /*
+        *      remove each module
+        */
+       rsnd_ssi_remove(pdev, priv);
+       rsnd_adg_remove(pdev, priv);
+       rsnd_scu_remove(pdev, priv);
+       rsnd_dai_remove(pdev, priv);
+       rsnd_gen_remove(pdev, priv);
+
+       return 0;
+}
+
+static struct platform_driver rsnd_driver = {
+       .driver = {
+               .name   = "rcar_sound",
+       },
+       .probe          = rsnd_probe,
+       .remove         = rsnd_remove,
+};
+module_platform_driver(rsnd_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Renesas R-Car audio driver");
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
+MODULE_ALIAS("platform:rcar-pcm-audio");
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
new file mode 100644 (file)
index 0000000..61232cd
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+ * Renesas R-Car Gen1 SRU/SSI support
+ *
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include "rsnd.h"
+
+struct rsnd_gen_ops {
+       int (*path_init)(struct rsnd_priv *priv,
+                        struct rsnd_dai *rdai,
+                        struct rsnd_dai_stream *io);
+       int (*path_exit)(struct rsnd_priv *priv,
+                        struct rsnd_dai *rdai,
+                        struct rsnd_dai_stream *io);
+};
+
+struct rsnd_gen_reg_map {
+       int index;      /* -1 : not supported */
+       u32 offset_id;  /* offset of ssi0, ssi1, ssi2... */
+       u32 offset_adr; /* offset of SSICR, SSISR, ... */
+};
+
+struct rsnd_gen {
+       void __iomem *base[RSND_BASE_MAX];
+
+       struct rsnd_gen_reg_map reg_map[RSND_REG_MAX];
+       struct rsnd_gen_ops *ops;
+};
+
+#define rsnd_priv_to_gen(p)    ((struct rsnd_gen *)(p)->gen)
+
+#define rsnd_is_gen1(s)                ((s)->info->flags & RSND_GEN1)
+#define rsnd_is_gen2(s)                ((s)->info->flags & RSND_GEN2)
+
+/*
+ *             Gen2
+ *             will be filled in the future
+ */
+
+/*
+ *             Gen1
+ */
+static int rsnd_gen1_path_init(struct rsnd_priv *priv,
+                              struct rsnd_dai *rdai,
+                              struct rsnd_dai_stream *io)
+{
+       struct rsnd_dai_platform_info *info = rsnd_dai_get_platform_info(rdai);
+       struct rsnd_mod *mod;
+       int ret;
+       int id;
+
+       /*
+        * Gen1 is created by SRU/SSI, and this SRU is base module of
+        * Gen2's SCU/SSIU/SSI. (Gen2 SCU/SSIU came from SRU)
+        *
+        * Easy image is..
+        *      Gen1 SRU = Gen2 SCU + SSIU + etc
+        *
+        * Gen2 SCU path is very flexible, but, Gen1 SRU (SCU parts) is
+        * using fixed path.
+        *
+        * Then, SSI id = SCU id here
+        */
+
+       if (rsnd_dai_is_play(rdai, io))
+               id = info->ssi_id_playback;
+       else
+               id = info->ssi_id_capture;
+
+       /* SSI */
+       mod = rsnd_ssi_mod_get(priv, id);
+       ret = rsnd_dai_connect(rdai, mod, io);
+       if (ret < 0)
+               return ret;
+
+       /* SCU */
+       mod = rsnd_scu_mod_get(priv, id);
+       ret = rsnd_dai_connect(rdai, mod, io);
+
+       return ret;
+}
+
+static int rsnd_gen1_path_exit(struct rsnd_priv *priv,
+                              struct rsnd_dai *rdai,
+                              struct rsnd_dai_stream *io)
+{
+       struct rsnd_mod *mod, *n;
+       int ret = 0;
+
+       /*
+        * remove all mod from rdai
+        */
+       for_each_rsnd_mod(mod, n, io)
+               ret |= rsnd_dai_disconnect(mod);
+
+       return ret;
+}
+
+static struct rsnd_gen_ops rsnd_gen1_ops = {
+       .path_init      = rsnd_gen1_path_init,
+       .path_exit      = rsnd_gen1_path_exit,
+};
+
+#define RSND_GEN1_REG_MAP(g, s, i, oi, oa)                             \
+       do {                                                            \
+               (g)->reg_map[RSND_REG_##i].index  = RSND_GEN1_##s;      \
+               (g)->reg_map[RSND_REG_##i].offset_id = oi;              \
+               (g)->reg_map[RSND_REG_##i].offset_adr = oa;             \
+       } while (0)
+
+static void rsnd_gen1_reg_map_init(struct rsnd_gen *gen)
+{
+       RSND_GEN1_REG_MAP(gen, SRU,     SSI_MODE0,      0x0,    0xD0);
+       RSND_GEN1_REG_MAP(gen, SRU,     SSI_MODE1,      0x0,    0xD4);
+
+       RSND_GEN1_REG_MAP(gen, ADG,     BRRA,           0x0,    0x00);
+       RSND_GEN1_REG_MAP(gen, ADG,     BRRB,           0x0,    0x04);
+       RSND_GEN1_REG_MAP(gen, ADG,     SSICKR,         0x0,    0x08);
+       RSND_GEN1_REG_MAP(gen, ADG,     AUDIO_CLK_SEL0, 0x0,    0x0c);
+       RSND_GEN1_REG_MAP(gen, ADG,     AUDIO_CLK_SEL1, 0x0,    0x10);
+       RSND_GEN1_REG_MAP(gen, ADG,     AUDIO_CLK_SEL3, 0x0,    0x18);
+       RSND_GEN1_REG_MAP(gen, ADG,     AUDIO_CLK_SEL4, 0x0,    0x1c);
+       RSND_GEN1_REG_MAP(gen, ADG,     AUDIO_CLK_SEL5, 0x0,    0x20);
+
+       RSND_GEN1_REG_MAP(gen, SSI,     SSICR,          0x40,   0x00);
+       RSND_GEN1_REG_MAP(gen, SSI,     SSISR,          0x40,   0x04);
+       RSND_GEN1_REG_MAP(gen, SSI,     SSITDR,         0x40,   0x08);
+       RSND_GEN1_REG_MAP(gen, SSI,     SSIRDR,         0x40,   0x0c);
+       RSND_GEN1_REG_MAP(gen, SSI,     SSIWSR,         0x40,   0x20);
+}
+
+static int rsnd_gen1_probe(struct platform_device *pdev,
+                          struct rcar_snd_info *info,
+                          struct rsnd_priv *priv)
+{
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+       struct resource *sru_res;
+       struct resource *adg_res;
+       struct resource *ssi_res;
+
+       /*
+        * map address
+        */
+       sru_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SRU);
+       adg_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_ADG);
+       ssi_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SSI);
+
+       gen->base[RSND_GEN1_SRU] = devm_ioremap_resource(dev, sru_res);
+       gen->base[RSND_GEN1_ADG] = devm_ioremap_resource(dev, adg_res);
+       gen->base[RSND_GEN1_SSI] = devm_ioremap_resource(dev, ssi_res);
+       if (IS_ERR(gen->base[RSND_GEN1_SRU]) ||
+           IS_ERR(gen->base[RSND_GEN1_ADG]) ||
+           IS_ERR(gen->base[RSND_GEN1_SSI]))
+               return -ENODEV;
+
+       gen->ops = &rsnd_gen1_ops;
+       rsnd_gen1_reg_map_init(gen);
+
+       dev_dbg(dev, "Gen1 device probed\n");
+       dev_dbg(dev, "SRU : %08x => %p\n",      sru_res->start,
+                                               gen->base[RSND_GEN1_SRU]);
+       dev_dbg(dev, "ADG : %08x => %p\n",      adg_res->start,
+                                               gen->base[RSND_GEN1_ADG]);
+       dev_dbg(dev, "SSI : %08x => %p\n",      ssi_res->start,
+                                               gen->base[RSND_GEN1_SSI]);
+
+       return 0;
+
+}
+
+static void rsnd_gen1_remove(struct platform_device *pdev,
+                            struct rsnd_priv *priv)
+{
+}
+
+/*
+ *             Gen
+ */
+int rsnd_gen_path_init(struct rsnd_priv *priv,
+                      struct rsnd_dai *rdai,
+                      struct rsnd_dai_stream *io)
+{
+       struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+
+       return gen->ops->path_init(priv, rdai, io);
+}
+
+int rsnd_gen_path_exit(struct rsnd_priv *priv,
+                      struct rsnd_dai *rdai,
+                      struct rsnd_dai_stream *io)
+{
+       struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+
+       return gen->ops->path_exit(priv, rdai, io);
+}
+
+void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
+                              struct rsnd_mod *mod,
+                              enum rsnd_reg reg)
+{
+       struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       int index;
+       u32 offset_id, offset_adr;
+
+       if (reg >= RSND_REG_MAX) {
+               dev_err(dev, "rsnd_reg reg error\n");
+               return NULL;
+       }
+
+       index           = gen->reg_map[reg].index;
+       offset_id       = gen->reg_map[reg].offset_id;
+       offset_adr      = gen->reg_map[reg].offset_adr;
+
+       if (index < 0) {
+               dev_err(dev, "unsupported reg access %d\n", reg);
+               return NULL;
+       }
+
+       if (offset_id && mod)
+               offset_id *= rsnd_mod_id(mod);
+
+       /*
+        * index/offset were set on gen1/gen2
+        */
+
+       return gen->base[index] + offset_id + offset_adr;
+}
+
+int rsnd_gen_probe(struct platform_device *pdev,
+                  struct rcar_snd_info *info,
+                  struct rsnd_priv *priv)
+{
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_gen *gen;
+       int i;
+
+       gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL);
+       if (!gen) {
+               dev_err(dev, "GEN allocate failed\n");
+               return -ENOMEM;
+       }
+
+       priv->gen = gen;
+
+       /*
+        * see
+        *      rsnd_reg_get()
+        *      rsnd_gen_probe()
+        */
+       for (i = 0; i < RSND_REG_MAX; i++)
+               gen->reg_map[i].index = -1;
+
+       /*
+        *      init each module
+        */
+       if (rsnd_is_gen1(priv))
+               return rsnd_gen1_probe(pdev, info, priv);
+
+       dev_err(dev, "unknown generation R-Car sound device\n");
+
+       return -ENODEV;
+}
+
+void rsnd_gen_remove(struct platform_device *pdev,
+                    struct rsnd_priv *priv)
+{
+       if (rsnd_is_gen1(priv))
+               rsnd_gen1_remove(pdev, priv);
+}
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
new file mode 100644 (file)
index 0000000..0e7727c
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * Renesas R-Car
+ *
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef RSND_H
+#define RSND_H
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <sound/rcar_snd.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+
+/*
+ *     pseudo register
+ *
+ * The register address offsets SRU/SCU/SSIU on Gen1/Gen2 are very different.
+ * This driver uses pseudo register in order to hide it.
+ * see gen1/gen2 for detail
+ */
+enum rsnd_reg {
+       /* SRU/SCU */
+       RSND_REG_SSI_MODE0,
+       RSND_REG_SSI_MODE1,
+
+       /* ADG */
+       RSND_REG_BRRA,
+       RSND_REG_BRRB,
+       RSND_REG_SSICKR,
+       RSND_REG_AUDIO_CLK_SEL0,
+       RSND_REG_AUDIO_CLK_SEL1,
+       RSND_REG_AUDIO_CLK_SEL2,
+       RSND_REG_AUDIO_CLK_SEL3,
+       RSND_REG_AUDIO_CLK_SEL4,
+       RSND_REG_AUDIO_CLK_SEL5,
+
+       /* SSI */
+       RSND_REG_SSICR,
+       RSND_REG_SSISR,
+       RSND_REG_SSITDR,
+       RSND_REG_SSIRDR,
+       RSND_REG_SSIWSR,
+
+       RSND_REG_MAX,
+};
+
+struct rsnd_priv;
+struct rsnd_mod;
+struct rsnd_dai;
+struct rsnd_dai_stream;
+
+/*
+ *     R-Car basic functions
+ */
+#define rsnd_mod_read(m, r) \
+       rsnd_read(rsnd_mod_to_priv(m), m, RSND_REG_##r)
+#define rsnd_mod_write(m, r, d) \
+       rsnd_write(rsnd_mod_to_priv(m), m, RSND_REG_##r, d)
+#define rsnd_mod_bset(m, r, s, d) \
+       rsnd_bset(rsnd_mod_to_priv(m), m, RSND_REG_##r, s, d)
+
+#define rsnd_priv_read(p, r)           rsnd_read(p, NULL, RSND_REG_##r)
+#define rsnd_priv_write(p, r, d)       rsnd_write(p, NULL, RSND_REG_##r, d)
+#define rsnd_priv_bset(p, r, s, d)     rsnd_bset(p, NULL, RSND_REG_##r, s, d)
+
+u32 rsnd_read(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg);
+void rsnd_write(struct rsnd_priv *priv, struct rsnd_mod *mod,
+               enum rsnd_reg reg, u32 data);
+void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg,
+                   u32 mask, u32 data);
+
+/*
+ *     R-Car sound mod
+ */
+
+struct rsnd_mod_ops {
+       char *name;
+       int (*init)(struct rsnd_mod *mod,
+                   struct rsnd_dai *rdai,
+                   struct rsnd_dai_stream *io);
+       int (*quit)(struct rsnd_mod *mod,
+                   struct rsnd_dai *rdai,
+                   struct rsnd_dai_stream *io);
+       int (*start)(struct rsnd_mod *mod,
+                    struct rsnd_dai *rdai,
+                    struct rsnd_dai_stream *io);
+       int (*stop)(struct rsnd_mod *mod,
+                   struct rsnd_dai *rdai,
+                   struct rsnd_dai_stream *io);
+};
+
+struct rsnd_mod {
+       int id;
+       struct rsnd_priv *priv;
+       struct rsnd_mod_ops *ops;
+       struct list_head list; /* connect to rsnd_dai playback/capture */
+};
+
+#define rsnd_mod_to_priv(mod) ((mod)->priv)
+#define rsnd_mod_id(mod) ((mod)->id)
+#define for_each_rsnd_mod(pos, n, io)  \
+       list_for_each_entry_safe(pos, n, &(io)->head, list)
+#define rsnd_mod_call(mod, func, rdai, io)     \
+       (!(mod) ? -ENODEV :                     \
+        !((mod)->ops->func) ? 0 :              \
+        (mod)->ops->func(mod, rdai, io))
+
+void rsnd_mod_init(struct rsnd_priv *priv,
+                  struct rsnd_mod *mod,
+                  struct rsnd_mod_ops *ops,
+                  int id);
+char *rsnd_mod_name(struct rsnd_mod *mod);
+
+/*
+ *     R-Car sound DAI
+ */
+#define RSND_DAI_NAME_SIZE     16
+struct rsnd_dai_stream {
+       struct list_head head; /* head of rsnd_mod list */
+       struct snd_pcm_substream *substream;
+       int byte_pos;
+       int period_pos;
+       int byte_per_period;
+       int next_period_byte;
+};
+
+struct rsnd_dai {
+       char name[RSND_DAI_NAME_SIZE];
+       struct rsnd_dai_platform_info *info; /* rcar_snd.h */
+       struct rsnd_dai_stream playback;
+       struct rsnd_dai_stream capture;
+
+       int clk_master:1;
+       int bit_clk_inv:1;
+       int frm_clk_inv:1;
+       int sys_delay:1;
+       int data_alignment:1;
+};
+
+#define rsnd_dai_nr(priv) ((priv)->dai_nr)
+#define for_each_rsnd_dai(rdai, priv, i)               \
+       for (i = 0, (rdai) = rsnd_dai_get(priv, i);     \
+            i < rsnd_dai_nr(priv);                     \
+            i++, (rdai) = rsnd_dai_get(priv, i))
+
+struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id);
+int rsnd_dai_disconnect(struct rsnd_mod *mod);
+int rsnd_dai_connect(struct rsnd_dai *rdai, struct rsnd_mod *mod,
+                    struct rsnd_dai_stream *io);
+int rsnd_dai_is_play(struct rsnd_dai *rdai, struct rsnd_dai_stream *io);
+#define rsnd_dai_get_platform_info(rdai) ((rdai)->info)
+#define rsnd_io_to_runtime(io) ((io)->substream->runtime)
+
+void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt);
+int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional);
+
+/*
+ *     R-Car Gen1/Gen2
+ */
+int rsnd_gen_probe(struct platform_device *pdev,
+                  struct rcar_snd_info *info,
+                  struct rsnd_priv *priv);
+void rsnd_gen_remove(struct platform_device *pdev,
+                    struct rsnd_priv *priv);
+int rsnd_gen_path_init(struct rsnd_priv *priv,
+                      struct rsnd_dai *rdai,
+                      struct rsnd_dai_stream *io);
+int rsnd_gen_path_exit(struct rsnd_priv *priv,
+                      struct rsnd_dai *rdai,
+                      struct rsnd_dai_stream *io);
+void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
+                              struct rsnd_mod *mod,
+                              enum rsnd_reg reg);
+
+/*
+ *     R-Car ADG
+ */
+int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod);
+int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate);
+int rsnd_adg_probe(struct platform_device *pdev,
+                  struct rcar_snd_info *info,
+                  struct rsnd_priv *priv);
+void rsnd_adg_remove(struct platform_device *pdev,
+                  struct rsnd_priv *priv);
+
+/*
+ *     R-Car sound priv
+ */
+struct rsnd_priv {
+
+       struct device *dev;
+       struct rcar_snd_info *info;
+       spinlock_t lock;
+
+       /*
+        * below value will be filled on rsnd_gen_probe()
+        */
+       void *gen;
+
+       /*
+        * below value will be filled on rsnd_scu_probe()
+        */
+       void *scu;
+       int scu_nr;
+
+       /*
+        * below value will be filled on rsnd_adg_probe()
+        */
+       void *adg;
+
+       /*
+        * below value will be filled on rsnd_ssi_probe()
+        */
+       void *ssiu;
+
+       /*
+        * below value will be filled on rsnd_dai_probe()
+        */
+       struct snd_soc_dai_driver *daidrv;
+       struct rsnd_dai *rdai;
+       int dai_nr;
+};
+
+#define rsnd_priv_to_dev(priv) ((priv)->dev)
+#define rsnd_lock(priv, flags) spin_lock_irqsave(&priv->lock, flags)
+#define rsnd_unlock(priv, flags) spin_unlock_irqrestore(&priv->lock, flags)
+
+/*
+ *     R-Car SCU
+ */
+int rsnd_scu_probe(struct platform_device *pdev,
+                  struct rcar_snd_info *info,
+                  struct rsnd_priv *priv);
+void rsnd_scu_remove(struct platform_device *pdev,
+                    struct rsnd_priv *priv);
+struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id);
+#define rsnd_scu_nr(priv) ((priv)->scu_nr)
+
+/*
+ *     R-Car SSI
+ */
+int rsnd_ssi_probe(struct platform_device *pdev,
+                  struct rcar_snd_info *info,
+                  struct rsnd_priv *priv);
+void rsnd_ssi_remove(struct platform_device *pdev,
+                  struct rsnd_priv *priv);
+struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
+
+#endif
diff --git a/sound/soc/sh/rcar/scu.c b/sound/soc/sh/rcar/scu.c
new file mode 100644 (file)
index 0000000..c12e65f
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Renesas R-Car SCU support
+ *
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include "rsnd.h"
+
+struct rsnd_scu {
+       struct rsnd_scu_platform_info *info; /* rcar_snd.h */
+       struct rsnd_mod mod;
+};
+
+#define rsnd_mod_to_scu(_mod)  \
+       container_of((_mod), struct rsnd_scu, mod)
+
+#define for_each_rsnd_scu(pos, priv, i)                                        \
+       for ((i) = 0;                                                   \
+            ((i) < rsnd_scu_nr(priv)) &&                               \
+                    ((pos) = (struct rsnd_scu *)(priv)->scu + i);      \
+            i++)
+
+static int rsnd_scu_init(struct rsnd_mod *mod,
+                        struct rsnd_dai *rdai,
+                        struct rsnd_dai_stream *io)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+
+       dev_dbg(dev, "%s.%d init\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
+
+       return 0;
+}
+
+static int rsnd_scu_quit(struct rsnd_mod *mod,
+                        struct rsnd_dai *rdai,
+                        struct rsnd_dai_stream *io)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+
+       dev_dbg(dev, "%s.%d quit\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
+
+       return 0;
+}
+
+static int rsnd_scu_start(struct rsnd_mod *mod,
+                         struct rsnd_dai *rdai,
+                         struct rsnd_dai_stream *io)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+
+       dev_dbg(dev, "%s.%d start\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
+
+       return 0;
+}
+
+static int rsnd_scu_stop(struct rsnd_mod *mod,
+                        struct rsnd_dai *rdai,
+                        struct rsnd_dai_stream *io)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+
+       dev_dbg(dev, "%s.%d stop\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
+
+       return 0;
+}
+
+static struct rsnd_mod_ops rsnd_scu_ops = {
+       .name   = "scu",
+       .init   = rsnd_scu_init,
+       .quit   = rsnd_scu_quit,
+       .start  = rsnd_scu_start,
+       .stop   = rsnd_scu_stop,
+};
+
+struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id)
+{
+       BUG_ON(id < 0 || id >= rsnd_scu_nr(priv));
+
+       return &((struct rsnd_scu *)(priv->scu) + id)->mod;
+}
+
+int rsnd_scu_probe(struct platform_device *pdev,
+                  struct rcar_snd_info *info,
+                  struct rsnd_priv *priv)
+{
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_scu *scu;
+       int i, nr;
+
+       /*
+        * init SCU
+        */
+       nr      = info->scu_info_nr;
+       scu     = devm_kzalloc(dev, sizeof(*scu) * nr, GFP_KERNEL);
+       if (!scu) {
+               dev_err(dev, "SCU allocate failed\n");
+               return -ENOMEM;
+       }
+
+       priv->scu_nr    = nr;
+       priv->scu       = scu;
+
+       for_each_rsnd_scu(scu, priv, i) {
+               rsnd_mod_init(priv, &scu->mod,
+                             &rsnd_scu_ops, i);
+               scu->info = &info->scu_info[i];
+       }
+
+       dev_dbg(dev, "scu probed\n");
+
+       return 0;
+}
+
+void rsnd_scu_remove(struct platform_device *pdev,
+                    struct rsnd_priv *priv)
+{
+}
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
new file mode 100644 (file)
index 0000000..061ac7e
--- /dev/null
@@ -0,0 +1,588 @@
+/*
+ * Renesas R-Car SSIU/SSI support
+ *
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * Based on fsi.c
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/delay.h>
+#include "rsnd.h"
+#define RSND_SSI_NAME_SIZE 16
+
+/*
+ * SSICR
+ */
+#define        FORCE           (1 << 31)       /* Fixed */
+#define        UIEN            (1 << 27)       /* Underflow Interrupt Enable */
+#define        OIEN            (1 << 26)       /* Overflow Interrupt Enable */
+#define        IIEN            (1 << 25)       /* Idle Mode Interrupt Enable */
+#define        DIEN            (1 << 24)       /* Data Interrupt Enable */
+
+#define        DWL_8           (0 << 19)       /* Data Word Length */
+#define        DWL_16          (1 << 19)       /* Data Word Length */
+#define        DWL_18          (2 << 19)       /* Data Word Length */
+#define        DWL_20          (3 << 19)       /* Data Word Length */
+#define        DWL_22          (4 << 19)       /* Data Word Length */
+#define        DWL_24          (5 << 19)       /* Data Word Length */
+#define        DWL_32          (6 << 19)       /* Data Word Length */
+
+#define        SWL_32          (3 << 16)       /* R/W System Word Length */
+#define        SCKD            (1 << 15)       /* Serial Bit Clock Direction */
+#define        SWSD            (1 << 14)       /* Serial WS Direction */
+#define        SCKP            (1 << 13)       /* Serial Bit Clock Polarity */
+#define        SWSP            (1 << 12)       /* Serial WS Polarity */
+#define        SDTA            (1 << 10)       /* Serial Data Alignment */
+#define        DEL             (1 <<  8)       /* Serial Data Delay */
+#define        CKDV(v)         (v <<  4)       /* Serial Clock Division Ratio */
+#define        TRMD            (1 <<  1)       /* Transmit/Receive Mode Select */
+#define        EN              (1 <<  0)       /* SSI Module Enable */
+
+/*
+ * SSISR
+ */
+#define        UIRQ            (1 << 27)       /* Underflow Error Interrupt Status */
+#define        OIRQ            (1 << 26)       /* Overflow Error Interrupt Status */
+#define        IIRQ            (1 << 25)       /* Idle Mode Interrupt Status */
+#define        DIRQ            (1 << 24)       /* Data Interrupt Status Flag */
+
+struct rsnd_ssi {
+       struct clk *clk;
+       struct rsnd_ssi_platform_info *info; /* rcar_snd.h */
+       struct rsnd_ssi *parent;
+       struct rsnd_mod mod;
+
+       struct rsnd_dai *rdai;
+       struct rsnd_dai_stream *io;
+       u32 cr_own;
+       u32 cr_clk;
+       u32 cr_etc;
+       int err;
+       unsigned int usrcnt;
+       unsigned int rate;
+};
+
+struct rsnd_ssiu {
+       u32 ssi_mode0;
+       u32 ssi_mode1;
+
+       int ssi_nr;
+       struct rsnd_ssi *ssi;
+};
+
+#define for_each_rsnd_ssi(pos, priv, i)                                        \
+       for (i = 0;                                                     \
+            (i < rsnd_ssi_nr(priv)) &&                                 \
+               ((pos) = ((struct rsnd_ssiu *)((priv)->ssiu))->ssi + i); \
+            i++)
+
+#define rsnd_ssi_nr(priv) (((struct rsnd_ssiu *)((priv)->ssiu))->ssi_nr)
+#define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod)
+#define rsnd_ssi_is_pio(ssi) ((ssi)->info->pio_irq > 0)
+#define rsnd_ssi_clk_from_parent(ssi) ((ssi)->parent)
+#define rsnd_rdai_is_clk_master(rdai) ((rdai)->clk_master)
+#define rsnd_ssi_mode_flags(p) ((p)->info->flags)
+#define rsnd_ssi_to_ssiu(ssi)\
+       (((struct rsnd_ssiu *)((ssi) - rsnd_mod_id(&(ssi)->mod))) - 1)
+
+static void rsnd_ssi_mode_init(struct rsnd_priv *priv,
+                              struct rsnd_ssiu *ssiu)
+{
+       struct rsnd_ssi *ssi;
+       u32 flags;
+       u32 val;
+       int i;
+
+       /*
+        * SSI_MODE0
+        */
+       ssiu->ssi_mode0 = 0;
+       for_each_rsnd_ssi(ssi, priv, i)
+               ssiu->ssi_mode0 |= (1 << i);
+
+       /*
+        * SSI_MODE1
+        */
+#define ssi_parent_set(p, sync, adg, ext)              \
+       do {                                            \
+               ssi->parent = ssiu->ssi + p;            \
+               if (flags & RSND_SSI_CLK_FROM_ADG)      \
+                       val = adg;                      \
+               else                                    \
+                       val = ext;                      \
+               if (flags & RSND_SSI_SYNC)              \
+                       val |= sync;                    \
+       } while (0)
+
+       ssiu->ssi_mode1 = 0;
+       for_each_rsnd_ssi(ssi, priv, i) {
+               flags = rsnd_ssi_mode_flags(ssi);
+
+               if (!(flags & RSND_SSI_CLK_PIN_SHARE))
+                       continue;
+
+               val = 0;
+               switch (i) {
+               case 1:
+                       ssi_parent_set(0, (1 << 4), (0x2 << 0), (0x1 << 0));
+                       break;
+               case 2:
+                       ssi_parent_set(0, (1 << 4), (0x2 << 2), (0x1 << 2));
+                       break;
+               case 4:
+                       ssi_parent_set(3, (1 << 20), (0x2 << 16), (0x1 << 16));
+                       break;
+               case 8:
+                       ssi_parent_set(7, 0, 0, 0);
+                       break;
+               }
+
+               ssiu->ssi_mode1 |= val;
+       }
+}
+
+static void rsnd_ssi_mode_set(struct rsnd_ssi *ssi)
+{
+       struct rsnd_ssiu *ssiu = rsnd_ssi_to_ssiu(ssi);
+
+       rsnd_mod_write(&ssi->mod, SSI_MODE0, ssiu->ssi_mode0);
+       rsnd_mod_write(&ssi->mod, SSI_MODE1, ssiu->ssi_mode1);
+}
+
+static void rsnd_ssi_status_check(struct rsnd_mod *mod,
+                                 u32 bit)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       u32 status;
+       int i;
+
+       for (i = 0; i < 1024; i++) {
+               status = rsnd_mod_read(mod, SSISR);
+               if (status & bit)
+                       return;
+
+               udelay(50);
+       }
+
+       dev_warn(dev, "status check failed\n");
+}
+
+static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
+                                    unsigned int rate)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       int i, j, ret;
+       int adg_clk_div_table[] = {
+               1, 6, /* see adg.c */
+       };
+       int ssi_clk_mul_table[] = {
+               1, 2, 4, 8, 16, 6, 12,
+       };
+       unsigned int main_rate;
+
+       /*
+        * Find best clock, and try to start ADG
+        */
+       for (i = 0; i < ARRAY_SIZE(adg_clk_div_table); i++) {
+               for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) {
+
+                       /*
+                        * this driver is assuming that
+                        * system word is 64fs (= 2 x 32bit)
+                        * see rsnd_ssi_start()
+                        */
+                       main_rate = rate / adg_clk_div_table[i]
+                               * 32 * 2 * ssi_clk_mul_table[j];
+
+                       ret = rsnd_adg_ssi_clk_try_start(&ssi->mod, main_rate);
+                       if (0 == ret) {
+                               ssi->rate       = rate;
+                               ssi->cr_clk     = FORCE | SWL_32 |
+                                                 SCKD | SWSD | CKDV(j);
+
+                               dev_dbg(dev, "ssi%d outputs %u Hz\n",
+                                       rsnd_mod_id(&ssi->mod), rate);
+
+                               return 0;
+                       }
+               }
+       }
+
+       dev_err(dev, "unsupported clock rate\n");
+       return -EIO;
+}
+
+static void rsnd_ssi_master_clk_stop(struct rsnd_ssi *ssi)
+{
+       ssi->rate = 0;
+       ssi->cr_clk = 0;
+       rsnd_adg_ssi_clk_stop(&ssi->mod);
+}
+
+static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
+                             struct rsnd_dai *rdai,
+                             struct rsnd_dai_stream *io)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       u32 cr;
+
+       if (0 == ssi->usrcnt) {
+               clk_enable(ssi->clk);
+
+               if (rsnd_rdai_is_clk_master(rdai)) {
+                       struct snd_pcm_runtime *runtime;
+
+                       runtime = rsnd_io_to_runtime(io);
+
+                       if (rsnd_ssi_clk_from_parent(ssi))
+                               rsnd_ssi_hw_start(ssi->parent, rdai, io);
+                       else
+                               rsnd_ssi_master_clk_start(ssi, runtime->rate);
+               }
+       }
+
+       cr  =   ssi->cr_own     |
+               ssi->cr_clk     |
+               ssi->cr_etc     |
+               EN;
+
+       rsnd_mod_write(&ssi->mod, SSICR, cr);
+
+       ssi->usrcnt++;
+
+       dev_dbg(dev, "ssi%d hw started\n", rsnd_mod_id(&ssi->mod));
+}
+
+static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi,
+                            struct rsnd_dai *rdai)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       u32 cr;
+
+       if (0 == ssi->usrcnt) /* stop might be called without start */
+               return;
+
+       ssi->usrcnt--;
+
+       if (0 == ssi->usrcnt) {
+               /*
+                * disable all IRQ,
+                * and, wait all data was sent
+                */
+               cr  =   ssi->cr_own     |
+                       ssi->cr_clk;
+
+               rsnd_mod_write(&ssi->mod, SSICR, cr | EN);
+               rsnd_ssi_status_check(&ssi->mod, DIRQ);
+
+               /*
+                * disable SSI,
+                * and, wait idle state
+                */
+               rsnd_mod_write(&ssi->mod, SSICR, cr);   /* disabled all */
+               rsnd_ssi_status_check(&ssi->mod, IIRQ);
+
+               if (rsnd_rdai_is_clk_master(rdai)) {
+                       if (rsnd_ssi_clk_from_parent(ssi))
+                               rsnd_ssi_hw_stop(ssi->parent, rdai);
+                       else
+                               rsnd_ssi_master_clk_stop(ssi);
+               }
+
+               clk_disable(ssi->clk);
+       }
+
+       dev_dbg(dev, "ssi%d hw stopped\n", rsnd_mod_id(&ssi->mod));
+}
+
+/*
+ *     SSI mod common functions
+ */
+static int rsnd_ssi_init(struct rsnd_mod *mod,
+                        struct rsnd_dai *rdai,
+                        struct rsnd_dai_stream *io)
+{
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+       u32 cr;
+
+       cr = FORCE;
+
+       /*
+        * always use 32bit system word for easy clock calculation.
+        * see also rsnd_ssi_master_clk_enable()
+        */
+       cr |= SWL_32;
+
+       /*
+        * init clock settings for SSICR
+        */
+       switch (runtime->sample_bits) {
+       case 16:
+               cr |= DWL_16;
+               break;
+       case 32:
+               cr |= DWL_24;
+               break;
+       default:
+               return -EIO;
+       }
+
+       if (rdai->bit_clk_inv)
+               cr |= SCKP;
+       if (rdai->frm_clk_inv)
+               cr |= SWSP;
+       if (rdai->data_alignment)
+               cr |= SDTA;
+       if (rdai->sys_delay)
+               cr |= DEL;
+       if (rsnd_dai_is_play(rdai, io))
+               cr |= TRMD;
+
+       /*
+        * set ssi parameter
+        */
+       ssi->rdai       = rdai;
+       ssi->io         = io;
+       ssi->cr_own     = cr;
+       ssi->err        = -1; /* ignore 1st error */
+
+       rsnd_ssi_mode_set(ssi);
+
+       dev_dbg(dev, "%s.%d init\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
+
+       return 0;
+}
+
+static int rsnd_ssi_quit(struct rsnd_mod *mod,
+                        struct rsnd_dai *rdai,
+                        struct rsnd_dai_stream *io)
+{
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+
+       dev_dbg(dev, "%s.%d quit\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
+
+       if (ssi->err > 0)
+               dev_warn(dev, "ssi under/over flow err = %d\n", ssi->err);
+
+       ssi->rdai       = NULL;
+       ssi->io         = NULL;
+       ssi->cr_own     = 0;
+       ssi->err        = 0;
+
+       return 0;
+}
+
+static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status)
+{
+       /* under/over flow error */
+       if (status & (UIRQ | OIRQ)) {
+               ssi->err++;
+
+               /* clear error status */
+               rsnd_mod_write(&ssi->mod, SSISR, 0);
+       }
+}
+
+/*
+ *             SSI PIO
+ */
+static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data)
+{
+       struct rsnd_ssi *ssi = data;
+       struct rsnd_dai_stream *io = ssi->io;
+       u32 status = rsnd_mod_read(&ssi->mod, SSISR);
+       irqreturn_t ret = IRQ_NONE;
+
+       if (io && (status & DIRQ)) {
+               struct rsnd_dai *rdai = ssi->rdai;
+               struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+               u32 *buf = (u32 *)(runtime->dma_area +
+                                  rsnd_dai_pointer_offset(io, 0));
+
+               rsnd_ssi_record_error(ssi, status);
+
+               /*
+                * 8/16/32 data can be assesse to TDR/RDR register
+                * directly as 32bit data
+                * see rsnd_ssi_init()
+                */
+               if (rsnd_dai_is_play(rdai, io))
+                       rsnd_mod_write(&ssi->mod, SSITDR, *buf);
+               else
+                       *buf = rsnd_mod_read(&ssi->mod, SSIRDR);
+
+               rsnd_dai_pointer_update(io, sizeof(*buf));
+
+               ret = IRQ_HANDLED;
+       }
+
+       return ret;
+}
+
+static int rsnd_ssi_pio_start(struct rsnd_mod *mod,
+                             struct rsnd_dai *rdai,
+                             struct rsnd_dai_stream *io)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+
+       /* enable PIO IRQ */
+       ssi->cr_etc = UIEN | OIEN | DIEN;
+
+       rsnd_ssi_hw_start(ssi, rdai, io);
+
+       dev_dbg(dev, "%s.%d start\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
+
+       return 0;
+}
+
+static int rsnd_ssi_pio_stop(struct rsnd_mod *mod,
+                            struct rsnd_dai *rdai,
+                            struct rsnd_dai_stream *io)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+
+       dev_dbg(dev, "%s.%d stop\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
+
+       ssi->cr_etc = 0;
+
+       rsnd_ssi_hw_stop(ssi, rdai);
+
+       return 0;
+}
+
+static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
+       .name   = "ssi (pio)",
+       .init   = rsnd_ssi_init,
+       .quit   = rsnd_ssi_quit,
+       .start  = rsnd_ssi_pio_start,
+       .stop   = rsnd_ssi_pio_stop,
+};
+
+/*
+ *             Non SSI
+ */
+static int rsnd_ssi_non(struct rsnd_mod *mod,
+                       struct rsnd_dai *rdai,
+                       struct rsnd_dai_stream *io)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       return 0;
+}
+
+static struct rsnd_mod_ops rsnd_ssi_non_ops = {
+       .name   = "ssi (non)",
+       .init   = rsnd_ssi_non,
+       .quit   = rsnd_ssi_non,
+       .start  = rsnd_ssi_non,
+       .stop   = rsnd_ssi_non,
+};
+
+/*
+ *             ssi mod function
+ */
+struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id)
+{
+       BUG_ON(id < 0 || id >= rsnd_ssi_nr(priv));
+
+       return &(((struct rsnd_ssiu *)(priv->ssiu))->ssi + id)->mod;
+}
+
+int rsnd_ssi_probe(struct platform_device *pdev,
+                  struct rcar_snd_info *info,
+                  struct rsnd_priv *priv)
+{
+       struct rsnd_ssi_platform_info *pinfo;
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_mod_ops *ops;
+       struct clk *clk;
+       struct rsnd_ssiu *ssiu;
+       struct rsnd_ssi *ssi;
+       char name[RSND_SSI_NAME_SIZE];
+       int i, nr, ret;
+
+       /*
+        *      init SSI
+        */
+       nr      = info->ssi_info_nr;
+       ssiu    = devm_kzalloc(dev, sizeof(*ssiu) + (sizeof(*ssi) * nr),
+                              GFP_KERNEL);
+       if (!ssiu) {
+               dev_err(dev, "SSI allocate failed\n");
+               return -ENOMEM;
+       }
+
+       priv->ssiu      = ssiu;
+       ssiu->ssi       = (struct rsnd_ssi *)(ssiu + 1);
+       ssiu->ssi_nr    = nr;
+
+       for_each_rsnd_ssi(ssi, priv, i) {
+               pinfo = &info->ssi_info[i];
+
+               snprintf(name, RSND_SSI_NAME_SIZE, "ssi.%d", i);
+
+               clk = clk_get(dev, name);
+               if (IS_ERR(clk))
+                       return PTR_ERR(clk);
+
+               ssi->info       = pinfo;
+               ssi->clk        = clk;
+
+               ops = &rsnd_ssi_non_ops;
+
+               /*
+                * SSI PIO case
+                */
+               if (rsnd_ssi_is_pio(ssi)) {
+                       ret = devm_request_irq(dev, pinfo->pio_irq,
+                                              &rsnd_ssi_pio_interrupt,
+                                              IRQF_SHARED,
+                                              dev_name(dev), ssi);
+                       if (ret) {
+                               dev_err(dev, "SSI request interrupt failed\n");
+                               return ret;
+                       }
+
+                       ops     = &rsnd_ssi_pio_ops;
+               }
+
+               rsnd_mod_init(priv, &ssi->mod, ops, i);
+       }
+
+       rsnd_ssi_mode_init(priv, ssiu);
+
+       dev_dbg(dev, "ssi probed\n");
+
+       return 0;
+}
+
+void rsnd_ssi_remove(struct platform_device *pdev,
+                  struct rsnd_priv *priv)
+{
+       struct rsnd_ssi *ssi;
+       int i;
+
+       for_each_rsnd_ssi(ssi, priv, i)
+               clk_put(ssi->clk);
+}
index 06a8000aa07bedd1c47beb401d26e9052512fc54..d22015074670c4bef44a6814b01d8f20c031d5d2 100644 (file)
@@ -334,7 +334,7 @@ static int soc_compr_copy(struct snd_compr_stream *cstream,
        return ret;
 }
 
-static int sst_compr_set_metadata(struct snd_compr_stream *cstream,
+static int soc_compr_set_metadata(struct snd_compr_stream *cstream,
                                struct snd_compr_metadata *metadata)
 {
        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
@@ -347,7 +347,7 @@ static int sst_compr_set_metadata(struct snd_compr_stream *cstream,
        return ret;
 }
 
-static int sst_compr_get_metadata(struct snd_compr_stream *cstream,
+static int soc_compr_get_metadata(struct snd_compr_stream *cstream,
                                struct snd_compr_metadata *metadata)
 {
        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
@@ -364,8 +364,8 @@ static struct snd_compr_ops soc_compr_ops = {
        .open           = soc_compr_open,
        .free           = soc_compr_free,
        .set_params     = soc_compr_set_params,
-       .set_metadata   = sst_compr_set_metadata,
-       .get_metadata   = sst_compr_get_metadata,
+       .set_metadata   = soc_compr_set_metadata,
+       .get_metadata   = soc_compr_get_metadata,
        .get_params     = soc_compr_get_params,
        .trigger        = soc_compr_trigger,
        .pointer        = soc_compr_pointer,
index d82ee386eab564d352eccd4209dff767b222e6f3..21f0e6a8118bd90d15c0cfc4f7922f489f1a9a3c 100644 (file)
@@ -192,7 +192,7 @@ static ssize_t pmdown_time_set(struct device *dev,
        struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
        int ret;
 
-       ret = strict_strtol(buf, 10, &rtd->pmdown_time);
+       ret = kstrtol(buf, 10, &rtd->pmdown_time);
        if (ret)
                return ret;
 
@@ -237,6 +237,7 @@ static ssize_t codec_reg_write_file(struct file *file,
        char *start = buf;
        unsigned long reg, value;
        struct snd_soc_codec *codec = file->private_data;
+       int ret;
 
        buf_size = min(count, (sizeof(buf)-1));
        if (copy_from_user(buf, user_buf, buf_size))
@@ -248,8 +249,9 @@ static ssize_t codec_reg_write_file(struct file *file,
        reg = simple_strtoul(start, &start, 16);
        while (*start == ' ')
                start++;
-       if (strict_strtoul(start, 16, &value))
-               return -EINVAL;
+       ret = kstrtoul(start, 16, &value);
+       if (ret)
+               return ret;
 
        /* Userspace has been fiddling around behind the kernel's back */
        add_taint(TAINT_USER, LOCKDEP_NOW_UNRELIABLE);
@@ -2299,6 +2301,22 @@ static int snd_soc_add_controls(struct snd_card *card, struct device *dev,
        return 0;
 }
 
+struct snd_kcontrol *snd_soc_card_get_kcontrol(struct snd_soc_card *soc_card,
+                                              const char *name)
+{
+       struct snd_card *card = soc_card->snd_card;
+       struct snd_kcontrol *kctl;
+
+       if (unlikely(!name))
+               return NULL;
+
+       list_for_each_entry(kctl, &card->controls, list)
+               if (!strncmp(kctl->id.name, name, sizeof(kctl->id.name)))
+                       return kctl;
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_card_get_kcontrol);
+
 /**
  * snd_soc_add_codec_controls - add an array of controls to a codec.
  * Convenience function to add a list of controls. Many codecs were
index b94190820e8cfa1b6c24e925f176196cc5efff98..d74c3560d556cc45dbb9191ccd74705258c7107d 100644 (file)
@@ -174,36 +174,118 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
        return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
 }
 
-/* get snd_card from DAPM context */
-static inline struct snd_card *dapm_get_snd_card(
-       struct snd_soc_dapm_context *dapm)
+struct dapm_kcontrol_data {
+       unsigned int value;
+       struct list_head paths;
+       struct snd_soc_dapm_widget_list wlist;
+};
+
+static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
+       struct snd_kcontrol *kcontrol)
 {
-       if (dapm->codec)
-               return dapm->codec->card->snd_card;
-       else if (dapm->platform)
-               return dapm->platform->card->snd_card;
-       else
-               BUG();
+       struct dapm_kcontrol_data *data;
 
-       /* unreachable */
-       return NULL;
+       data = kzalloc(sizeof(*data) + sizeof(widget), GFP_KERNEL);
+       if (!data) {
+               dev_err(widget->dapm->dev,
+                               "ASoC: can't allocate kcontrol data for %s\n",
+                               widget->name);
+               return -ENOMEM;
+       }
+
+       data->wlist.widgets[0] = widget;
+       data->wlist.num_widgets = 1;
+       INIT_LIST_HEAD(&data->paths);
+
+       kcontrol->private_data = data;
+
+       return 0;
 }
 
-/* get soc_card from DAPM context */
-static inline struct snd_soc_card *dapm_get_soc_card(
-               struct snd_soc_dapm_context *dapm)
+static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
 {
-       if (dapm->codec)
-               return dapm->codec->card;
-       else if (dapm->platform)
-               return dapm->platform->card;
-       else
-               BUG();
+       struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl);
+       kfree(data);
+}
 
-       /* unreachable */
-       return NULL;
+static struct snd_soc_dapm_widget_list *dapm_kcontrol_get_wlist(
+       const struct snd_kcontrol *kcontrol)
+{
+       struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
+
+       return &data->wlist;
+}
+
+static int dapm_kcontrol_add_widget(struct snd_kcontrol *kcontrol,
+       struct snd_soc_dapm_widget *widget)
+{
+       struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
+       struct dapm_kcontrol_data *new_data;
+       unsigned int n = data->wlist.num_widgets + 1;
+
+       new_data = krealloc(data, sizeof(*data) + sizeof(widget) * n,
+               GFP_KERNEL);
+       if (!new_data)
+               return -ENOMEM;
+
+       new_data->wlist.widgets[n - 1] = widget;
+       new_data->wlist.num_widgets = n;
+
+       kcontrol->private_data = new_data;
+
+       return 0;
+}
+
+static void dapm_kcontrol_add_path(const struct snd_kcontrol *kcontrol,
+       struct snd_soc_dapm_path *path)
+{
+       struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
+
+       list_add_tail(&path->list_kcontrol, &data->paths);
+}
+
+static struct list_head *dapm_kcontrol_get_path_list(
+       const struct snd_kcontrol *kcontrol)
+{
+       struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
+
+       return &data->paths;
 }
 
+#define dapm_kcontrol_for_each_path(path, kcontrol) \
+       list_for_each_entry(path, dapm_kcontrol_get_path_list(kcontrol), \
+               list_kcontrol)
+
+static unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol)
+{
+       struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
+
+       return data->value;
+}
+
+static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol,
+       unsigned int value)
+{
+       struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
+
+       if (data->value == value)
+               return false;
+
+       data->value = value;
+
+       return true;
+}
+
+/**
+ * snd_soc_dapm_kcontrol_codec() - Returns the codec associated to a kcontrol
+ * @kcontrol: The kcontrol
+ */
+struct snd_soc_codec *snd_soc_dapm_kcontrol_codec(struct snd_kcontrol *kcontrol)
+{
+       return dapm_kcontrol_get_wlist(kcontrol)->widgets[0]->codec;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_codec);
+
 static void dapm_reset(struct snd_soc_card *card)
 {
        struct snd_soc_dapm_widget *w;
@@ -211,6 +293,7 @@ static void dapm_reset(struct snd_soc_card *card)
        memset(&card->dapm_stats, 0, sizeof(card->dapm_stats));
 
        list_for_each_entry(w, &card->widgets, list) {
+               w->new_power = w->power;
                w->power_checked = false;
                w->inputs = -1;
                w->outputs = -1;
@@ -507,11 +590,6 @@ static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
        return 0;
 }
 
-static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
-{
-       kfree(kctl->private_data);
-}
-
 /*
  * Determine if a kcontrol is shared. If it is, look it up. If it isn't,
  * create it. Either way, add the widget into the control's widget list
@@ -525,9 +603,6 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
        size_t prefix_len;
        int shared;
        struct snd_kcontrol *kcontrol;
-       struct snd_soc_dapm_widget_list *wlist;
-       int wlistentries;
-       size_t wlistsize;
        bool wname_in_long_name, kcname_in_long_name;
        char *long_name;
        const char *name;
@@ -546,25 +621,6 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
        shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[kci],
                                         &kcontrol);
 
-       if (kcontrol) {
-               wlist = kcontrol->private_data;
-               wlistentries = wlist->num_widgets + 1;
-       } else {
-               wlist = NULL;
-               wlistentries = 1;
-       }
-
-       wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
-                       wlistentries * sizeof(struct snd_soc_dapm_widget *);
-       wlist = krealloc(wlist, wlistsize, GFP_KERNEL);
-       if (wlist == NULL) {
-               dev_err(dapm->dev, "ASoC: can't allocate widget list for %s\n",
-                       w->name);
-               return -ENOMEM;
-       }
-       wlist->num_widgets = wlistentries;
-       wlist->widgets[wlistentries - 1] = w;
-
        if (!kcontrol) {
                if (shared) {
                        wname_in_long_name = false;
@@ -587,7 +643,6 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
                                kcname_in_long_name = false;
                                break;
                        default:
-                               kfree(wlist);
                                return -EINVAL;
                        }
                }
@@ -602,10 +657,8 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
                        long_name = kasprintf(GFP_KERNEL, "%s %s",
                                 w->name + prefix_len,
                                 w->kcontrol_news[kci].name);
-                       if (long_name == NULL) {
-                               kfree(wlist);
+                       if (long_name == NULL)
                                return -ENOMEM;
-                       }
 
                        name = long_name;
                } else if (wname_in_long_name) {
@@ -616,23 +669,32 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
                        name = w->kcontrol_news[kci].name;
                }
 
-               kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], wlist, name,
+               kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], NULL, name,
                                        prefix);
                kcontrol->private_free = dapm_kcontrol_free;
                kfree(long_name);
+
+               ret = dapm_kcontrol_data_alloc(w, kcontrol);
+               if (ret) {
+                       snd_ctl_free_one(kcontrol);
+                       return ret;
+               }
+
                ret = snd_ctl_add(card, kcontrol);
                if (ret < 0) {
                        dev_err(dapm->dev,
                                "ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
                                w->name, name, ret);
-                       kfree(wlist);
                        return ret;
                }
+       } else {
+               ret = dapm_kcontrol_add_widget(kcontrol, w);
+               if (ret)
+                       return ret;
        }
 
-       kcontrol->private_data = wlist;
        w->kcontrols[kci] = kcontrol;
-       path->kcontrol = kcontrol;
+       dapm_kcontrol_add_path(kcontrol, path);
 
        return 0;
 }
@@ -652,7 +714,7 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
                                continue;
 
                        if (w->kcontrols[i]) {
-                               path->kcontrol = w->kcontrols[i];
+                               dapm_kcontrol_add_path(w->kcontrols[i], path);
                                continue;
                        }
 
@@ -691,7 +753,7 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w)
                return ret;
 
        list_for_each_entry(path, &w->sources, list_sink)
-               path->kcontrol = w->kcontrols[0];
+               dapm_kcontrol_add_path(w->kcontrols[0], path);
 
        return 0;
 }
@@ -1061,7 +1123,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w,
        int ret;
 
        if (SND_SOC_DAPM_EVENT_ON(event)) {
-               if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) {
+               if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
                        ret = regulator_allow_bypass(w->regulator, false);
                        if (ret != 0)
                                dev_warn(w->dapm->dev,
@@ -1071,7 +1133,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w,
 
                return regulator_enable(w->regulator);
        } else {
-               if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) {
+               if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
                        ret = regulator_allow_bypass(w->regulator, true);
                        if (ret != 0)
                                dev_warn(w->dapm->dev,
@@ -1243,10 +1305,9 @@ static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget,
        list_add_tail(&new_widget->power_list, list);
 }
 
-static void dapm_seq_check_event(struct snd_soc_dapm_context *dapm,
+static void dapm_seq_check_event(struct snd_soc_card *card,
                                 struct snd_soc_dapm_widget *w, int event)
 {
-       struct snd_soc_card *card = dapm->card;
        const char *ev_name;
        int power, ret;
 
@@ -1280,55 +1341,50 @@ static void dapm_seq_check_event(struct snd_soc_dapm_context *dapm,
                return;
        }
 
-       if (w->power != power)
+       if (w->new_power != power)
                return;
 
        if (w->event && (w->event_flags & event)) {
-               pop_dbg(dapm->dev, card->pop_time, "pop test : %s %s\n",
+               pop_dbg(w->dapm->dev, card->pop_time, "pop test : %s %s\n",
                        w->name, ev_name);
                trace_snd_soc_dapm_widget_event_start(w, event);
                ret = w->event(w, NULL, event);
                trace_snd_soc_dapm_widget_event_done(w, event);
                if (ret < 0)
-                       dev_err(dapm->dev, "ASoC: %s: %s event failed: %d\n",
+                       dev_err(w->dapm->dev, "ASoC: %s: %s event failed: %d\n",
                               ev_name, w->name, ret);
        }
 }
 
 /* Apply the coalesced changes from a DAPM sequence */
-static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm,
+static void dapm_seq_run_coalesced(struct snd_soc_card *card,
                                   struct list_head *pending)
 {
-       struct snd_soc_card *card = dapm->card;
        struct snd_soc_dapm_widget *w;
-       int reg, power;
+       int reg;
        unsigned int value = 0;
        unsigned int mask = 0;
-       unsigned int cur_mask;
 
        reg = list_first_entry(pending, struct snd_soc_dapm_widget,
                               power_list)->reg;
 
        list_for_each_entry(w, pending, power_list) {
-               cur_mask = 1 << w->shift;
                BUG_ON(reg != w->reg);
+               w->power = w->new_power;
 
-               if (w->invert)
-                       power = !w->power;
+               mask |= w->mask << w->shift;
+               if (w->power)
+                       value |= w->on_val << w->shift;
                else
-                       power = w->power;
+                       value |= w->off_val << w->shift;
 
-               mask |= cur_mask;
-               if (power)
-                       value |= cur_mask;
-
-               pop_dbg(dapm->dev, card->pop_time,
+               pop_dbg(w->dapm->dev, card->pop_time,
                        "pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n",
                        w->name, reg, value, mask);
 
                /* Check for events */
-               dapm_seq_check_event(dapm, w, SND_SOC_DAPM_PRE_PMU);
-               dapm_seq_check_event(dapm, w, SND_SOC_DAPM_PRE_PMD);
+               dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMU);
+               dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMD);
        }
 
        if (reg >= 0) {
@@ -1338,7 +1394,7 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm,
                w = list_first_entry(pending, struct snd_soc_dapm_widget,
                                     power_list);
 
-               pop_dbg(dapm->dev, card->pop_time,
+               pop_dbg(w->dapm->dev, card->pop_time,
                        "pop test : Applying 0x%x/0x%x to %x in %dms\n",
                        value, mask, reg, card->pop_time);
                pop_wait(card->pop_time);
@@ -1346,8 +1402,8 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm,
        }
 
        list_for_each_entry(w, pending, power_list) {
-               dapm_seq_check_event(dapm, w, SND_SOC_DAPM_POST_PMU);
-               dapm_seq_check_event(dapm, w, SND_SOC_DAPM_POST_PMD);
+               dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMU);
+               dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMD);
        }
 }
 
@@ -1359,8 +1415,8 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm,
  * Currently anything that requires more than a single write is not
  * handled.
  */
-static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
-                        struct list_head *list, int event, bool power_up)
+static void dapm_seq_run(struct snd_soc_card *card,
+       struct list_head *list, int event, bool power_up)
 {
        struct snd_soc_dapm_widget *w, *n;
        LIST_HEAD(pending);
@@ -1383,7 +1439,7 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
                if (sort[w->id] != cur_sort || w->reg != cur_reg ||
                    w->dapm != cur_dapm || w->subseq != cur_subseq) {
                        if (!list_empty(&pending))
-                               dapm_seq_run_coalesced(cur_dapm, &pending);
+                               dapm_seq_run_coalesced(card, &pending);
 
                        if (cur_dapm && cur_dapm->seq_notifier) {
                                for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
@@ -1443,7 +1499,7 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
        }
 
        if (!list_empty(&pending))
-               dapm_seq_run_coalesced(cur_dapm, &pending);
+               dapm_seq_run_coalesced(card, &pending);
 
        if (cur_dapm && cur_dapm->seq_notifier) {
                for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
@@ -1453,37 +1509,48 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
        }
 }
 
-static void dapm_widget_update(struct snd_soc_dapm_context *dapm)
+static void dapm_widget_update(struct snd_soc_card *card)
 {
-       struct snd_soc_dapm_update *update = dapm->update;
-       struct snd_soc_dapm_widget *w;
+       struct snd_soc_dapm_update *update = card->update;
+       struct snd_soc_dapm_widget_list *wlist;
+       struct snd_soc_dapm_widget *w = NULL;
+       unsigned int wi;
        int ret;
 
        if (!update)
                return;
 
-       w = update->widget;
+       wlist = dapm_kcontrol_get_wlist(update->kcontrol);
 
-       if (w->event &&
-           (w->event_flags & SND_SOC_DAPM_PRE_REG)) {
-               ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG);
-               if (ret != 0)
-                       dev_err(dapm->dev, "ASoC: %s DAPM pre-event failed: %d\n",
-                              w->name, ret);
+       for (wi = 0; wi < wlist->num_widgets; wi++) {
+               w = wlist->widgets[wi];
+
+               if (w->event && (w->event_flags & SND_SOC_DAPM_PRE_REG)) {
+                       ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG);
+                       if (ret != 0)
+                               dev_err(w->dapm->dev, "ASoC: %s DAPM pre-event failed: %d\n",
+                                          w->name, ret);
+               }
        }
 
+       if (!w)
+               return;
+
        ret = soc_widget_update_bits_locked(w, update->reg, update->mask,
                                  update->val);
        if (ret < 0)
-               dev_err(dapm->dev, "ASoC: %s DAPM update failed: %d\n",
+               dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n",
                        w->name, ret);
 
-       if (w->event &&
-           (w->event_flags & SND_SOC_DAPM_POST_REG)) {
-               ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG);
-               if (ret != 0)
-                       dev_err(dapm->dev, "ASoC: %s DAPM post-event failed: %d\n",
-                              w->name, ret);
+       for (wi = 0; wi < wlist->num_widgets; wi++) {
+               w = wlist->widgets[wi];
+
+               if (w->event && (w->event_flags & SND_SOC_DAPM_POST_REG)) {
+                       ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG);
+                       if (ret != 0)
+                               dev_err(w->dapm->dev, "ASoC: %s DAPM post-event failed: %d\n",
+                                          w->name, ret);
+               }
        }
 }
 
@@ -1611,8 +1678,6 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
                dapm_seq_insert(w, up_list, true);
        else
                dapm_seq_insert(w, down_list, false);
-
-       w->power = power;
 }
 
 static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
@@ -1646,9 +1711,8 @@ static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
  *  o Input pin to Output pin (bypass, sidetone)
  *  o DAC to ADC (loopback).
  */
-static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
+static int dapm_power_widgets(struct snd_soc_card *card, int event)
 {
-       struct snd_soc_card *card = dapm->card;
        struct snd_soc_dapm_widget *w;
        struct snd_soc_dapm_context *d;
        LIST_HEAD(up_list);
@@ -1688,7 +1752,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
                        break;
                }
 
-               if (w->power) {
+               if (w->new_power) {
                        d = w->dapm;
 
                        /* Supplies and micbiases only bring the
@@ -1730,29 +1794,29 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
        trace_snd_soc_dapm_walk_done(card);
 
        /* Run all the bias changes in parallel */
-       list_for_each_entry(d, &dapm->card->dapm_list, list)
+       list_for_each_entry(d, &card->dapm_list, list)
                async_schedule_domain(dapm_pre_sequence_async, d,
                                        &async_domain);
        async_synchronize_full_domain(&async_domain);
 
        list_for_each_entry(w, &down_list, power_list) {
-               dapm_seq_check_event(dapm, w, SND_SOC_DAPM_WILL_PMD);
+               dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMD);
        }
 
        list_for_each_entry(w, &up_list, power_list) {
-               dapm_seq_check_event(dapm, w, SND_SOC_DAPM_WILL_PMU);
+               dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMU);
        }
 
        /* Power down widgets first; try to avoid amplifying pops. */
-       dapm_seq_run(dapm, &down_list, event, false);
+       dapm_seq_run(card, &down_list, event, false);
 
-       dapm_widget_update(dapm);
+       dapm_widget_update(card);
 
        /* Now power up. */
-       dapm_seq_run(dapm, &up_list, event, true);
+       dapm_seq_run(card, &up_list, event, true);
 
        /* Run all the bias changes in parallel */
-       list_for_each_entry(d, &dapm->card->dapm_list, list)
+       list_for_each_entry(d, &card->dapm_list, list)
                async_schedule_domain(dapm_post_sequence_async, d,
                                        &async_domain);
        async_synchronize_full_domain(&async_domain);
@@ -1763,7 +1827,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
                        d->stream_event(d, event);
        }
 
-       pop_dbg(dapm->dev, card->pop_time,
+       pop_dbg(card->dev, card->pop_time,
                "DAPM sequencing finished, waiting %dms\n", card->pop_time);
        pop_wait(card->pop_time);
 
@@ -1798,8 +1862,8 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
 
        if (w->reg >= 0)
                ret += snprintf(buf + ret, PAGE_SIZE - ret,
-                               " - R%d(0x%x) bit %d",
-                               w->reg, w->reg, w->shift);
+                               " - R%d(0x%x) mask 0x%x",
+                               w->reg, w->reg, w->mask << w->shift);
 
        ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
 
@@ -1936,22 +2000,14 @@ static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
 #endif
 
 /* test and update the power status of a mux widget */
-static int soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
+static int soc_dapm_mux_update_power(struct snd_soc_card *card,
                                 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
 {
        struct snd_soc_dapm_path *path;
        int found = 0;
 
-       if (widget->id != snd_soc_dapm_mux &&
-           widget->id != snd_soc_dapm_virt_mux &&
-           widget->id != snd_soc_dapm_value_mux)
-               return -ENODEV;
-
        /* find dapm widget path assoc with kcontrol */
-       list_for_each_entry(path, &widget->dapm->card->paths, list) {
-               if (path->kcontrol != kcontrol)
-                       continue;
-
+       dapm_kcontrol_for_each_path(path, kcontrol) {
                if (!path->name || !e->texts[mux])
                        continue;
 
@@ -1966,73 +2022,68 @@ static int soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
                                                "mux disconnection");
                        path->connect = 0; /* old connection must be powered down */
                }
+               dapm_mark_dirty(path->sink, "mux change");
        }
 
-       if (found) {
-               dapm_mark_dirty(widget, "mux change");
-               dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
-       }
+       if (found)
+               dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
 
        return found;
 }
 
-int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
-               struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
+int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
+       struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e,
+       struct snd_soc_dapm_update *update)
 {
-       struct snd_soc_card *card = widget->dapm->card;
+       struct snd_soc_card *card = dapm->card;
        int ret;
 
        mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
-       ret = soc_dapm_mux_update_power(widget, kcontrol, mux, e);
+       card->update = update;
+       ret = soc_dapm_mux_update_power(card, kcontrol, mux, e);
+       card->update = NULL;
        mutex_unlock(&card->dapm_mutex);
        if (ret > 0)
-               soc_dpcm_runtime_update(widget);
+               soc_dpcm_runtime_update(card);
        return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
 
 /* test and update the power status of a mixer or switch widget */
-static int soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
+static int soc_dapm_mixer_update_power(struct snd_soc_card *card,
                                   struct snd_kcontrol *kcontrol, int connect)
 {
        struct snd_soc_dapm_path *path;
        int found = 0;
 
-       if (widget->id != snd_soc_dapm_mixer &&
-           widget->id != snd_soc_dapm_mixer_named_ctl &&
-           widget->id != snd_soc_dapm_switch)
-               return -ENODEV;
-
        /* find dapm widget path assoc with kcontrol */
-       list_for_each_entry(path, &widget->dapm->card->paths, list) {
-               if (path->kcontrol != kcontrol)
-                       continue;
-
-               /* found, now check type */
+       dapm_kcontrol_for_each_path(path, kcontrol) {
                found = 1;
                path->connect = connect;
                dapm_mark_dirty(path->source, "mixer connection");
+               dapm_mark_dirty(path->sink, "mixer update");
        }
 
-       if (found) {
-               dapm_mark_dirty(widget, "mixer update");
-               dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
-       }
+       if (found)
+               dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
 
        return found;
 }
 
-int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
-                               struct snd_kcontrol *kcontrol, int connect)
+int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
+       struct snd_kcontrol *kcontrol, int connect,
+       struct snd_soc_dapm_update *update)
 {
-       struct snd_soc_card *card = widget->dapm->card;
+       struct snd_soc_card *card = dapm->card;
        int ret;
 
        mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
-       ret = soc_dapm_mixer_update_power(widget, kcontrol, connect);
+       card->update = update;
+       ret = soc_dapm_mixer_update_power(card, kcontrol, connect);
+       card->update = NULL;
        mutex_unlock(&card->dapm_mutex);
        if (ret > 0)
-               soc_dpcm_runtime_update(widget);
+               soc_dpcm_runtime_update(card);
        return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
@@ -2111,6 +2162,7 @@ static void dapm_free_path(struct snd_soc_dapm_path *path)
 {
        list_del(&path->list_sink);
        list_del(&path->list_source);
+       list_del(&path->list_kcontrol);
        list_del(&path->list);
        kfree(path);
 }
@@ -2205,70 +2257,20 @@ int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
                return 0;
 
        mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
-       ret = dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
+       ret = dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP);
        mutex_unlock(&dapm->card->dapm_mutex);
        return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
 
-static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
-                                 const struct snd_soc_dapm_route *route)
+static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
+       struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
+       const char *control,
+       int (*connected)(struct snd_soc_dapm_widget *source,
+                        struct snd_soc_dapm_widget *sink))
 {
        struct snd_soc_dapm_path *path;
-       struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
-       struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;
-       const char *sink;
-       const char *control = route->control;
-       const char *source;
-       char prefixed_sink[80];
-       char prefixed_source[80];
-       int ret = 0;
-
-       if (dapm->codec && dapm->codec->name_prefix) {
-               snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
-                        dapm->codec->name_prefix, route->sink);
-               sink = prefixed_sink;
-               snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
-                        dapm->codec->name_prefix, route->source);
-               source = prefixed_source;
-       } else {
-               sink = route->sink;
-               source = route->source;
-       }
-
-       /*
-        * find src and dest widgets over all widgets but favor a widget from
-        * current DAPM context
-        */
-       list_for_each_entry(w, &dapm->card->widgets, list) {
-               if (!wsink && !(strcmp(w->name, sink))) {
-                       wtsink = w;
-                       if (w->dapm == dapm)
-                               wsink = w;
-                       continue;
-               }
-               if (!wsource && !(strcmp(w->name, source))) {
-                       wtsource = w;
-                       if (w->dapm == dapm)
-                               wsource = w;
-               }
-       }
-       /* use widget from another DAPM context if not found from this */
-       if (!wsink)
-               wsink = wtsink;
-       if (!wsource)
-               wsource = wtsource;
-
-       if (wsource == NULL) {
-               dev_err(dapm->dev, "ASoC: no source widget found for %s\n",
-                       route->source);
-               return -ENODEV;
-       }
-       if (wsink == NULL) {
-               dev_err(dapm->dev, "ASoC: no sink widget found for %s\n",
-                       route->sink);
-               return -ENODEV;
-       }
+       int ret;
 
        path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
        if (!path)
@@ -2276,7 +2278,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
 
        path->source = wsource;
        path->sink = wsink;
-       path->connected = route->connected;
+       path->connected = connected;
        INIT_LIST_HEAD(&path->list);
        INIT_LIST_HEAD(&path->list_source);
        INIT_LIST_HEAD(&path->list_sink);
@@ -2362,11 +2364,77 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
        dapm_mark_dirty(wsink, "Route added");
 
        return 0;
+err:
+       kfree(path);
+       return ret;
+}
+
+static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
+                                 const struct snd_soc_dapm_route *route)
+{
+       struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
+       struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;
+       const char *sink;
+       const char *source;
+       char prefixed_sink[80];
+       char prefixed_source[80];
+       int ret;
+
+       if (dapm->codec && dapm->codec->name_prefix) {
+               snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
+                        dapm->codec->name_prefix, route->sink);
+               sink = prefixed_sink;
+               snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
+                        dapm->codec->name_prefix, route->source);
+               source = prefixed_source;
+       } else {
+               sink = route->sink;
+               source = route->source;
+       }
+
+       /*
+        * find src and dest widgets over all widgets but favor a widget from
+        * current DAPM context
+        */
+       list_for_each_entry(w, &dapm->card->widgets, list) {
+               if (!wsink && !(strcmp(w->name, sink))) {
+                       wtsink = w;
+                       if (w->dapm == dapm)
+                               wsink = w;
+                       continue;
+               }
+               if (!wsource && !(strcmp(w->name, source))) {
+                       wtsource = w;
+                       if (w->dapm == dapm)
+                               wsource = w;
+               }
+       }
+       /* use widget from another DAPM context if not found from this */
+       if (!wsink)
+               wsink = wtsink;
+       if (!wsource)
+               wsource = wtsource;
 
+       if (wsource == NULL) {
+               dev_err(dapm->dev, "ASoC: no source widget found for %s\n",
+                       route->source);
+               return -ENODEV;
+       }
+       if (wsink == NULL) {
+               dev_err(dapm->dev, "ASoC: no sink widget found for %s\n",
+                       route->sink);
+               return -ENODEV;
+       }
+
+       ret = snd_soc_dapm_add_path(dapm, wsource, wsink, route->control,
+               route->connected);
+       if (ret)
+               goto err;
+
+       return 0;
 err:
        dev_warn(dapm->dev, "ASoC: no dapm match for %s --> %s --> %s\n",
-                source, control, sink);
-       kfree(path);
+                source, route->control, sink);
        return ret;
 }
 
@@ -2570,12 +2638,13 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes);
  */
 int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
 {
+       struct snd_soc_card *card = dapm->card;
        struct snd_soc_dapm_widget *w;
        unsigned int val;
 
-       mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
+       mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
 
-       list_for_each_entry(w, &dapm->card->widgets, list)
+       list_for_each_entry(w, &card->widgets, list)
        {
                if (w->new)
                        continue;
@@ -2585,7 +2654,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
                                                sizeof(struct snd_kcontrol *),
                                                GFP_KERNEL);
                        if (!w->kcontrols) {
-                               mutex_unlock(&dapm->card->dapm_mutex);
+                               mutex_unlock(&card->dapm_mutex);
                                return -ENOMEM;
                        }
                }
@@ -2611,12 +2680,9 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
 
                /* Read the initial power state from the device */
                if (w->reg >= 0) {
-                       val = soc_widget_read(w, w->reg);
-                       val &= 1 << w->shift;
-                       if (w->invert)
-                               val = !val;
-
-                       if (val)
+                       val = soc_widget_read(w, w->reg) >> w->shift;
+                       val &= w->mask;
+                       if (val == w->on_val)
                                w->power = 1;
                }
 
@@ -2626,8 +2692,8 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
                dapm_debugfs_add_widget(w);
        }
 
-       dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
-       mutex_unlock(&dapm->card->dapm_mutex);
+       dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
+       mutex_unlock(&card->dapm_mutex);
        return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
@@ -2644,8 +2710,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
 int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+       struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
        unsigned int reg = mc->reg;
@@ -2655,12 +2720,12 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
        unsigned int invert = mc->invert;
 
        if (snd_soc_volsw_is_stereo(mc))
-               dev_warn(widget->dapm->dev,
+               dev_warn(codec->dapm.dev,
                         "ASoC: Control '%s' is stereo, which is not supported\n",
                         kcontrol->id.name);
 
        ucontrol->value.integer.value[0] =
-               (snd_soc_read(widget->codec, reg) >> shift) & mask;
+               (snd_soc_read(codec, reg) >> shift) & mask;
        if (invert)
                ucontrol->value.integer.value[0] =
                        max - ucontrol->value.integer.value[0];
@@ -2681,9 +2746,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);
 int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-       struct snd_soc_codec *codec = widget->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
        struct snd_soc_card *card = codec->card;
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
@@ -2695,10 +2758,9 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
        unsigned int val;
        int connect, change;
        struct snd_soc_dapm_update update;
-       int wi;
 
        if (snd_soc_volsw_is_stereo(mc))
-               dev_warn(widget->dapm->dev,
+               dev_warn(codec->dapm.dev,
                         "ASoC: Control '%s' is stereo, which is not supported\n",
                         kcontrol->id.name);
 
@@ -2712,28 +2774,22 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
 
        mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
-       change = snd_soc_test_bits(widget->codec, reg, mask, val);
+       change = snd_soc_test_bits(codec, reg, mask, val);
        if (change) {
-               for (wi = 0; wi < wlist->num_widgets; wi++) {
-                       widget = wlist->widgets[wi];
-
-                       widget->value = val;
+               update.kcontrol = kcontrol;
+               update.reg = reg;
+               update.mask = mask;
+               update.val = val;
 
-                       update.kcontrol = kcontrol;
-                       update.widget = widget;
-                       update.reg = reg;
-                       update.mask = mask;
-                       update.val = val;
-                       widget->dapm->update = &update;
+               card->update = &update;
 
-                       soc_dapm_mixer_update_power(widget, kcontrol, connect);
+               soc_dapm_mixer_update_power(card, kcontrol, connect);
 
-                       widget->dapm->update = NULL;
-               }
+               card->update = NULL;
        }
 
        mutex_unlock(&card->dapm_mutex);
-       return 0;
+       return change;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
 
@@ -2749,12 +2805,11 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
 int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+       struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int val;
 
-       val = snd_soc_read(widget->codec, e->reg);
+       val = snd_soc_read(codec, e->reg);
        ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & e->mask;
        if (e->shift_l != e->shift_r)
                ucontrol->value.enumerated.item[1] =
@@ -2776,15 +2831,12 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
 int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-       struct snd_soc_codec *codec = widget->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
        struct snd_soc_card *card = codec->card;
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int val, mux, change;
        unsigned int mask;
        struct snd_soc_dapm_update update;
-       int wi;
 
        if (ucontrol->value.enumerated.item[0] > e->max - 1)
                return -EINVAL;
@@ -2800,24 +2852,17 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
 
        mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
-       change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
+       change = snd_soc_test_bits(codec, e->reg, mask, val);
        if (change) {
-               for (wi = 0; wi < wlist->num_widgets; wi++) {
-                       widget = wlist->widgets[wi];
-
-                       widget->value = val;
+               update.kcontrol = kcontrol;
+               update.reg = e->reg;
+               update.mask = mask;
+               update.val = val;
+               card->update = &update;
 
-                       update.kcontrol = kcontrol;
-                       update.widget = widget;
-                       update.reg = e->reg;
-                       update.mask = mask;
-                       update.val = val;
-                       widget->dapm->update = &update;
+               soc_dapm_mux_update_power(card, kcontrol, mux, e);
 
-                       soc_dapm_mux_update_power(widget, kcontrol, mux, e);
-
-                       widget->dapm->update = NULL;
-               }
+               card->update = NULL;
        }
 
        mutex_unlock(&card->dapm_mutex);
@@ -2835,11 +2880,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
 int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol,
                               struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-
-       ucontrol->value.enumerated.item[0] = widget->value;
-
+       ucontrol->value.enumerated.item[0] = dapm_kcontrol_get_value(kcontrol);
        return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt);
@@ -2854,34 +2895,25 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt);
 int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
                               struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-       struct snd_soc_codec *codec = widget->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
        struct snd_soc_card *card = codec->card;
+       unsigned int value;
        struct soc_enum *e =
                (struct soc_enum *)kcontrol->private_value;
        int change;
-       int ret = 0;
-       int wi;
 
        if (ucontrol->value.enumerated.item[0] >= e->max)
                return -EINVAL;
 
        mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
-       change = widget->value != ucontrol->value.enumerated.item[0];
-       if (change) {
-               for (wi = 0; wi < wlist->num_widgets; wi++) {
-                       widget = wlist->widgets[wi];
-
-                       widget->value = ucontrol->value.enumerated.item[0];
-
-                       soc_dapm_mux_update_power(widget, kcontrol, widget->value, e);
-               }
-       }
+       value = ucontrol->value.enumerated.item[0];
+       change = dapm_kcontrol_set_value(kcontrol, value);
+       if (change)
+               soc_dapm_mux_update_power(card, kcontrol, value, e);
 
        mutex_unlock(&card->dapm_mutex);
-       return ret;
+       return change;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt);
 
@@ -2901,12 +2933,11 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt);
 int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+       struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int reg_val, val, mux;
 
-       reg_val = snd_soc_read(widget->codec, e->reg);
+       reg_val = snd_soc_read(codec, e->reg);
        val = (reg_val >> e->shift_l) & e->mask;
        for (mux = 0; mux < e->max; mux++) {
                if (val == e->values[mux])
@@ -2942,15 +2973,12 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_value_enum_double);
 int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-       struct snd_soc_codec *codec = widget->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
        struct snd_soc_card *card = codec->card;
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int val, mux, change;
        unsigned int mask;
        struct snd_soc_dapm_update update;
-       int wi;
 
        if (ucontrol->value.enumerated.item[0] > e->max - 1)
                return -EINVAL;
@@ -2966,24 +2994,17 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
 
        mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
-       change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
+       change = snd_soc_test_bits(codec, e->reg, mask, val);
        if (change) {
-               for (wi = 0; wi < wlist->num_widgets; wi++) {
-                       widget = wlist->widgets[wi];
+               update.kcontrol = kcontrol;
+               update.reg = e->reg;
+               update.mask = mask;
+               update.val = val;
+               card->update = &update;
 
-                       widget->value = val;
+               soc_dapm_mux_update_power(card, kcontrol, mux, e);
 
-                       update.kcontrol = kcontrol;
-                       update.widget = widget;
-                       update.reg = e->reg;
-                       update.mask = mask;
-                       update.val = val;
-                       widget->dapm->update = &update;
-
-                       soc_dapm_mux_update_power(widget, kcontrol, mux, e);
-
-                       widget->dapm->update = NULL;
-               }
+               card->update = NULL;
        }
 
        mutex_unlock(&card->dapm_mutex);
@@ -3080,7 +3101,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
                        return NULL;
                }
 
-               if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) {
+               if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
                        ret = regulator_allow_bypass(w->regulator, true);
                        if (ret != 0)
                                dev_warn(w->dapm->dev,
@@ -3127,16 +3148,16 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
        case snd_soc_dapm_value_mux:
                w->power_check = dapm_generic_check_power;
                break;
-       case snd_soc_dapm_adc:
-       case snd_soc_dapm_aif_out:
        case snd_soc_dapm_dai_out:
                w->power_check = dapm_adc_check_power;
                break;
-       case snd_soc_dapm_dac:
-       case snd_soc_dapm_aif_in:
        case snd_soc_dapm_dai_in:
                w->power_check = dapm_dac_check_power;
                break;
+       case snd_soc_dapm_adc:
+       case snd_soc_dapm_aif_out:
+       case snd_soc_dapm_dac:
+       case snd_soc_dapm_aif_in:
        case snd_soc_dapm_pga:
        case snd_soc_dapm_out_drv:
        case snd_soc_dapm_input:
@@ -3416,9 +3437,6 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
 {
        struct snd_soc_dapm_widget *dai_w, *w;
        struct snd_soc_dai *dai;
-       struct snd_soc_dapm_route r;
-
-       memset(&r, 0, sizeof(r));
 
        /* For each DAI widget... */
        list_for_each_entry(dai_w, &card->widgets, list) {
@@ -3451,23 +3469,21 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
                        if (dai->driver->playback.stream_name &&
                            strstr(w->sname,
                                   dai->driver->playback.stream_name)) {
-                               r.source = dai->playback_widget->name;
-                               r.sink = w->name;
                                dev_dbg(dai->dev, "%s -> %s\n",
-                                        r.source, r.sink);
+                                        dai->playback_widget->name, w->name);
 
-                               snd_soc_dapm_add_route(w->dapm, &r);
+                               snd_soc_dapm_add_path(w->dapm,
+                                       dai->playback_widget, w, NULL, NULL);
                        }
 
                        if (dai->driver->capture.stream_name &&
                            strstr(w->sname,
                                   dai->driver->capture.stream_name)) {
-                               r.source = w->name;
-                               r.sink = dai->capture_widget->name;
                                dev_dbg(dai->dev, "%s -> %s\n",
-                                       r.source, r.sink);
+                                       w->name, dai->capture_widget->name);
 
-                               snd_soc_dapm_add_route(w->dapm, &r);
+                               snd_soc_dapm_add_path(w->dapm, w,
+                                       dai->capture_widget, NULL, NULL);
                        }
                }
        }
@@ -3529,7 +3545,7 @@ static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
                }
        }
 
-       dapm_power_widgets(&rtd->card->dapm, event);
+       dapm_power_widgets(rtd->card, event);
 }
 
 /**
@@ -3798,7 +3814,7 @@ static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm)
                if (dapm->bias_level == SND_SOC_BIAS_ON)
                        snd_soc_dapm_set_bias_level(dapm,
                                                    SND_SOC_BIAS_PREPARE);
-               dapm_seq_run(dapm, &down_list, 0, false);
+               dapm_seq_run(card, &down_list, 0, false);
                if (dapm->bias_level == SND_SOC_BIAS_PREPARE)
                        snd_soc_dapm_set_bias_level(dapm,
                                                    SND_SOC_BIAS_STANDBY);
index 0bb5cccd77663a4d819a67731245e51564af3224..7aa26b5178aa60ac68d7f2c281b515ecf35ef979 100644 (file)
@@ -263,7 +263,7 @@ static irqreturn_t gpio_handler(int irq, void *data)
        if (device_may_wakeup(dev))
                pm_wakeup_event(dev, gpio->debounce_time + 50);
 
-       schedule_delayed_work(&gpio->work,
+       queue_delayed_work(system_power_efficient_wq, &gpio->work,
                              msecs_to_jiffies(gpio->debounce_time));
 
        return IRQ_HANDLED;
index b6c640332a1722c95c27fa8aa99b4d8b135d456f..fb70fbe26862f63ef879b5fde3c58e49e2fd49a6 100644 (file)
@@ -411,8 +411,9 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
                } else {
                        /* start delayed pop wq here for playback streams */
                        rtd->pop_wait = 1;
-                       schedule_delayed_work(&rtd->delayed_work,
-                               msecs_to_jiffies(rtd->pmdown_time));
+                       queue_delayed_work(system_power_efficient_wq,
+                                          &rtd->delayed_work,
+                                          msecs_to_jiffies(rtd->pmdown_time));
                }
        } else {
                /* capture streams can be powered down now */
@@ -1832,18 +1833,10 @@ static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream)
 /* Called by DAPM mixer/mux changes to update audio routing between PCMs and
  * any DAI links.
  */
-int soc_dpcm_runtime_update(struct snd_soc_dapm_widget *widget)
+int soc_dpcm_runtime_update(struct snd_soc_card *card)
 {
-       struct snd_soc_card *card;
        int i, old, new, paths;
 
-       if (widget->codec)
-               card = widget->codec->card;
-       else if (widget->platform)
-               card = widget->platform->card;
-       else
-               return -EINVAL;
-
        mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
        for (i = 0; i < card->num_rtd; i++) {
                struct snd_soc_dapm_widget_list *list;
index 995b120c2cd0a49a90a191e1e06649cb52396839..8fc653ca3ab40b3ef04d1a58723a2466086ab8ff 100644 (file)
@@ -1,8 +1,8 @@
 config SND_SOC_TEGRA
        tristate "SoC Audio for the Tegra System-on-Chip"
-       depends on ARCH_TEGRA && TEGRA20_APB_DMA
+       depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST
        select REGMAP_MMIO
-       select SND_SOC_GENERIC_DMAENGINE_PCM if TEGRA20_APB_DMA
+       select SND_SOC_GENERIC_DMAENGINE_PCM
        help
          Say Y or M here if you want support for SoC audio on Tegra.
 
@@ -61,7 +61,7 @@ config SND_SOC_TEGRA30_I2S
 
 config SND_SOC_TEGRA_RT5640
        tristate "SoC Audio support for Tegra boards using an RT5640 codec"
-       depends on SND_SOC_TEGRA && I2C
+       depends on SND_SOC_TEGRA && I2C && GPIOLIB
        select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
        select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC
        select SND_SOC_RT5640
@@ -71,7 +71,7 @@ config SND_SOC_TEGRA_RT5640
 
 config SND_SOC_TEGRA_WM8753
        tristate "SoC Audio support for Tegra boards using a WM8753 codec"
-       depends on SND_SOC_TEGRA && I2C
+       depends on SND_SOC_TEGRA && I2C && GPIOLIB
        select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
        select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC
        select SND_SOC_WM8753
@@ -81,7 +81,7 @@ config SND_SOC_TEGRA_WM8753
 
 config SND_SOC_TEGRA_WM8903
        tristate "SoC Audio support for Tegra boards using a WM8903 codec"
-       depends on SND_SOC_TEGRA && I2C
+       depends on SND_SOC_TEGRA && I2C && GPIOLIB
        select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
        select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC
        select SND_SOC_WM8903
@@ -92,7 +92,7 @@ config SND_SOC_TEGRA_WM8903
 
 config SND_SOC_TEGRA_WM9712
        tristate "SoC Audio support for Tegra boards using a WM9712 codec"
-       depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC
+       depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC && GPIOLIB
        select SND_SOC_TEGRA20_AC97
        select SND_SOC_WM9712
        help
@@ -110,7 +110,7 @@ config SND_SOC_TEGRA_TRIMSLICE
 
 config SND_SOC_TEGRA_ALC5632
        tristate "SoC Audio support for Tegra boards using an ALC5632 codec"
-       depends on SND_SOC_TEGRA && I2C
+       depends on SND_SOC_TEGRA && I2C && GPIOLIB
        select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
        select SND_SOC_ALC5632
        help
index 6c486625321bebb78b6f66370fda54a49a300fcb..00106b5a4b61f5fef7f28fa96efc479ac42af736 100644 (file)
@@ -432,8 +432,6 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
 
        return 0;
 
-err_unregister_pcm:
-       tegra_pcm_platform_unregister(&pdev->dev);
 err_unregister_component:
        snd_soc_unregister_component(&pdev->dev);
 err_asoc_utils_fini:
index 48d05d9e1002b3f13529f386d543c0b59803874e..c61ea3a1030f7a683f55bd087049392fe4867bfb 100644 (file)
@@ -13,8 +13,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <asm/mach-types.h>
-
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
index f87fc53e9b8cddab8d8f529c0ab730a8481ede8d..8e774d1a243c624dcca5b09c25065316629d886e 100644 (file)
@@ -28,8 +28,6 @@
  *
  */
 
-#include <asm/mach-types.h>
-
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
index 05c68aab5cf0a9a8e06a7fb93f27cd2b0d3cf3e0..734bfcd211481ccccf26c86a3db23399ecf9ffb3 100644 (file)
@@ -24,8 +24,6 @@
  *
  */
 
-#include <asm/mach-types.h>
-
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
index 4bcce8a3cdedd618e18844a55373c273cbd6427c..e0305a1485680b18cbc85ba33a506bda799f47c1 100644 (file)
@@ -184,9 +184,6 @@ static int txx9aclc_ac97_dev_probe(struct platform_device *pdev)
        if (irq < 0)
                return irq;
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!r)
-               return -EBUSY;
-
        drvdata->base = devm_ioremap_resource(&pdev->dev, r);
        if (IS_ERR(drvdata->base))
                return PTR_ERR(drvdata->base);
index 8f5cd00a6e468622af895ed4faebeaf78d7b8f9e..178d1bad62591565589803f52c859a2062044df2 100644 (file)
@@ -52,6 +52,7 @@ static struct snd_soc_dai_link mop500_dai_links[] = {
 
 static struct snd_soc_card mop500_card = {
        .name = "MOP500-card",
+       .owner = THIS_MODULE,
        .probe = NULL,
        .dai_link = mop500_dai_links,
        .num_links = ARRAY_SIZE(mop500_dai_links),
index 1f9bbd55553fc79bd539b8ad17f369be5beed267..5a51b18c50fe9230faabb923219c281b45a47970 100644 (file)
@@ -305,11 +305,9 @@ static void usX2Y_unlinkSeq(struct snd_usX2Y_AsyncSeq *S)
 {
        int     i;
        for (i = 0; i < URBS_AsyncSeq; ++i) {
-               if (S[i].urb) {
-                       usb_kill_urb(S->urb[i]);
-                       usb_free_urb(S->urb[i]);
-                       S->urb[i] = NULL;
-               }
+               usb_kill_urb(S->urb[i]);
+               usb_free_urb(S->urb[i]);
+               S->urb[i] = NULL;
        }
        kfree(S->buffer);
 }
index 68f67cf3d3182f5dcc696a50f3ef889c05ea10d2..32cf2ce15d69bcfca9c24da9ad318fc1a2e84eb2 100644 (file)
 #include <pwd.h>
 #include <grp.h>
 
+#ifndef VIRTIO_F_ANY_LAYOUT
+#define VIRTIO_F_ANY_LAYOUT            27
+#endif
+
 /*L:110
  * We can ignore the 43 include files we need for this program, but I do want
  * to draw attention to the use of kernel-style types.
@@ -1544,6 +1548,8 @@ static void setup_tun_net(char *arg)
        add_feature(dev, VIRTIO_NET_F_HOST_ECN);
        /* We handle indirect ring entries */
        add_feature(dev, VIRTIO_RING_F_INDIRECT_DESC);
+       /* We're compliant with the damn spec. */
+       add_feature(dev, VIRTIO_F_ANY_LAYOUT);
        set_config(dev, sizeof(conf), &conf);
 
        /* We don't need the socket any more; setup is done. */
diff --git a/tools/power/fspin/Makefile b/tools/power/fspin/Makefile
new file mode 100644 (file)
index 0000000..5274007
--- /dev/null
@@ -0,0 +1,21 @@
+CC             = $(CROSS_COMPILE)gcc
+BUILD_OUTPUT   := $(PWD)
+PREFIX         := /usr
+DESTDIR                :=
+
+fspin : fspin.c
+CFLAGS +=      -Wall
+
+%: %.c
+       @mkdir -p $(BUILD_OUTPUT)
+       $(CC) $(CFLAGS) $< -o $(BUILD_OUTPUT)/$@ -lpthread
+
+.PHONY : clean
+clean :
+       @rm -f $(BUILD_OUTPUT)/fspin
+
+install : fspin
+       install -d  $(DESTDIR)$(PREFIX)/bin
+       install $(BUILD_OUTPUT)/fspin $(DESTDIR)$(PREFIX)/bin/fspin
+       install -d  $(DESTDIR)$(PREFIX)/share/man/man1
+       install fspin.1 $(DESTDIR)$(PREFIX)/share/man/man1
diff --git a/tools/power/fspin/fspin.1 b/tools/power/fspin/fspin.1
new file mode 100644 (file)
index 0000000..b57308e
--- /dev/null
@@ -0,0 +1,68 @@
+.\"  This page Copyright (C) 2013 Len Brown <len.brown@intel.com>
+.\"  Distributed under the GPL, Copyleft 1994.
+.TH FSPIN 8
+.SH NAME
+fspin \- simple workload for power experiments
+.SH SYNOPSIS
+.ft B
+.B fspin
+.RB [ "\-v" ]
+.RB [ "\-i iterations" ]
+.RB [ "\-s sec_per_iteration" ]
+.RB [ "\-t threads" ]
+.RB [ "\-b bin_to_cpus" ]
+.RB [ "\-m memory (b|k|m)" ]
+.br
+.SH DESCRIPTION
+\fBfspin\fP
+heats up the hardware by running a
+floating-point spin loop per processor.
+Every
+.I interval_sec
+fspin presents the sum of the work completed
+by all threads.
+.SS Options
+.PP
+\fB-v\fP increases verbosity.
+By default, fspin prints only the quantity work completed.
+.PP
+\fB-s sec_per_iteration\fP
+Print the indicator of work completed every
+sec_per_interval seconds.  By default, 5 sec.
+.PP
+\fB-t threads\fP
+Create
+.I threads
+software threads.  Default is number of
+logical processors available, or if '-b' option is used,
+one thread per bound processor.
+.PP
+\fB-b bind_to_cpus\fP
+Bind the threads to the indicated list of comma-separated CPU numbers.
+A range of CPUs can be specified by using '-'.
+.PP
+\fB-i iterations\fP
+Exit after
+.I iterations
+and print total of work completed.
+Default is to continue running forever, printing work per iteration/sec.
+.PP
+\fB-m memory\fP
+Allocate arrays of 
+.I memory_size,
+which is followed by a modifier b|k|m, for bytes, kilobytes, or megabytes,
+respectively.  Default is 512 bytes, which will spin in-cache.
+Increase this number to exercise larger caches and memory.
+
+.SH WHAT FSPIN IS NOT
+Fspin is just a simple tool,
+and has not be characterized as a
+.I performance benchmark.
+Fspin is not a
+.I power virus for cooling HW design,
+as there are better tools, specialized for that purpose.
+
+.PP
+.SH AUTHORS
+.nf
+Written by Len Brown <len.brown@intel.com>
diff --git a/tools/power/fspin/fspin.c b/tools/power/fspin/fspin.c
new file mode 100644 (file)
index 0000000..38288c1
--- /dev/null
@@ -0,0 +1,443 @@
+/*
+ * fspin.c - user utility to burn CPU cycles, thrash the cache and memory
+ *
+ * Copyright (c) 2013, Intel Corporation.
+ * Len Brown <len.brown@intel.com>
+ *
+ * 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.
+ */
+
+/*
+ * Creates one thread per logical processor (override with -t).
+ * Threads run on any processor (override with -b).
+ * Each thread allocates and initializes its own data.
+ * Then it processes the data using an infinite DAXPY loop:
+ * Double precision Y[i] = A*X[i] + Y[i]
+ *
+ * The parent thread wakes up every reporting interval,
+ * (override 5 sec default with -i),
+ * sums up and prints aggregate performance.
+ *
+ * The actual computation is somewhat arbitrary, if not random.
+ * The performance number is intended only to be compared to itself
+ * on the same machine, to illustrate how various power limiting
+ * techniques impact performance.
+ */
+#define _GNU_SOURCE
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <ctype.h>
+#include <time.h>
+#include <sched.h>
+#include <errno.h>
+#include <sys/time.h>
+
+#define BANNER "fspin v1.1, April 7, 2013 - Len Brown <len.brown@intel.com>"
+
+#define handle_error_en(en, msg) \
+       do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
+
+#define handle_error(msg) \
+       do { perror(msg); exit(EXIT_FAILURE); } while (0)
+
+struct thread_info {           /* Used as argument to spin_loop() */
+       pthread_t thread_id;    /* ID returned by pthread_create() */
+       int thread_num;         /* Application-defined thread # */
+};
+
+struct padded {
+       double counter; /* 8 bytes */
+       double pad[(32 - 1)];   /* round up to 256 byte line */
+} *thread_data;
+
+int num_threads;
+int thread_num_override;
+int data_bytes = 512;
+int nrcpus = 64;
+int sec_per_interval = 5;      /* seconds */
+int iterations;
+int verbose;
+int do_binding;
+
+cpu_set_t *cpu_affinity_set;
+size_t cpu_affinity_setsize;
+
+void
+allocate_cpusets()
+{
+       /*
+        * Allocate and initialize cpu_affinity_set
+        */
+       cpu_affinity_set = CPU_ALLOC(nrcpus);
+       if (cpu_affinity_set == NULL) {
+               perror("CPU_ALLOC");
+               exit(3);
+       }
+       cpu_affinity_setsize = CPU_ALLOC_SIZE(nrcpus);
+       CPU_ZERO_S(cpu_affinity_setsize, cpu_affinity_set);
+}
+
+void
+bind_to_cpus()
+{
+       if (!do_binding)
+               return;
+
+       if (sched_setaffinity(0, cpu_affinity_setsize, cpu_affinity_set) == -1) {
+               fprintf(stderr, "bind_to_cpus() failed\n");
+               perror("sched_setaffinity");
+               exit(-1);
+       }
+}
+
+int get_num_cpus()
+{
+       cpu_set_t *mask;
+       size_t size;
+       int num_cpus;
+
+realloc:
+       mask = CPU_ALLOC(nrcpus);
+       size = CPU_ALLOC_SIZE(nrcpus);
+       CPU_ZERO_S(size, mask);
+       if (sched_getaffinity(0, size, mask) == -1) {
+               CPU_FREE(mask);
+               if (errno == EINVAL &&
+                       nrcpus < (1024 << 8)) {
+                       nrcpus = nrcpus << 2;
+                       goto realloc;
+               }
+               perror("sched_getaffinity");
+               return -1;
+       }
+
+       num_cpus = CPU_COUNT_S(size, mask);
+
+       CPU_FREE(mask);
+
+       return num_cpus;
+}
+
+static void *spin_loop(void *arg)
+{
+       struct thread_info *tinfo = (struct thread_info *)arg;
+       double *x, *y;
+       int i = 0;
+       int data_entries = data_bytes / sizeof(double);
+       unsigned long long bitmask = random();
+
+               
+       x = malloc(data_bytes);
+       y = malloc(data_bytes);
+
+       if (x == NULL || y == NULL) {
+               perror("malloc");
+               exit(-1);
+       }
+
+       /*
+        * seed data array with random bits
+        */
+       for (i = 0; i < data_entries; ++i) {
+               x[i] = 1.0 + i * bitmask;
+               y[i] = 1.0 + i * bitmask;
+       }
+
+       for (i = 0; ; i++) {
+
+               double a = 3.1415926535 * i;
+
+               y[i] = a * x[i] + y[i];         /* DAXPY */
+
+               thread_data[tinfo->thread_num].counter++;
+
+               if (i >= data_entries)
+                       i = 0;
+       }
+       /* not reached */
+}
+
+void usage()
+{
+       fprintf(stderr,
+               "Usage: fspin [-v][-s sec_per_iteration][-i iterations][-t num_threads][-b cpu_list][-m memory(b|k|m)]\n");
+       fprintf(stderr, "\twhere 'cpu_list' is comma and dash separated numbers with no spaces\n");
+       exit(EXIT_FAILURE);
+}
+
+void parse_error(char *string, char c)
+{
+       fprintf(stderr, "parse error on '%s' at '%c'\n", string, c);
+       usage();
+}
+
+int add_cpu_to_bind_mask(int cpu) {
+       static int num_added;
+
+       /* check if cpu is valid */
+       if (cpu < 0 || cpu > nrcpus) {
+               fprintf(stderr, "invalid cpu %d\n", cpu);
+               exit(1);
+       }
+
+       if (CPU_ISSET_S(cpu, cpu_affinity_setsize, cpu_affinity_set)) {
+               fprintf(stderr, "can't bind to cpu %d more than once\n", cpu);
+               exit(1);
+       }
+
+       /* add cpu to set */
+       CPU_SET_S(cpu, cpu_affinity_setsize, cpu_affinity_set);
+
+       if (verbose)
+               printf("%d, ", cpu);
+
+       num_added += 1;
+
+       return num_added;
+}
+
+
+int
+parse_bind_cpu_list(char *cpu_list)
+{
+       char *p;
+       int range_next = -1;
+       int total_cpus_added = 0;
+
+       allocate_cpusets();
+
+       for(p = cpu_list; *p != '\0'; ) {
+               int num, retval;
+
+               /* remaining list must start w/ valid cpu number */
+
+               if (!isdigit(*p))
+                       parse_error(p, *p);
+
+               retval = sscanf(p, "%u", &num);
+               if (retval == EOF)
+                       usage();
+               else if (retval == 0)
+                       parse_error(p, *p);
+
+               if (range_next >= 0) {
+                       if (num <= range_next)  /* range must be low to high */
+                               parse_error(p, *p);
+
+                       for ( ; range_next < num; range_next++)
+                               total_cpus_added = add_cpu_to_bind_mask(range_next);
+
+                       range_next = -1;
+               }
+
+               total_cpus_added = add_cpu_to_bind_mask(num);
+
+               while (isdigit(*p))
+                       p++;
+
+               switch (*p) {
+               case ',':
+                       p++;
+                       continue;
+               case '-':
+                       range_next = num + 1;
+                       p++;
+                       continue;
+               }
+
+       }
+       return total_cpus_added;
+}
+
+int parse_memory_param(char *p)
+{
+       int bytes;
+       char units;
+
+       if (2 != sscanf(p, "%d%c", &bytes, &units)) {
+               fprintf(stderr, "failed to parse -m\n");
+               usage();
+       }
+       switch (units) {
+       case 'b':
+       case 'B':
+               break;
+       case 'k':
+       case 'K':
+               bytes *= 1024;
+               break;
+       case 'm':
+       case 'M':
+               bytes *= 1024*1024;
+               break;
+       case 'g':
+       case 'G':
+               bytes *= 1024*1024*1024;
+               break;
+       default:
+               fprintf(stderr, "-m: bad memory units, use b, k, m, g\n");
+       
+       }
+       return bytes;
+       
+}
+
+void parse_args(int argc, char *argv[])
+{
+       int opt;
+
+       nrcpus = get_num_cpus();
+
+       while ((opt = getopt(argc, argv, "s:i:t:b:m:v")) != -1) {
+               switch (opt) {
+               case 's':
+                       sec_per_interval = atoi(optarg);
+                       if (verbose)
+                               printf("sec_per_interval %d\n", sec_per_interval);
+                       break;
+               case 'i':
+                       iterations = atoi(optarg);
+                       if (verbose)
+                               printf("iterations %d\n", iterations);
+                       break;
+               case 't':
+                       thread_num_override = atoi(optarg);
+                       if (verbose)
+                               printf("Thread Count Override: %d\n", thread_num_override);
+                       break;
+               case 'b':
+                       do_binding = parse_bind_cpu_list(optarg);
+                       if (verbose)
+                               printf("Binding to %d CPUs.\n", do_binding);
+                       break;
+               case 'm':
+                       data_bytes = parse_memory_param(optarg);
+                       if (verbose)
+                               printf("Memory Override: %d\n", data_bytes);
+                       break;
+               case 'v':
+                       verbose++;
+                       break;
+               default:        /* '?' */
+                       usage();        /* does not return */
+               }
+       }
+}
+
+unsigned long long lsum_old;
+
+
+struct thread_info *tinfo;
+pthread_attr_t attr;
+
+void create_threads()
+{
+       int s, tnum;
+
+       if (thread_num_override)
+               num_threads = thread_num_override;
+       else if (do_binding)
+               num_threads = do_binding;
+       else
+               num_threads = nrcpus;
+
+       thread_data = calloc(num_threads, sizeof(struct padded));
+       if (thread_data == NULL)
+               handle_error("calloc");
+
+       /* Initialize thread creation attributes */
+
+       s = pthread_attr_init(&attr);
+       if (s != 0)
+               handle_error_en(s, "pthread_attr_init");
+
+       /* Allocate memory for pthread_create() arguments */
+
+       tinfo = calloc(num_threads, sizeof(struct thread_info));
+       if (tinfo == NULL)
+               handle_error("calloc");
+
+       for (tnum = 0; tnum < num_threads; tnum++) {
+               tinfo[tnum].thread_num = tnum;
+
+               /* The pthread_create() call stores the thread ID into
+                * corresponding element of tinfo[]
+                */
+
+               s = pthread_create(&tinfo[tnum].thread_id, &attr,
+                                  &spin_loop, &tinfo[tnum]);
+               if (s != 0)
+                       handle_error_en(s, "pthread_create");
+       }
+       printf("%d threads created\n", num_threads);
+       return;
+}
+
+
+void monitor_threads()
+{
+       struct timespec ts;
+       struct timeval tv_old, tv_new, tv_delta;
+       int i, j;
+       double interval_float;
+       unsigned long long lsum;
+
+       ts.tv_sec = sec_per_interval;
+       ts.tv_nsec = 0;
+       gettimeofday(&tv_old, (struct timezone *)NULL);
+
+       for (i = 0; iterations ? i < iterations : 1 ; i++) {
+
+               if (nanosleep(&ts, NULL) != 0) {
+                       perror("nanosleep");
+                       exit(-1);
+               }
+
+               for (j = 0, lsum = 0; j < num_threads; ++j)
+                       lsum += thread_data[j].counter;
+
+               gettimeofday(&tv_new, NULL);
+               timersub(&tv_new, &tv_old, &tv_delta);
+
+               interval_float = tv_delta.tv_sec + tv_delta.tv_usec/1000000.0;
+               printf("%.2f\n", (lsum - lsum_old)/interval_float/1000000);
+
+               tv_old = tv_new;
+               lsum_old = lsum;
+       }
+       /* summary */
+       for (j = 0, lsum = 0; j < num_threads; ++j) {
+               printf("%d %.2f\n", j, thread_data[j].counter/1000000.0);
+               lsum += thread_data[j].counter;
+       }
+       printf("Total %.2f\n", lsum/1000000.0);
+       
+}
+
+
+void print_banner()
+{
+       puts(BANNER);
+}
+
+int main(int argc, char *argv[])
+{
+       parse_args(argc, argv);
+
+
+       print_banner();
+
+       bind_to_cpus();
+
+       create_threads();
+
+       monitor_threads();      /* never returns */
+
+       return 0;
+}
diff --git a/tools/virtio/.gitignore b/tools/virtio/.gitignore
new file mode 100644 (file)
index 0000000..1cfbb01
--- /dev/null
@@ -0,0 +1,3 @@
+*.d
+virtio_test
+vringh_test