]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'driver-core/driver-core-next'
authorStephen Rothwell <sfr@canb.auug.org.au>
Wed, 31 Jul 2013 03:29:50 +0000 (13:29 +1000)
committerStephen Rothwell <sfr@canb.auug.org.au>
Wed, 31 Jul 2013 03:29:50 +0000 (13:29 +1000)
1425 files changed:
Documentation/DocBook/drm.tmpl
Documentation/RCU/RTFP.txt
Documentation/RCU/rcubarrier.txt
Documentation/RCU/torture.txt
Documentation/arm/OMAP/omap_pm
Documentation/block/cfq-iosched.txt
Documentation/development-process/2.Process
Documentation/devicetree/bindings/arm/ste-u300.txt
Documentation/devicetree/bindings/arm/vexpress-sysreg.txt
Documentation/devicetree/bindings/clock/clk-exynos-audss.txt
Documentation/devicetree/bindings/dma/atmel-dma.txt
Documentation/devicetree/bindings/dma/fsl-imx-dma.txt
Documentation/devicetree/bindings/dma/ste-dma40.txt
Documentation/devicetree/bindings/leds/leds-lp55xx.txt
Documentation/devicetree/bindings/leds/pca9633.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mfd/cros-ec.txt
Documentation/devicetree/bindings/mtd/atmel-nand.txt
Documentation/devicetree/bindings/mtd/fsmc-nand.txt
Documentation/devicetree/bindings/net/can/sja1000.txt
Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt
Documentation/devicetree/bindings/regulator/88pm800.txt [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/palmas-pmic.txt
Documentation/devicetree/bindings/regulator/pfuze100.txt [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/regulator.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/tlv320aic3x.txt
Documentation/devicetree/bindings/sound/wm8994.txt
Documentation/devicetree/bindings/timer/moxa,moxart-timer.txt [new file with mode: 0644]
Documentation/devicetree/bindings/tty/serial/renesas,sci-serial.txt [new file with mode: 0644]
Documentation/devicetree/bindings/video/atmel,lcdc.txt [new file with mode: 0644]
Documentation/dma-buf-sharing.txt
Documentation/fb/fbcon.txt
Documentation/fb/viafb.txt
Documentation/filesystems/ext4.txt
Documentation/filesystems/f2fs.txt
Documentation/filesystems/nfs/pnfs.txt
Documentation/filesystems/relay.txt
Documentation/filesystems/sysfs-tagging.txt
Documentation/hwmon/w83791d
Documentation/hwmon/w83792d
Documentation/i2c/upgrading-clients
Documentation/kbuild/kconfig.txt
Documentation/kernel-parameters.txt
Documentation/laptops/asus-laptop.txt
Documentation/laptops/sony-laptop.txt
Documentation/laptops/thinkpad-acpi.txt
Documentation/leds/leds-lp55xx.txt
Documentation/memory-barriers.txt
Documentation/memory-hotplug.txt
Documentation/networking/ip-sysctl.txt
Documentation/networking/sctp.txt
Documentation/printk-formats.txt
Documentation/rapidio/rapidio.txt
Documentation/sound/alsa/compress_offload.txt
Documentation/sysfs-rules.txt
Documentation/timers/NO_HZ.txt
Documentation/virtual/kvm/api.txt
Documentation/workqueue.txt
Documentation/x86/boot.txt
Documentation/x86/x86_64/boot-options.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/init.c
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/include/asm/dma-contiguous.h
arch/arm/include/asm/hardware/debug-8250.S [deleted file]
arch/arm/include/asm/neon.h [new file with mode: 0644]
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/kernel/hyp-stub.S
arch/arm/kernel/setup.c
arch/arm/kvm/arm.c
arch/arm/lib/Makefile
arch/arm/lib/xor-neon.c [new file with mode: 0644]
arch/arm/mach-at91/at91sam9261_devices.c
arch/arm/mach-at91/at91sam9263_devices.c
arch/arm/mach-at91/at91sam9g45_devices.c
arch/arm/mach-at91/at91sam9rl_devices.c
arch/arm/mach-at91/board-sam9261ek.c
arch/arm/mach-at91/board-sam9263ek.c
arch/arm/mach-at91/board-sam9m10g45ek.c
arch/arm/mach-at91/board-sam9rlek.c
arch/arm/mach-at91/board.h
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/include/mach/debug-macro.S [deleted file]
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/dma-mapping.c
arch/arm/mm/init.c
arch/arm/mm/mmu.c
arch/arm/mm/proc-v7-2level.S
arch/arm/mm/proc-v7-3level.S
arch/arm/mm/proc-v7.S
arch/arm/vfp/vfphw.S
arch/arm/vfp/vfpmodule.c
arch/arm/xen/enlighten.c
arch/arm64/mm/init.c
arch/avr32/boards/atngw100/evklcd10x.c
arch/avr32/boards/atngw100/mrmt.c
arch/avr32/boards/atstk1000/atstk1000.h
arch/avr32/boards/atstk1000/setup.c
arch/avr32/boards/favr-32/setup.c
arch/avr32/boards/hammerhead/setup.c
arch/avr32/boards/merisc/display.c
arch/avr32/boards/mimc200/setup.c
arch/avr32/mach-at32ap/at32ap700x.c
arch/avr32/mach-at32ap/include/mach/board.h
arch/c6x/kernel/devicetree.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/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/ia64/kvm/kvm-ia64.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/metag/mm/init.c
arch/microblaze/kernel/prom.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/prom.c
arch/mips/kernel/smp-bmips.c
arch/mips/kvm/kvm_mips.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/powertv/asic/asic_devices.c
arch/openrisc/kernel/prom.c
arch/parisc/configs/c8000_defconfig [new file with mode: 0644]
arch/parisc/configs/generic-32bit_defconfig [new file with mode: 0644]
arch/parisc/configs/generic-64bit_defconfig [new file with mode: 0644]
arch/parisc/include/asm/parisc-device.h
arch/parisc/kernel/cache.c
arch/parisc/kernel/inventory.c
arch/parisc/kernel/signal.c
arch/parisc/kernel/signal32.c
arch/parisc/kernel/sys32.h [deleted file]
arch/parisc/kernel/sys_parisc32.c
arch/powerpc/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/spu.h
arch/powerpc/kernel/prom.c
arch/powerpc/kvm/powerpc.c
arch/powerpc/perf/power7-events-list.h [new file with mode: 0644]
arch/powerpc/perf/power7-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/kvm_host.h
arch/s390/include/asm/mmu.h
arch/s390/include/asm/mmu_context.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/processor.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/kvm/diag.c
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/kvm-s390.h
arch/s390/kvm/priv.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/tile/include/asm/cacheflush.h
arch/tile/include/asm/cmpxchg.h
arch/tile/include/asm/uaccess.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/cacheflush.c
arch/tile/lib/exports.c
arch/tile/lib/usercopy_32.S
arch/tile/lib/usercopy_64.S
arch/x86/Kconfig
arch/x86/boot/compressed/eboot.c
arch/x86/ia32/ia32_aout.c
arch/x86/ia32/ia32entry.S
arch/x86/include/asm/acpi.h
arch/x86/include/asm/alternative.h
arch/x86/include/asm/bitops.h
arch/x86/include/asm/cpufeature.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/mce.h
arch/x86/include/asm/mutex_64.h
arch/x86/include/asm/processor.h
arch/x86/include/asm/pvclock.h
arch/x86/include/asm/sync_bitops.h
arch/x86/include/asm/tsc.h
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/alternative.c
arch/x86/kernel/apic/apic.c
arch/x86/kernel/cpu/mcheck/mce-internal.h
arch/x86/kernel/cpu/mcheck/mce.c
arch/x86/kernel/cpu/mcheck/mce_intel.c
arch/x86/kernel/cpu/perf_event.c
arch/x86/kernel/devicetree.c
arch/x86/kernel/early-quirks.c
arch/x86/kernel/head_32.S
arch/x86/kernel/i387.c
arch/x86/kernel/jump_label.c
arch/x86/kernel/kprobes/common.h
arch/x86/kernel/kprobes/core.c
arch/x86/kernel/kprobes/opt.c
arch/x86/kernel/pvclock.c
arch/x86/kernel/traps.c
arch/x86/kernel/tsc.c
arch/x86/kvm/lapic.c
arch/x86/kvm/mmu.c
arch/x86/kvm/pmu.c
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/lguest/boot.c
arch/x86/pci/i386.c
arch/x86/um/elfcore.c
arch/x86/vdso/vclock_gettime.c
arch/xtensa/kernel/setup.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/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/apei/ghes.c
drivers/acpi/apei/hest.c
drivers/acpi/battery.c
drivers/acpi/bus.c
drivers/acpi/button.c
drivers/acpi/dock.c
drivers/acpi/ec.c
drivers/acpi/event.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.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/Kconfig
drivers/base/Makefile
drivers/base/power/main.c
drivers/base/regmap/regmap-irq.c
drivers/base/regmap/regmap.c
drivers/bcma/Kconfig
drivers/bcma/main.c
drivers/bcma/scan.c
drivers/bluetooth/btmrvl_debugfs.c
drivers/char/agp/parisc-agp.c
drivers/char/sonypi.c
drivers/char/virtio_console.c
drivers/clocksource/Makefile
drivers/clocksource/cadence_ttc_timer.c
drivers/clocksource/moxart_timer.c [new file with mode: 0644]
drivers/clocksource/sun4i_timer.c
drivers/clocksource/time-orion.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/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/caam/caamalg.c
drivers/crypto/caam/caamhash.c
drivers/crypto/caam/desc_constr.h
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/amd64_edac.c
drivers/edac/edac_mc_sysfs.c
drivers/edac/tile_edac.c
drivers/firewire/core-cdev.c
drivers/firewire/core-transaction.c
drivers/firewire/ohci.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_drm_gem.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/nouveau/nouveau_display.c
drivers/gpu/drm/nouveau/nouveau_drm.c
drivers/gpu/drm/nouveau/nouveau_gem.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/cik.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/ni.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_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/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-core.c
drivers/hid/hid-ids.h
drivers/hid/hid-kye.c
drivers/hid/hid-logitech-dj.c
drivers/hid/hid-magicmouse.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-xinmo.c [new file with mode: 0644]
drivers/hid/usbhid/hid-core.c
drivers/hwmon/coretemp.c
drivers/hwmon/nct6775.c
drivers/hwmon/w83792d.c
drivers/isdn/hardware/mISDN/hfcpci.c
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/leds-88pm860x.c
drivers/leds/leds-adp5520.c
drivers/leds/leds-asic3.c
drivers/leds/leds-atmel-pwm.c
drivers/leds/leds-bd2802.c
drivers/leds/leds-da903x.c
drivers/leds/leds-da9052.c
drivers/leds/leds-gpio.c
drivers/leds/leds-lm3530.c
drivers/leds/leds-lm3533.c
drivers/leds/leds-lm355x.c
drivers/leds/leds-lm3642.c
drivers/leds/leds-lp3944.c
drivers/leds/leds-lp5521.c
drivers/leds/leds-lp5523.c
drivers/leds/leds-lp5562.c
drivers/leds/leds-lp55xx-common.c
drivers/leds/leds-lp8501.c [new file with mode: 0644]
drivers/leds/leds-lt3593.c
drivers/leds/leds-netxbig.c
drivers/leds/leds-ns2.c
drivers/leds/leds-pca9532.c
drivers/leds/leds-pca955x.c
drivers/leds/leds-pca9633.c
drivers/leds/leds-pwm.c
drivers/leds/leds-regulator.c
drivers/leds/leds-renesas-tpu.c
drivers/leds/leds-s3c24xx.c
drivers/leds/leds-tca6507.c
drivers/leds/leds-wm831x-status.c
drivers/leds/leds-wm8350.c
drivers/md/md.c
drivers/md/md.h
drivers/md/raid5.c
drivers/md/raid5.h
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_main.c
drivers/net/bonding/bond_sysfs.c
drivers/net/can/usb/esd_usb2.c
drivers/net/can/usb/usb_8dev.c
drivers/net/ethernet/allwinner/Kconfig
drivers/net/ethernet/broadcom/Kconfig
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/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_dcb_82598.c
drivers/net/ethernet/marvell/mvneta.c
drivers/net/ethernet/mellanox/mlx4/cmd.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/mlx5/core/cmd.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/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/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/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/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/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/phy.h
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.c
drivers/net/wireless/iwlwifi/dvm/main.c
drivers/net/wireless/iwlwifi/iwl-prph.h
drivers/net/wireless/iwlwifi/mvm/d3.c
drivers/net/wireless/iwlwifi/mvm/debugfs.c
drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/scan.c
drivers/net/wireless/iwlwifi/mvm/sta.c
drivers/net/wireless/iwlwifi/pcie/drv.c
drivers/net/wireless/iwlwifi/pcie/rx.c
drivers/net/wireless/iwlwifi/pcie/trans.c
drivers/net/wireless/mwifiex/11n_aggr.c
drivers/net/wireless/mwifiex/cfg80211.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/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/usb.c
drivers/of/fdt.c
drivers/of/platform.c
drivers/parisc/iosapic.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/pci-acpi.c
drivers/pci/pci.c
drivers/pci/pcie/Kconfig
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/regulator/88pm800.c [new file with mode: 0644]
drivers/regulator/88pm8607.c
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/aat2870-regulator.c
drivers/regulator/ab3100.c
drivers/regulator/ad5398.c
drivers/regulator/as3711-regulator.c
drivers/regulator/core.c
drivers/regulator/da903x.c
drivers/regulator/da9052-regulator.c
drivers/regulator/da9055-regulator.c
drivers/regulator/fan53555.c
drivers/regulator/fixed.c
drivers/regulator/gpio-regulator.c
drivers/regulator/isl6271a-regulator.c
drivers/regulator/lp3971.c
drivers/regulator/lp3972.c
drivers/regulator/lp872x.c
drivers/regulator/lp8755.c
drivers/regulator/max1586.c
drivers/regulator/max8649.c
drivers/regulator/max8660.c
drivers/regulator/max8925-regulator.c
drivers/regulator/max8952.c
drivers/regulator/max8973-regulator.c
drivers/regulator/of_regulator.c
drivers/regulator/palmas-regulator.c
drivers/regulator/pcap-regulator.c
drivers/regulator/pcf50633-regulator.c
drivers/regulator/pfuze100-regulator.c [new file with mode: 0644]
drivers/regulator/s2mps11.c
drivers/regulator/tps51632-regulator.c
drivers/regulator/tps62360-regulator.c
drivers/regulator/tps65023-regulator.c
drivers/regulator/tps6524x-regulator.c
drivers/regulator/tps65912-regulator.c
drivers/regulator/twl-regulator.c
drivers/regulator/userspace-consumer.c
drivers/regulator/virtual.c
drivers/regulator/wm831x-dcdc.c
drivers/regulator/wm831x-isink.c
drivers/regulator/wm831x-ldo.c
drivers/regulator/wm8350-regulator.c
drivers/regulator/wm8400-regulator.c
drivers/regulator/wm8994-regulator.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/spi/Kconfig
drivers/spi/Makefile
drivers/spi/spi-atmel.c
drivers/spi/spi-bcm2835.c
drivers/spi/spi-bcm63xx.c
drivers/spi/spi-bfin-v3.c [new file with mode: 0644]
drivers/spi/spi-bitbang.c
drivers/spi/spi-clps711x.c
drivers/spi/spi-coldfire-qspi.c
drivers/spi/spi-davinci.c
drivers/spi/spi-ep93xx.c
drivers/spi/spi-imx.c
drivers/spi/spi-mxs.c
drivers/spi/spi-omap-100k.c
drivers/spi/spi-omap2-mcspi.c
drivers/spi/spi-orion.c
drivers/spi/spi-pl022.c
drivers/spi/spi-pxa2xx.c
drivers/spi/spi-s3c64xx.c
drivers/spi/spi-sh-hspi.c
drivers/spi/spi-sh-msiof.c
drivers/spi/spi-sirf.c
drivers/spi/spi-tegra114.c
drivers/spi/spi-tegra20-sflash.c
drivers/spi/spi-tegra20-slink.c
drivers/spi/spi-tle62x0.c
drivers/spi/spi-txx9.c
drivers/spi/spi-xilinx.c
drivers/spi/spi.c
drivers/staging/zcache/zcache-main.c
drivers/tty/serial/8250/8250_gsc.c
drivers/tty/serial/arc_uart.c
drivers/tty/serial/mxs-auart.c
drivers/tty/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/Kconfig
drivers/video/atmel_lcdfb.c
drivers/xen/Makefile
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/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/connect.c
fs/cifs/link.c
fs/cifs/sess.c
fs/cifs/smb1ops.c
fs/coredump.c
fs/dlm/ast.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/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/xattr.h
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_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/ata.h
include/linux/atmel-ssc.h
include/linux/bcma/bcma.h
include/linux/binfmts.h
include/linux/coda.h
include/linux/coredump.h
include/linux/cpufreq.h
include/linux/cpuidle.h
include/linux/debugobjects.h
include/linux/dma-contiguous.h
include/linux/dmaengine.h
include/linux/elf.h
include/linux/elfcore.h
include/linux/firewire.h
include/linux/hid.h
include/linux/if_team.h
include/linux/igmp.h
include/linux/ktime.h
include/linux/kvm_host.h
include/linux/libata.h
include/linux/lockdep.h
include/linux/mfd/arizona/gpio.h [new file with mode: 0644]
include/linux/mfd/samsung/s2mps11.h
include/linux/mlx4/cmd.h
include/linux/mlx4/device.h
include/linux/mm.h
include/linux/mod_devicetable.h
include/linux/mtd/fsmc.h
include/linux/mtd/nand.h
include/linux/netdevice.h
include/linux/nodemask.h
include/linux/of.h
include/linux/of_fdt.h
include/linux/pci-acpi.h
include/linux/platform_data/atmel.h
include/linux/platform_data/elm.h
include/linux/platform_data/leds-lp55xx.h
include/linux/platform_data/leds-pca9633.h
include/linux/raid/pq.h
include/linux/rcupdate.h
include/linux/regmap.h
include/linux/regulator/consumer.h
include/linux/regulator/driver.h
include/linux/regulator/machine.h
include/linux/regulator/pfuze100.h [new file with mode: 0644]
include/linux/sched.h
include/linux/security.h
include/linux/serial_sci.h
include/linux/spi/spi.h
include/linux/spi/spi_bitbang.h
include/linux/tcp.h
include/linux/tick.h
include/linux/usb/usbnet.h
include/linux/workqueue.h
include/linux/xattr.h
include/net/9p/transport.h
include/net/af_vsock.h [moved from net/vmw_vsock/af_vsock.h with 100% similarity]
include/net/bluetooth/hci.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/trace/events/power.h
include/uapi/drm/drm.h
include/uapi/drm/i915_drm.h
include/uapi/linux/firewire-cdev.h
include/uapi/linux/if_tun.h
include/uapi/linux/perf_event.h
include/uapi/linux/reiserfs_xattr.h
include/uapi/linux/sctp.h
include/uapi/linux/tcp.h
include/uapi/linux/virtio_net.h
include/video/atmel_lcdc.h
kernel/cgroup.c
kernel/cpuset.c
kernel/elfcore.c
kernel/events/core.c
kernel/lglock.c
kernel/mutex.c
kernel/power/suspend.c
kernel/rcu.h
kernel/rcupdate.c
kernel/rcutorture.c
kernel/rcutree.c
kernel/rcutree.h
kernel/rcutree_plugin.h
kernel/sched/core.c
kernel/sched/cpupri.c
kernel/sched/fair.c
kernel/sched/sched.h
kernel/sysctl.c
kernel/time/Kconfig
kernel/time/tick-sched.c
kernel/trace/ftrace.c
kernel/trace/trace_events.c
kernel/trace/trace_events_filter.c
kernel/workqueue.c
lib/debugobjects.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/Kconfig
mm/memory-failure.c
mm/slub.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_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/neighbour.c
net/core/pktgen.c
net/core/skbuff.c
net/core/sock.c
net/core/stream.c
net/dccp/proto.c
net/ipv4/fib_trie.c
net/ipv4/igmp.c
net/ipv4/ip_vti.c
net/ipv4/ipmr.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/ip6_fib.c
net/ipv6/ip6mr.c
net/ipv6/mcast.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/mesh_ps.c
net/mac80211/pm.c
net/mac80211/rc80211_minstrel.c
net/mac80211/rc80211_minstrel_ht.c
net/mac80211/rx.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/packet/af_packet.c
net/sched/sch_cbq.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/sunrpc/rpc_pipe.c
net/sunrpc/svcsock.c
net/sunrpc/xprtsock.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/nl80211.c
net/wireless/reg.c
net/wireless/sme.c
net/xfrm/xfrm_state.c
scripts/kconfig/mconf.c
scripts/kconfig/nconf.c
scripts/kconfig/symbol.c
scripts/package/builddeb
scripts/package/mkspec
security/capability.c
security/integrity/evm/evm_main.c
security/security.c
security/selinux/hooks.c
security/selinux/include/objsec.h
security/selinux/include/security.h
security/selinux/include/xfrm.h
security/selinux/netnode.c
security/selinux/selinuxfs.c
security/selinux/ss/ebitmap.c
security/selinux/ss/ebitmap.h
security/selinux/ss/mls.c
security/selinux/ss/mls_types.h
security/selinux/ss/policydb.c
security/selinux/ss/services.c
security/selinux/xfrm.c
security/smack/smack_lsm.c
sound/core/compress_offload.c
sound/drivers/dummy.c
sound/firewire/speakers.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_generic.c
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_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/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/pcm3008.c
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/sta32x.c
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/twl6040.c
sound/soc/codecs/uda134x.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-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/lib/traceevent/Makefile
tools/lib/traceevent/event-parse.c
tools/lib/traceevent/event-parse.h
tools/lib/traceevent/kbuffer-parse.c [new file with mode: 0644]
tools/lib/traceevent/kbuffer.h [new file with mode: 0644]
tools/lib/traceevent/trace-seq.c
tools/perf/Documentation/perf-diff.txt
tools/perf/Documentation/perf-list.txt
tools/perf/Documentation/perf-report.txt
tools/perf/Documentation/perf-top.txt
tools/perf/Makefile
tools/perf/arch/x86/Makefile
tools/perf/arch/x86/util/tsc.c [new file with mode: 0644]
tools/perf/arch/x86/util/tsc.h [new file with mode: 0644]
tools/perf/bench/mem-memcpy.c
tools/perf/builtin-diff.c
tools/perf/builtin-inject.c
tools/perf/builtin-kmem.c
tools/perf/builtin-list.c
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-sched.c
tools/perf/builtin-script.c
tools/perf/builtin-timechart.c
tools/perf/builtin-top.c
tools/perf/builtin-trace.c
tools/perf/config/Makefile
tools/perf/tests/builtin-test.c
tools/perf/tests/dso-data.c
tools/perf/tests/evsel-tp-sched.c
tools/perf/tests/make
tools/perf/tests/parse-events.c
tools/perf/tests/perf-time-to-tsc.c [new file with mode: 0644]
tools/perf/tests/tests.h
tools/perf/tests/vmlinux-kallsyms.c
tools/perf/ui/browsers/hists.c
tools/perf/ui/gtk/hists.c
tools/perf/ui/hist.c
tools/perf/ui/setup.c
tools/perf/ui/stdio/hist.c
tools/perf/util/callchain.c
tools/perf/util/callchain.h
tools/perf/util/cpumap.h
tools/perf/util/event.c
tools/perf/util/event.h
tools/perf/util/evlist.c
tools/perf/util/evsel.c
tools/perf/util/header.c
tools/perf/util/header.h
tools/perf/util/hist.c
tools/perf/util/hist.h
tools/perf/util/include/linux/string.h
tools/perf/util/machine.c
tools/perf/util/machine.h
tools/perf/util/parse-events.c
tools/perf/util/parse-events.h
tools/perf/util/parse-events.y
tools/perf/util/pmu.c
tools/perf/util/pmu.h
tools/perf/util/scripting-engines/trace-event-perl.c
tools/perf/util/scripting-engines/trace-event-python.c
tools/perf/util/session.c
tools/perf/util/session.h
tools/perf/util/sort.c
tools/perf/util/sort.h
tools/perf/util/string.c
tools/perf/util/symbol.c
tools/perf/util/thread.c
tools/perf/util/thread.h
tools/perf/util/tool.h
tools/perf/util/trace-event-info.c
tools/perf/util/trace-event-parse.c
tools/perf/util/trace-event-read.c
tools/perf/util/trace-event-scripting.c
tools/perf/util/trace-event.h
tools/perf/util/util.c
tools/perf/util/util.h
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]
virt/kvm/kvm_main.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 7f40c72a9c515078afe5fa2b0c7da2d09cebfedb..350be9ab3135f59ead842c3861f0329343df1e76 100644 (file)
@@ -39,7 +39,7 @@ in read-mostly situations.  This algorithm does take pains to avoid
 write-side contention and parallelize the other write-side overheads by
 providing a fine-grained locking design, however, it would be interesting
 to see how much of the performance advantage reported in 1990 remains
-in 2004.
+in 2004 (to say nothing of 2013).
 
 At about this same time, Adams [Adams91] described ``chaotic relaxation'',
 where the normal barriers between successive iterations of convergent
@@ -86,9 +86,9 @@ DYNIX/ptx kernel.  The corresponding conference paper appeared in 1998
 [McKenney98].
 
 In 1999, the Tornado and K42 groups described their "generations"
-mechanism, which quite similar to RCU [Gamsa99].  These operating systems
-made pervasive use of RCU in place of "existence locks", which greatly
-simplifies locking hierarchies.
+mechanism, which is quite similar to RCU [Gamsa99].  These operating
+systems made pervasive use of RCU in place of "existence locks", which
+greatly simplifies locking hierarchies and helps avoid deadlocks.
 
 2001 saw the first RCU presentation involving Linux [McKenney01a]
 at OLS.  The resulting abundance of RCU patches was presented the
@@ -106,8 +106,11 @@ these techniques still impose significant read-side overhead in the
 form of memory barriers.  Researchers at Sun worked along similar lines
 in the same timeframe [HerlihyLM02].  These techniques can be thought
 of as inside-out reference counts, where the count is represented by the
-number of hazard pointers referencing a given data structure (rather than
-the more conventional counter field within the data structure itself).
+number of hazard pointers referencing a given data structure rather than
+the more conventional counter field within the data structure itself.
+The key advantage of inside-out reference counts is that they can be
+stored in immortal variables, thus allowing races between access and
+deletion to be avoided.
 
 By the same token, RCU can be thought of as a "bulk reference count",
 where some form of reference counter covers all reference by a given CPU
@@ -179,7 +182,25 @@ tree using software transactional memory to protect concurrent updates
 (strange, but true!) [PhilHoward2011RCUTMRBTree], yet another variant of
 RCU-protected resizeable hash tables [Triplett:2011:RPHash], the 3.0 RCU
 trainwreck [PaulEMcKenney2011RCU3.0trainwreck], and Neil Brown's "Meet the
-Lockers" LWN article [NeilBrown2011MeetTheLockers].
+Lockers" LWN article [NeilBrown2011MeetTheLockers].  Some academic
+work looked at debugging uses of RCU [Seyster:2011:RFA:2075416.2075425].
+
+In 2012, Josh Triplett received his Ph.D. with his dissertation
+covering RCU-protected resizable hash tables and the relationship
+between memory barriers and read-side traversal order:  If the updater
+is making changes in the opposite direction from the read-side traveral
+order, the updater need only execute a memory-barrier instruction,
+but if in the same direction, the updater needs to wait for a grace
+period between the individual updates [JoshTriplettPhD].  Also in 2012,
+after seventeen years of attempts, an RCU paper made it into a top-flight
+academic journal, IEEE Transactions on Parallel and Distributed Systems
+[MathieuDesnoyers2012URCU].  A group of researchers in Spain applied
+user-level RCU to crowd simulation [GuillermoVigueras2012RCUCrowd], and
+another group of researchers in Europe produced a formal description of
+RCU based on separation logic [AlexeyGotsman2012VerifyGraceExtended],
+which was published in the 2013 European Symposium on Programming
+[AlexeyGotsman2013ESOPRCU].
+
 
 
 Bibtex Entries
@@ -193,13 +214,12 @@ Bibtex Entries
 ,volume="5"
 ,number="3"
 ,pages="354-382"
-,note="Available:
-\url{http://portal.acm.org/citation.cfm?id=320619&dl=GUIDE,}
-[Viewed December 3, 2007]"
 ,annotation={
        Use garbage collector to clean up data after everyone is done with it.
        .
        Oldest use of something vaguely resembling RCU that I have found.
+       http://portal.acm.org/citation.cfm?id=320619&dl=GUIDE,
+       [Viewed December 3, 2007]
 }
 }
 
@@ -309,7 +329,7 @@ for Programming Languages and Operating Systems}"
 ,doi = {http://doi.acm.org/10.1145/42392.42399}
 ,publisher = {ACM}
 ,address = {New York, NY, USA}
-,annotation= {
+,annotation={
        At the top of page 307: "Conflicts with deposits and withdrawals
        are necessary if the reported total is to be up to date.  They
        could be avoided by having total return a sum that is slightly
@@ -346,8 +366,9 @@ for Programming Languages and Operating Systems}"
 }
 }
 
-@Book{Adams91
-,Author="Gregory R. Adams"
+# Was Adams91, see also syncrefs.bib.
+@Book{Andrews91textbook
+,Author="Gregory R. Andrews"
 ,title="Concurrent Programming, Principles, and Practices"
 ,Publisher="Benjamin Cummins"
 ,Year="1991"
@@ -398,39 +419,39 @@ for Programming Languages and Operating Systems}"
 }
 }
 
-@conference{Pu95a,
-Author = "Calton Pu and Tito Autrey and Andrew Black and Charles Consel and
+@conference{Pu95a
+,Author = "Calton Pu and Tito Autrey and Andrew Black and Charles Consel and
 Crispin Cowan and Jon Inouye and Lakshmi Kethana and Jonathan Walpole and
-Ke Zhang",
-Title = "Optimistic Incremental Specialization: Streamlining a Commercial
-Operating System",
-Booktitle = "15\textsuperscript{th} ACM Symposium on
-Operating Systems Principles (SOSP'95)",
-address = "Copper Mountain, CO",
-month="December",
-year="1995",
-pages="314-321",
-annotation="
+Ke Zhang"
+,Title = "Optimistic Incremental Specialization: Streamlining a Commercial
+,Operating System"
+,Booktitle = "15\textsuperscript{th} ACM Symposium on
+,Operating Systems Principles (SOSP'95)"
+,address = "Copper Mountain, CO"
+,month="December"
+,year="1995"
+,pages="314-321"
+,annotation={
        Uses a replugger, but with a flag to signal when people are
        using the resource at hand.  Only one reader at a time.
-"
-}
-
-@conference{Cowan96a,
-Author = "Crispin Cowan and Tito Autrey and Charles Krasic and
-Calton Pu and Jonathan Walpole",
-Title = "Fast Concurrent Dynamic Linking for an Adaptive Operating System",
-Booktitle = "International Conference on Configurable Distributed Systems
-(ICCDS'96)",
-address = "Annapolis, MD",
-month="May",
-year="1996",
-pages="108",
-isbn="0-8186-7395-8",
-annotation="
+}
+}
+
+@conference{Cowan96a
+,Author = "Crispin Cowan and Tito Autrey and Charles Krasic and
+,Calton Pu and Jonathan Walpole"
+,Title = "Fast Concurrent Dynamic Linking for an Adaptive Operating System"
+,Booktitle = "International Conference on Configurable Distributed Systems
+(ICCDS'96)"
+,address = "Annapolis, MD"
+,month="May"
+,year="1996"
+,pages="108"
+,isbn="0-8186-7395-8"
+,annotation={
        Uses a replugger, but with a counter to signal when people are
        using the resource at hand.  Allows multiple readers.
-"
+}
 }
 
 @techreport{Slingwine95
@@ -493,14 +514,13 @@ Problems"
 ,Year="1998"
 ,pages="509-518"
 ,Address="Las Vegas, NV"
-,note="Available:
-\url{http://www.rdrop.com/users/paulmck/RCU/rclockpdcsproof.pdf}
-[Viewed December 3, 2007]"
 ,annotation={
        Describes and analyzes RCU mechanism in DYNIX/ptx.  Describes
        application to linked list update and log-buffer flushing.
        Defines 'quiescent state'.  Includes both measured and analytic
        evaluation.
+       http://www.rdrop.com/users/paulmck/RCU/rclockpdcsproof.pdf
+       [Viewed December 3, 2007]
 }
 }
 
@@ -514,13 +534,12 @@ Operating System Design and Implementation}"
 ,Year="1999"
 ,pages="87-100"
 ,Address="New Orleans, LA"
-,note="Available:
-\url{http://www.usenix.org/events/osdi99/full_papers/gamsa/gamsa.pdf}
-[Viewed August 30, 2006]"
 ,annotation={
        Use of RCU-like facility in K42/Tornado.  Another independent
        invention of RCU.
        See especially pages 7-9 (Section 5).
+       http://www.usenix.org/events/osdi99/full_papers/gamsa/gamsa.pdf
+       [Viewed August 30, 2006]
 }
 }
 
@@ -611,9 +630,9 @@ Orran Krieger and Rusty Russell and Dipankar Sarma and Maneesh Soni"
 ,note="Available:
 \url{http://marc.theaimsgroup.com/?l=linux-kernel&m=100259266316456&w=2}
 [Viewed June 23, 2004]"
-,annotation="
+,annotation={
        Memory-barrier and Alpha thread.  100 messages, not too bad...
-"
+}
 }
 
 @unpublished{Spraul01
@@ -624,10 +643,10 @@ Orran Krieger and Rusty Russell and Dipankar Sarma and Maneesh Soni"
 ,note="Available:
 \url{http://marc.theaimsgroup.com/?l=linux-kernel&m=100264675012867&w=2}
 [Viewed June 23, 2004]"
-,annotation="
+,annotation={
        Suggested burying memory barriers in Linux's list-manipulation
        primitives.
-"
+}
 }
 
 @unpublished{LinusTorvalds2001a
@@ -638,6 +657,8 @@ Orran Krieger and Rusty Russell and Dipankar Sarma and Maneesh Soni"
 ,note="Available:
 \url{http://lkml.org/lkml/2001/10/13/105}
 [Viewed August 21, 2004]"
+,annotation={
+}
 }
 
 @unpublished{Blanchard02a
@@ -657,10 +678,10 @@ Orran Krieger and Rusty Russell and Dipankar Sarma and Maneesh Soni"
 ,Month="June"
 ,Year="2002"
 ,pages="289-300"
-,annotation="
+,annotation={
        Measured scalability of Linux 2.4 kernel's directory-entry cache
        (dcache), and measured some scalability enhancements.
-"
+}
 }
 
 @Conference{McKenney02a
@@ -674,10 +695,10 @@ Andrea Arcangeli and Andi Kleen and Orran Krieger and Rusty Russell"
 ,note="Available:
 \url{http://www.linux.org.uk/~ajh/ols2002_proceedings.pdf.gz}
 [Viewed June 23, 2004]"
-,annotation="
+,annotation={
        Presented and compared a number of RCU implementations for the
        Linux kernel.
-"
+}
 }
 
 @unpublished{Sarma02a
@@ -688,9 +709,9 @@ Andrea Arcangeli and Andi Kleen and Orran Krieger and Rusty Russell"
 ,note="Available:
 \url{http://marc.theaimsgroup.com/?l=linux-kernel&m=102645767914212&w=2}
 [Viewed June 23, 2004]"
-,annotation="
+,annotation={
        Compare fastwalk and RCU for dcache.  RCU won.
-"
+}
 }
 
 @unpublished{Barbieri02
@@ -701,9 +722,9 @@ Andrea Arcangeli and Andi Kleen and Orran Krieger and Rusty Russell"
 ,note="Available:
 \url{http://marc.theaimsgroup.com/?l=linux-kernel&m=103082050621241&w=2}
 [Viewed: June 23, 2004]"
-,annotation="
+,annotation={
        Suggested RCU for vfs\_shared\_cred.
-"
+}
 }
 
 @unpublished{Dickins02a
@@ -722,10 +743,10 @@ Andrea Arcangeli and Andi Kleen and Orran Krieger and Rusty Russell"
 ,note="Available:
 \url{http://marc.theaimsgroup.com/?l=linux-kernel&m=103462075416638&w=2}
 [Viewed June 23, 2004]"
-,annotation="
+,annotation={
        Performance of dcache RCU on kernbench for 16x NUMA-Q and 1x,
        2x, and 4x systems.  RCU does no harm, and helps on 16x.
-"
+}
 }
 
 @unpublished{LinusTorvalds2003a
@@ -736,14 +757,14 @@ Andrea Arcangeli and Andi Kleen and Orran Krieger and Rusty Russell"
 ,note="Available:
 \url{http://lkml.org/lkml/2003/3/9/205}
 [Viewed March 13, 2006]"
-,annotation="
+,annotation={
        Linus suggests replacing brlock with RCU and/or seqlocks:
        .
        'It's entirely possible that the current user could be replaced
        by RCU and/or seqlocks, and we could get rid of brlocks entirely.'
        .
        Steve Hemminger responds by replacing them with RCU.
-"
+}
 }
 
 @article{Appavoo03a
@@ -758,9 +779,9 @@ B. Rosenburg and M. Stumm and J. Xenidis"
 ,volume="42"
 ,number="1"
 ,pages="60-76"
-,annotation="
+,annotation={
        Use of RCU to enable hot-swapping for autonomic behavior in K42.
-"
+}
 }
 
 @unpublished{Seigh03
@@ -769,9 +790,9 @@ B. Rosenburg and M. Stumm and J. Xenidis"
 ,Year="2003"
 ,Month="March"
 ,note="email correspondence"
-,annotation="
+,annotation={
        Described the relationship of the VM/XA passive serialization to RCU.
-"
+}
 }
 
 @Conference{Arcangeli03
@@ -785,14 +806,12 @@ Dipankar Sarma"
 ,year="2003"
 ,month="June"
 ,pages="297-310"
-,note="Available:
-\url{http://www.rdrop.com/users/paulmck/RCU/rcu.FREENIX.2003.06.14.pdf}
-[Viewed November 21, 2007]"
-,annotation="
+,annotation={
        Compared updated RCU implementations for the Linux kernel, and
        described System V IPC use of RCU, including order-of-magnitude
        performance improvements.
-"
+       http://www.rdrop.com/users/paulmck/RCU/rcu.FREENIX.2003.06.14.pdf
+}
 }
 
 @Conference{Soules03a
@@ -820,10 +839,10 @@ Michal Ostrowski and Bryan Rosenburg and Jimi Xenidis"
 ,note="Available:
 \url{http://www.linuxjournal.com/article/6993}
 [Viewed November 14, 2007]"
-,annotation="
+,annotation={
        Reader-friendly intro to RCU, with the infamous old-man-and-brat
        cartoon.
-"
+}
 }
 
 @unpublished{Sarma03a
@@ -832,7 +851,9 @@ Michal Ostrowski and Bryan Rosenburg and Jimi Xenidis"
 ,month="December"
 ,year="2003"
 ,note="Message ID: 20031222180114.GA2248@in.ibm.com"
-,annotation="dipankar/ct.2004.03.27/RCUll.2003.12.22.patch"
+,annotation={
+       dipankar/ct.2004.03.27/RCUll.2003.12.22.patch
+}
 }
 
 @techreport{Friedberg03a
@@ -844,11 +865,11 @@ Michal Ostrowski and Bryan Rosenburg and Jimi Xenidis"
 ,number="US Patent 6,662,184"
 ,month="December"
 ,pages="112"
-,annotation="
+,annotation={
        Applies RCU to a wildcard-search Patricia tree in order to permit
        synchronization-free lookup.  RCU is used to retain removed nodes
        for a grace period before freeing them.
-"
+}
 }
 
 @article{McKenney04a
@@ -860,12 +881,11 @@ Michal Ostrowski and Bryan Rosenburg and Jimi Xenidis"
 ,volume="1"
 ,number="118"
 ,pages="38-46"
-,note="Available:
-\url{http://www.linuxjournal.com/node/7124}
-[Viewed December 26, 2010]"
-,annotation="
+,annotation={
        Reader friendly intro to dcache and RCU.
-"
+       http://www.linuxjournal.com/node/7124
+       [Viewed December 26, 2010]
+}
 }
 
 @Conference{McKenney04b
@@ -879,10 +899,10 @@ Michal Ostrowski and Bryan Rosenburg and Jimi Xenidis"
 \url{http://www.linux.org.au/conf/2004/abstracts.html#90}
 \url{http://www.rdrop.com/users/paulmck/RCU/lockperf.2004.01.17a.pdf}
 [Viewed June 23, 2004]"
-,annotation="
+,annotation={
        Compares performance of RCU to that of other locking primitives
        over a number of CPUs (x86, Opteron, Itanium, and PPC).
-"
+}
 }
 
 @unpublished{Sarma04a
@@ -891,7 +911,9 @@ Michal Ostrowski and Bryan Rosenburg and Jimi Xenidis"
 ,month="March"
 ,year="2004"
 ,note="\url{http://marc.theaimsgroup.com/?l=linux-kernel&m=108003746402892&w=2}"
-,annotation="Head of thread: dipankar/2004.03.23/rcu-low-lat.1.patch"
+,annotation={
+       Head of thread: dipankar/2004.03.23/rcu-low-lat.1.patch
+}
 }
 
 @unpublished{Sarma04b
@@ -900,7 +922,9 @@ Michal Ostrowski and Bryan Rosenburg and Jimi Xenidis"
 ,month="March"
 ,year="2004"
 ,note="\url{http://marc.theaimsgroup.com/?l=linux-kernel&m=108016474829546&w=2}"
-,annotation="dipankar/rcuth.2004.03.24/rcu-throttle.patch"
+,annotation={
+       dipankar/rcuth.2004.03.24/rcu-throttle.patch
+}
 }
 
 @unpublished{Spraul04a
@@ -911,9 +935,9 @@ Michal Ostrowski and Bryan Rosenburg and Jimi Xenidis"
 ,note="Available:
 \url{http://marc.theaimsgroup.com/?l=linux-kernel&m=108546407726602&w=2}
 [Viewed June 23, 2004]"
-,annotation="
+,annotation={
        Hierarchical-bitmap patch for RCU infrastructure.
-"
+}
 }
 
 @unpublished{Steiner04a
@@ -950,10 +974,12 @@ Realtime Applications"
 ,year="2004"
 ,month="June"
 ,pages="182-191"
-,annotation="
+,annotation={
        Describes and compares a number of modifications to the Linux RCU
        implementation that make it friendly to realtime applications.
-"
+       https://www.usenix.org/conference/2004-usenix-annual-technical-conference/making-rcu-safe-deep-sub-millisecond-response
+       [Viewed July 26, 2012]
+}
 }
 
 @phdthesis{PaulEdwardMcKenneyPhD
@@ -964,14 +990,13 @@ in Operating System Kernels"
 ,school="OGI School of Science and Engineering at
 Oregon Health and Sciences University"
 ,year="2004"
-,note="Available:
-\url{http://www.rdrop.com/users/paulmck/RCU/RCUdissertation.2004.07.14e1.pdf}
-[Viewed October 15, 2004]"
-,annotation="
+,annotation={
        Describes RCU implementations and presents design patterns
        corresponding to common uses of RCU in several operating-system
        kernels.
-"
+       http://www.rdrop.com/users/paulmck/RCU/RCUdissertation.2004.07.14e1.pdf
+       [Viewed October 15, 2004]
+}
 }
 
 @unpublished{PaulEMcKenney2004rcu:dereference
@@ -982,9 +1007,9 @@ Oregon Health and Sciences University"
 ,note="Available:
 \url{http://lkml.org/lkml/2004/8/6/237}
 [Viewed June 8, 2010]"
-,annotation="
+,annotation={
        Introduce rcu_dereference().
-"
+}
 }
 
 @unpublished{JimHouston04a
@@ -995,11 +1020,11 @@ Oregon Health and Sciences University"
 ,note="Available:
 \url{http://lkml.org/lkml/2004/8/30/87}
 [Viewed February 17, 2005]"
-,annotation="
+,annotation={
        Uses active code in rcu_read_lock() and rcu_read_unlock() to
        make RCU happen, allowing RCU to function on CPUs that do not
        receive a scheduling-clock interrupt.
-"
+}
 }
 
 @unpublished{TomHart04a
@@ -1010,9 +1035,9 @@ Oregon Health and Sciences University"
 ,note="Available:
 \url{http://www.cs.toronto.edu/~tomhart/masters_thesis.html}
 [Viewed October 15, 2004]"
-,annotation="
+,annotation={
        Proposes comparing RCU to lock-free methods for the Linux kernel.
-"
+}
 }
 
 @unpublished{Vaddagiri04a
@@ -1023,9 +1048,9 @@ Oregon Health and Sciences University"
 ,note="Available:
 \url{http://marc.theaimsgroup.com/?t=109395731700004&r=1&w=2}
 [Viewed October 18, 2004]"
-,annotation="
+,annotation={
        Srivatsa's RCU patch for tcp_ehash lookup.
-"
+}
 }
 
 @unpublished{Thirumalai04a
@@ -1036,9 +1061,9 @@ Oregon Health and Sciences University"
 ,note="Available:
 \url{http://marc.theaimsgroup.com/?t=109144217400003&r=1&w=2}
 [Viewed October 18, 2004]"
-,annotation="
+,annotation={
        Ravikiran's lockfree FD patch.
-"
+}
 }
 
 @unpublished{Thirumalai04b
@@ -1049,9 +1074,9 @@ Oregon Health and Sciences University"
 ,note="Available:
 \url{http://marc.theaimsgroup.com/?l=linux-kernel&m=109152521410459&w=2}
 [Viewed October 18, 2004]"
-,annotation="
+,annotation={
        Ravikiran's lockfree FD patch.
-"
+}
 }
 
 @unpublished{PaulEMcKenney2004rcu:assign:pointer
@@ -1062,9 +1087,9 @@ Oregon Health and Sciences University"
 ,note="Available:
 \url{http://lkml.org/lkml/2004/10/23/241}
 [Viewed June 8, 2010]"
-,annotation="
+,annotation={
        Introduce rcu_assign_pointer().
-"
+}
 }
 
 @unpublished{JamesMorris04a
@@ -1073,12 +1098,12 @@ Oregon Health and Sciences University"
 ,day="15"
 ,month="November"
 ,year="2004"
-,note="Available:
-\url{http://marc.theaimsgroup.com/?l=linux-kernel&m=110054979416004&w=2}
-[Viewed December 10, 2004]"
-,annotation="
+,note="\url{http://marc.theaimsgroup.com/?l=linux-kernel&m=110054979416004&w=2}"
+,annotation={
        James Morris posts Kaigai Kohei's patch to LKML.
-"
+       [Viewed December 10, 2004]
+       Kaigai's patch is at https://lkml.org/lkml/2004/9/27/52
+}
 }
 
 @unpublished{JamesMorris04b
@@ -1089,9 +1114,9 @@ Oregon Health and Sciences University"
 ,note="Available:
 \url{http://www.livejournal.com/users/james_morris/2153.html}
 [Viewed December 10, 2004]"
-,annotation="
+,annotation={
        RCU helps SELinux performance.  ;-)  Made LWN.
-"
+}
 }
 
 @unpublished{PaulMcKenney2005RCUSemantics
@@ -1103,9 +1128,9 @@ Oregon Health and Sciences University"
 ,note="Available:
 \url{http://www.rdrop.com/users/paulmck/RCU/rcu-semantics.2005.01.30a.pdf}
 [Viewed December 6, 2009]"
-,annotation="
+,annotation={
        Early derivation of RCU semantics.
-"
+}
 }
 
 @unpublished{PaulMcKenney2005e
@@ -1117,10 +1142,10 @@ Oregon Health and Sciences University"
 ,note="Available:
 \url{http://lkml.org/lkml/2005/3/17/199}
 [Viewed September 5, 2005]"
-,annotation="
+,annotation={
        First posting showing how RCU can be safely adapted for
        preemptable RCU read side critical sections.
-"
+}
 }
 
 @unpublished{EsbenNeilsen2005a
@@ -1132,12 +1157,12 @@ Oregon Health and Sciences University"
 ,note="Available:
 \url{http://lkml.org/lkml/2005/3/18/122}
 [Viewed March 30, 2006]"
-,annotation="
+,annotation={
        Esben Neilsen suggests read-side suppression of grace-period
        processing for crude-but-workable realtime RCU.  The downside
-       is indefinite grace periods...But this is OK for experimentation
+       is indefinite grace periods...  But this is OK for experimentation
        and testing.
-"
+}
 }
 
 @unpublished{TomHart05a
@@ -1149,10 +1174,10 @@ Data Structures"
 ,note="Available:
 \url{ftp://ftp.cs.toronto.edu/csrg-technical-reports/515/}
 [Viewed March 4, 2005]"
-,annotation="
+,annotation={
        Comparison of RCU, QBSR, and EBSR.  RCU wins for read-mostly
        workloads.  ;-)
-"
+}
 }
 
 @unpublished{JonCorbet2005DeprecateSyncKernel
@@ -1164,10 +1189,10 @@ Data Structures"
 ,note="Available:
 \url{http://lwn.net/Articles/134484/}
 [Viewed May 3, 2005]"
-,annotation="
+,annotation={
        Jon Corbet describes deprecation of synchronize_kernel()
        in favor of synchronize_rcu() and synchronize_sched().
-"
+}
 }
 
 @unpublished{PaulMcKenney05a
@@ -1178,10 +1203,10 @@ Data Structures"
 ,note="Available:
 \url{http://lkml.org/lkml/2005/5/9/185}
 [Viewed May 13, 2005]"
-,annotation="
+,annotation={
        First publication of working lock-based deferred free patches
        for the CONFIG_PREEMPT_RT environment.
-"
+}
 }
 
 @conference{PaulMcKenney05b
@@ -1194,10 +1219,10 @@ Data Structures"
 ,note="Available:
 \url{http://www.rdrop.com/users/paulmck/RCU/realtimeRCU.2005.04.23a.pdf}
 [Viewed May 13, 2005]"
-,annotation="
+,annotation={
        Realtime turns into making RCU yet more realtime friendly.
        http://lca2005.linux.org.au/Papers/Paul%20McKenney/Towards%20Hard%20Realtime%20Response%20from%20the%20Linux%20Kernel/LKS.2005.04.22a.pdf
-"
+}
 }
 
 @unpublished{PaulEMcKenneyHomePage
@@ -1208,9 +1233,9 @@ Data Structures"
 ,note="Available:
 \url{http://www.rdrop.com/users/paulmck/}
 [Viewed May 25, 2005]"
-,annotation="
+,annotation={
        Paul McKenney's home page.
-"
+}
 }
 
 @unpublished{PaulEMcKenneyRCUPage
@@ -1221,9 +1246,9 @@ Data Structures"
 ,note="Available:
 \url{http://www.rdrop.com/users/paulmck/RCU}
 [Viewed May 25, 2005]"
-,annotation="
+,annotation={
        Paul McKenney's RCU page.
-"
+}
 }
 
 @unpublished{JosephSeigh2005a
@@ -1232,10 +1257,10 @@ Data Structures"
 ,month="July"
 ,year="2005"
 ,note="Personal communication"
-,annotation="
+,annotation={
        Joe Seigh announcing his atomic-ptr-plus project.
        http://sourceforge.net/projects/atomic-ptr-plus/
-"
+}
 }
 
 @unpublished{JosephSeigh2005b
@@ -1247,9 +1272,9 @@ Data Structures"
 ,note="Available:
 \url{http://sourceforge.net/projects/atomic-ptr-plus/}
 [Viewed August 8, 2005]"
-,annotation="
+,annotation={
        Joe Seigh's atomic-ptr-plus project.
-"
+}
 }
 
 @unpublished{PaulMcKenney2005c
@@ -1261,9 +1286,9 @@ Data Structures"
 ,note="Available:
 \url{http://lkml.org/lkml/2005/8/1/155}
 [Viewed March 14, 2006]"
-,annotation="
+,annotation={
        First operating counter-based realtime RCU patch posted to LKML.
-"
+}
 }
 
 @unpublished{PaulMcKenney2005d
@@ -1275,11 +1300,11 @@ Data Structures"
 ,note="Available:
 \url{http://lkml.org/lkml/2005/8/8/108}
 [Viewed March 14, 2006]"
-,annotation="
+,annotation={
        First operating counter-based realtime RCU patch posted to LKML,
        but fixed so that various unusual combinations of configuration
        parameters all function properly.
-"
+}
 }
 
 @unpublished{PaulMcKenney2005rcutorture
@@ -1291,9 +1316,25 @@ Data Structures"
 ,note="Available:
 \url{http://lkml.org/lkml/2005/10/1/70}
 [Viewed March 14, 2006]"
-,annotation="
+,annotation={
        First rcutorture patch.
-"
+}
+}
+
+@unpublished{DavidSMiller2006HashedLocking
+,Author="David S. Miller"
+,Title="Re: [{PATCH}, {RFC}] {RCU} : {OOM} avoidance and lower latency"
+,month="January"
+,day="6"
+,year="2006"
+,note="Available:
+\url{https://lkml.org/lkml/2006/1/7/22}
+[Viewed February 29, 2012]"
+,annotation={
+       David Miller's view on hashed arrays of locks: used to really
+       like it, but time he saw an opportunity for this technique,
+       something else always proved superior.  Partitioning or RCU.  ;-)
+}
 }
 
 @conference{ThomasEHart2006a
@@ -1309,10 +1350,10 @@ Distributed Processing Symposium"
 ,note="Available:
 \url{http://www.rdrop.com/users/paulmck/RCU/hart_ipdps06.pdf}
 [Viewed April 28, 2008]"
-,annotation="
+,annotation={
        Compares QSBR, HPBR, EBR, and lock-free reference counting.
        http://www.cs.toronto.edu/~tomhart/perflab/ipdps06.tgz
-"
+}
 }
 
 @unpublished{NickPiggin2006radixtree
@@ -1324,9 +1365,9 @@ Distributed Processing Symposium"
 ,note="Available:
 \url{http://lkml.org/lkml/2006/6/20/238}
 [Viewed March 25, 2008]"
-,annotation="
+,annotation={
        RCU-protected radix tree.
-"
+}
 }
 
 @Conference{PaulEMcKenney2006b
@@ -1341,9 +1382,9 @@ Suparna Bhattacharya"
 \url{http://www.linuxsymposium.org/2006/view_abstract.php?content_key=184}
 \url{http://www.rdrop.com/users/paulmck/RCU/OLSrtRCU.2006.08.11a.pdf}
 [Viewed January 1, 2007]"
-,annotation="
+,annotation={
        Described how to improve the -rt implementation of realtime RCU.
-"
+}
 }
 
 @unpublished{WikipediaRCU
@@ -1354,12 +1395,11 @@ Canis Rufus and Zoicon5 and Anome and Hal Eisen"
 ,month="July"
 ,day="8"
 ,year="2006"
-,note="Available:
-\url{http://en.wikipedia.org/wiki/Read-copy-update}
-[Viewed August 21, 2006]"
-,annotation="
+,note="\url{http://en.wikipedia.org/wiki/Read-copy-update}"
+,annotation={
        Wikipedia RCU page as of July 8 2006.
-"
+       [Viewed August 21, 2006]
+}
 }
 
 @Conference{NickPiggin2006LocklessPageCache
@@ -1372,9 +1412,9 @@ Canis Rufus and Zoicon5 and Anome and Hal Eisen"
 ,note="Available:
 \url{http://www.linuxsymposium.org/2006/view_abstract.php?content_key=184}
 [Viewed January 11, 2009]"
-,annotation="
+,annotation={
        Uses RCU-protected radix tree for a lockless page cache.
-"
+}
 }
 
 @unpublished{PaulEMcKenney2006c
@@ -1388,9 +1428,9 @@ Canis Rufus and Zoicon5 and Anome and Hal Eisen"
 Revised:
 \url{http://www.rdrop.com/users/paulmck/RCU/srcu.2007.01.14a.pdf}
 [Viewed August 21, 2006]"
-,annotation="
+,annotation={
        LWN article introducing SRCU.
-"
+}
 }
 
 @unpublished{RobertOlsson2006a
@@ -1399,12 +1439,11 @@ Revised:
 ,month="August"
 ,day="18"
 ,year="2006"
-,note="Available:
-\url{http://www.nada.kth.se/~snilsson/publications/TRASH/trash.pdf}
-[Viewed March 4, 2011]"
-,annotation="
+,note="\url{http://www.nada.kth.se/~snilsson/publications/TRASH/trash.pdf}"
+,annotation={
        RCU-protected dynamic trie-hash combination.
-"
+       [Viewed March 4, 2011]
+}
 }
 
 @unpublished{ChristophHellwig2006RCU2SRCU
@@ -1426,10 +1465,10 @@ Revised:
 ,note="Available:
 \url{http://www.rdrop.com/users/paulmck/RCU/linuxusage.html}
 [Viewed January 14, 2007]"
-,annotation="
+,annotation={
        Paul McKenney's RCU page showing graphs plotting Linux-kernel
        usage of RCU.
-"
+}
 }
 
 @unpublished{PaulEMcKenneyRCUusageRawDataPage
@@ -1440,10 +1479,10 @@ Revised:
 ,note="Available:
 \url{http://www.rdrop.com/users/paulmck/RCU/linuxusage/rculocktab.html}
 [Viewed January 14, 2007]"
-,annotation="
+,annotation={
        Paul McKenney's RCU page showing Linux usage of RCU in tabular
        form, with links to corresponding cscope databases.
-"
+}
 }
 
 @unpublished{GauthamShenoy2006RCUrwlock
@@ -1455,13 +1494,13 @@ Revised:
 ,note="Available:
 \url{http://lkml.org/lkml/2006/10/26/73}
 [Viewed January 26, 2009]"
-,annotation="
+,annotation={
        RCU-based reader-writer lock that allows readers to proceed with
        no memory barriers or atomic instruction in absence of writers.
        If writer do show up, readers must of course wait as required by
        the semantics of reader-writer locking.  This is a recursive
        lock.
-"
+}
 }
 
 @unpublished{JensAxboe2006SlowSRCU
@@ -1474,11 +1513,11 @@ Revised:
 ,note="Available:
 \url{http://lkml.org/lkml/2006/11/17/56}
 [Viewed May 28, 2007]"
-,annotation="
+,annotation={
        SRCU's grace periods are too slow for Jens, even after a
        factor-of-three speedup.
        Sped-up version of SRCU at http://lkml.org/lkml/2006/11/17/359.
-"
+}
 }
 
 @unpublished{OlegNesterov2006QRCU
@@ -1491,10 +1530,10 @@ Revised:
 ,note="Available:
 \url{http://lkml.org/lkml/2006/11/19/69}
 [Viewed May 28, 2007]"
-,annotation="
+,annotation={
        First cut of QRCU.  Expanded/corrected versions followed.
        Used to be OlegNesterov2007QRCU, now time-corrected.
-"
+}
 }
 
 @unpublished{OlegNesterov2006aQRCU
@@ -1506,10 +1545,10 @@ Revised:
 ,note="Available:
 \url{http://lkml.org/lkml/2006/11/29/330}
 [Viewed November 26, 2008]"
-,annotation="
+,annotation={
        Expanded/corrected version of QRCU.
        Used to be OlegNesterov2007aQRCU, now time-corrected.
-"
+}
 }
 
 @unpublished{EvgeniyPolyakov2006RCUslowdown
@@ -1521,10 +1560,10 @@ Revised:
 ,note="Available:
 \url{http://www.ioremap.net/node/41}
 [Viewed October 28, 2008]"
-,annotation="
+,annotation={
        Using RCU as a pure delay leads to a 2.5x slowdown in skbs in
        the Linux kernel.
-"
+}
 }
 
 @inproceedings{ChrisMatthews2006ClusteredObjectsRCU
@@ -1541,7 +1580,8 @@ Revised:
 ,annotation={
        Uses K42's RCU-like functionality to manage clustered-object
        lifetimes.
-}}
+}
+}
 
 @article{DilmaDaSilva2006K42
 ,author = {Silva, Dilma Da and Krieger, Orran and Wisniewski, Robert W. and Waterland, Amos and Tam, David and Baumann, Andrew}
@@ -1557,7 +1597,8 @@ Revised:
 ,address = {New York, NY, USA}
 ,annotation={
        Describes relationship of K42 generations to RCU.
-}}
+}
+}
 
 # CoreyMinyard2007list_splice_rcu
 @unpublished{CoreyMinyard2007list:splice:rcu
@@ -1569,9 +1610,9 @@ Revised:
 ,note="Available:
 \url{http://lkml.org/lkml/2007/1/3/112}
 [Viewed May 28, 2007]"
-,annotation="
+,annotation={
        Patch for list_splice_rcu().
-"
+}
 }
 
 @unpublished{PaulEMcKenney2007rcubarrier
@@ -1583,9 +1624,9 @@ Revised:
 ,note="Available:
 \url{http://lwn.net/Articles/217484/}
 [Viewed November 22, 2007]"
-,annotation="
+,annotation={
        LWN article introducing the rcu_barrier() primitive.
-"
+}
 }
 
 @unpublished{PeterZijlstra2007SyncBarrier
@@ -1597,10 +1638,10 @@ Revised:
 ,note="Available:
 \url{http://lkml.org/lkml/2007/1/28/34}
 [Viewed March 27, 2008]"
-,annotation="
+,annotation={
        RCU-like implementation for frequent updaters and rare readers(!).
        Subsumed into QRCU.  Maybe...
-"
+}
 }
 
 @unpublished{PaulEMcKenney2007BoostRCU
@@ -1609,14 +1650,13 @@ Revised:
 ,month="February"
 ,day="5"
 ,year="2007"
-,note="Available:
-\url{http://lwn.net/Articles/220677/}
-Revised:
-\url{http://www.rdrop.com/users/paulmck/RCU/RCUbooststate.2007.04.16a.pdf}
-[Viewed September 7, 2007]"
-,annotation="
+,note="\url{http://lwn.net/Articles/220677/}"
+,annotation={
        LWN article introducing RCU priority boosting.
-"
+       Revised:
+       http://www.rdrop.com/users/paulmck/RCU/RCUbooststate.2007.04.16a.pdf
+       [Viewed September 7, 2007]
+}
 }
 
 @unpublished{PaulMcKenney2007QRCUpatch
@@ -1628,9 +1668,9 @@ Revised:
 ,note="Available:
 \url{http://lkml.org/lkml/2007/2/25/18}
 [Viewed March 27, 2008]"
-,annotation="
+,annotation={
        Patch for QRCU supplying lock-free fast path.
-"
+}
 }
 
 @article{JonathanAppavoo2007K42RCU
@@ -1647,7 +1687,8 @@ Revised:
 ,address = {New York, NY, USA}
 ,annotation={
        Role of RCU in K42.
-}}
+}
+}
 
 @conference{RobertOlsson2007Trash
 ,Author="Robert Olsson and Stefan Nilsson"
@@ -1658,9 +1699,9 @@ Revised:
 ,note="Available:
 \url{http://ieeexplore.ieee.org/xpl/freeabs_all.jsp?arnumber=4281239}
 [Viewed October 1, 2010]"
-,annotation="
+,annotation={
        RCU-protected dynamic trie-hash combination.
-"
+}
 }
 
 @conference{PeterZijlstra2007ConcurrentPagecacheRCU
@@ -1673,10 +1714,10 @@ Revised:
 ,note="Available:
 \url{http://ols.108.redhat.com/2007/Reprints/zijlstra-Reprint.pdf}
 [Viewed April 14, 2008]"
-,annotation="
+,annotation={
        Page-cache modifications permitting RCU readers and concurrent
        updates.
-"
+}
 }
 
 @unpublished{PaulEMcKenney2007whatisRCU
@@ -1701,11 +1742,11 @@ Revised:
 ,note="Available:
 \url{http://lwn.net/Articles/243851/}
 [Viewed September 8, 2007]"
-,annotation="
+,annotation={
        LWN article describing Promela and spin, and also using Oleg
        Nesterov's QRCU as an example (with Paul McKenney's fastpath).
        Merged patch at: http://lkml.org/lkml/2007/2/25/18
-"
+}
 }
 
 @unpublished{PaulEMcKenney2007WG21DDOatomics
@@ -1714,12 +1755,12 @@ Revised:
 ,month="August"
 ,day="3"
 ,year="2007"
-,note="Preprint:
+,note="Available:
 \url{http://open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2664.htm}
 [Viewed December 7, 2009]"
-,annotation="
+,annotation={
        RCU for C++, parts 1 and 2.
-"
+}
 }
 
 @unpublished{PaulEMcKenney2007WG21DDOannotation
@@ -1728,12 +1769,12 @@ Revised:
 ,month="September"
 ,day="18"
 ,year="2008"
-,note="Preprint:
+,note="Available:
 \url{http://open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2782.htm}
 [Viewed December 7, 2009]"
-,annotation="
+,annotation={
        RCU for C++, part 2, updated many times.
-"
+}
 }
 
 @unpublished{PaulEMcKenney2007PreemptibleRCUPatch
@@ -1745,10 +1786,10 @@ Revised:
 ,note="Available:
 \url{http://lkml.org/lkml/2007/9/10/213}
 [Viewed October 25, 2007]"
-,annotation="
+,annotation={
        Final patch for preemptable RCU to -rt.  (Later patches were
        to mainline, eventually incorporated.)
-"
+}
 }
 
 @unpublished{PaulEMcKenney2007PreemptibleRCU
@@ -1760,9 +1801,9 @@ Revised:
 ,note="Available:
 \url{http://lwn.net/Articles/253651/}
 [Viewed October 25, 2007]"
-,annotation="
+,annotation={
        LWN article describing the design of preemptible RCU.
-"
+}
 }
 
 @article{ThomasEHart2007a
@@ -1783,6 +1824,7 @@ Revised:
 }
 }
 
+# MathieuDesnoyers2007call_rcu_schedNeeded
 @unpublished{MathieuDesnoyers2007call:rcu:schedNeeded
 ,Author="Mathieu Desnoyers"
 ,Title="Re: [patch 1/2] {Linux} Kernel Markers - Support Multiple Probes"
@@ -1792,9 +1834,9 @@ Revised:
 ,note="Available:
 \url{http://lkml.org/lkml/2007/12/20/244}
 [Viewed March 27, 2008]"
-,annotation="
+,annotation={
        Request for call_rcu_sched() and rcu_barrier_sched().
-"
+}
 }
 
 
@@ -1815,11 +1857,11 @@ Revised:
 ,note="Available:
 \url{http://lwn.net/Articles/262464/}
 [Viewed December 27, 2007]"
-,annotation="
+,annotation={
        Lays out the three basic components of RCU: (1) publish-subscribe,
        (2) wait for pre-existing readers to complete, and (2) maintain
        multiple versions.
-"
+}
 }
 
 @unpublished{PaulEMcKenney2008WhatIsRCUUsage
@@ -1831,7 +1873,7 @@ Revised:
 ,note="Available:
 \url{http://lwn.net/Articles/263130/}
 [Viewed January 4, 2008]"
-,annotation="
+,annotation={
        Lays out six uses of RCU:
        1. RCU is a Reader-Writer Lock Replacement
        2. RCU is a Restricted Reference-Counting Mechanism
@@ -1839,7 +1881,7 @@ Revised:
        4. RCU is a Poor Man's Garbage Collector
        5. RCU is a Way of Providing Existence Guarantees
        6. RCU is a Way of Waiting for Things to Finish
-"
+}
 }
 
 @unpublished{PaulEMcKenney2008WhatIsRCUAPI
@@ -1851,10 +1893,10 @@ Revised:
 ,note="Available:
 \url{http://lwn.net/Articles/264090/}
 [Viewed January 10, 2008]"
-,annotation="
+,annotation={
        Gives an overview of the Linux-kernel RCU API and a brief annotated RCU
        bibliography.
-"
+}
 }
 
 #
@@ -1872,10 +1914,10 @@ Revised:
 ,note="Available:
 \url{http://lkml.org/lkml/2008/1/29/208}
 [Viewed March 27, 2008]"
-,annotation="
+,annotation={
        Patch that prevents preemptible RCU from unnecessarily waking
        up dynticks-idle CPUs.
-"
+}
 }
 
 @unpublished{PaulEMcKenney2008LKMLDependencyOrdering
@@ -1887,9 +1929,9 @@ Revised:
 ,note="Available:
 \url{http://lkml.org/lkml/2008/2/2/255}
 [Viewed October 18, 2008]"
-,annotation="
+,annotation={
        Explanation of compilers violating dependency ordering.
-"
+}
 }
 
 @Conference{PaulEMcKenney2008Beijing
@@ -1916,24 +1958,26 @@ lot of {Linux} into your technology!!!"
 ,note="Available:
 \url{http://lwn.net/Articles/279077/}
 [Viewed April 24, 2008]"
-,annotation="
+,annotation={
        Describes use of Promela and Spin to validate (and fix!) the
        dynticks/RCU interface.
-"
+}
 }
 
 @article{DinakarGuniguntala2008IBMSysJ
 ,author="D. Guniguntala and P. E. McKenney and J. Triplett and J. Walpole"
 ,title="The read-copy-update mechanism for supporting real-time applications on shared-memory multiprocessor systems with {Linux}"
 ,Year="2008"
-,Month="April-June"
+,Month="May"
 ,journal="IBM Systems Journal"
 ,volume="47"
 ,number="2"
 ,pages="221-236"
-,annotation="
+,annotation={
        RCU, realtime RCU, sleepable RCU, performance.
-"
+       http://www.research.ibm.com/journal/sj/472/guniguntala.pdf
+       [Viewed April 24, 2008]
+}
 }
 
 @unpublished{LaiJiangshan2008NewClassicAlgorithm
@@ -1945,11 +1989,11 @@ lot of {Linux} into your technology!!!"
 ,note="Available:
 \url{http://lkml.org/lkml/2008/6/2/539}
 [Viewed December 10, 2008]"
-,annotation="
+,annotation={
        Updated RCU classic algorithm.  Introduced multi-tailed list
        for RCU callbacks and also pulling common code into
        __call_rcu().
-"
+}
 }
 
 @article{PaulEMcKenney2008RCUOSR
@@ -1966,6 +2010,7 @@ lot of {Linux} into your technology!!!"
 ,address="New York, NY, USA"
 ,annotation={
        Linux changed RCU to a far greater degree than RCU has changed Linux.
+       http://portal.acm.org/citation.cfm?doid=1400097.1400099
 }
 }
 
@@ -1978,10 +2023,10 @@ lot of {Linux} into your technology!!!"
 ,note="Available:
 \url{http://lkml.org/lkml/2008/8/21/336}
 [Viewed December 8, 2008]"
-,annotation="
+,annotation={
        State-based RCU.  One key thing that this patch does is to
        separate the dynticks handling of NMIs and IRQs.
-"
+}
 }
 
 @unpublished{ManfredSpraul2008dyntickIRQNMI
@@ -1993,12 +2038,13 @@ lot of {Linux} into your technology!!!"
 ,note="Available:
 \url{http://lkml.org/lkml/2008/9/6/86}
 [Viewed December 8, 2008]"
-,annotation="
+,annotation={
        Manfred notes a fix required to my attempt to separate irq
        and NMI processing for hierarchical RCU's dynticks interface.
-"
+}
 }
 
+# Was PaulEMcKenney2011cyclicRCU
 @techreport{PaulEMcKenney2008cyclicRCU
 ,author="Paul E. McKenney"
 ,title="Efficient Support of Consistent Cyclic Search With Read-Copy Update"
@@ -2008,11 +2054,11 @@ lot of {Linux} into your technology!!!"
 ,number="US Patent 7,426,511"
 ,month="September"
 ,pages="23"
-,annotation="
+,annotation={
        Maintains an additional level of indirection to allow
        readers to confine themselves to the desired snapshot of the
        data structure.  Only permits one update at a time.
-"
+}
 }
 
 @unpublished{PaulEMcKenney2008HierarchicalRCU
@@ -2021,13 +2067,12 @@ lot of {Linux} into your technology!!!"
 ,month="November"
 ,day="3"
 ,year="2008"
-,note="Available:
-\url{http://lwn.net/Articles/305782/}
-[Viewed November 6, 2008]"
-,annotation="
+,note="\url{http://lwn.net/Articles/305782/}"
+,annotation={
        RCU with combining-tree-based grace-period detection,
        permitting it to handle thousands of CPUs.
-"
+       [Viewed November 6, 2008]
+}
 }
 
 @unpublished{PaulEMcKenney2009BloatwatchRCU
@@ -2039,10 +2084,10 @@ lot of {Linux} into your technology!!!"
 ,note="Available:
 \url{http://lkml.org/lkml/2009/1/14/449}
 [Viewed January 15, 2009]"
-,annotation="
+,annotation={
        Small-footprint implementation of RCU for uniprocessor
        embedded applications -- and also for exposition purposes.
-"
+}
 }
 
 @conference{PaulEMcKenney2009MaliciousURCU
@@ -2055,9 +2100,9 @@ lot of {Linux} into your technology!!!"
 ,note="Available:
 \url{http://www.rdrop.com/users/paulmck/RCU/urcutorture.2009.01.22a.pdf}
 [Viewed February 2, 2009]"
-,annotation="
+,annotation={
        Realtime RCU and torture-testing RCU uses.
-"
+}
 }
 
 @unpublished{MathieuDesnoyers2009URCU
@@ -2066,16 +2111,14 @@ lot of {Linux} into your technology!!!"
 ,month="February"
 ,day="5"
 ,year="2009"
-,note="Available:
-\url{http://lkml.org/lkml/2009/2/5/572}
-\url{http://lttng.org/urcu}
-[Viewed February 20, 2009]"
-,annotation="
+,note="\url{http://lttng.org/urcu}"
+,annotation={
        Mathieu Desnoyers's user-space RCU implementation.
        git://lttng.org/userspace-rcu.git
        http://lttng.org/cgi-bin/gitweb.cgi?p=userspace-rcu.git
        http://lttng.org/urcu
-"
+       http://lkml.org/lkml/2009/2/5/572
+}
 }
 
 @unpublished{PaulEMcKenney2009LWNBloatWatchRCU
@@ -2087,9 +2130,24 @@ lot of {Linux} into your technology!!!"
 ,note="Available:
 \url{http://lwn.net/Articles/323929/}
 [Viewed March 20, 2009]"
-,annotation="
+,annotation={
        Uniprocessor assumptions allow simplified RCU implementation.
-"
+}
+}
+
+@unpublished{EvgeniyPolyakov2009EllipticsNetwork
+,Author="Evgeniy Polyakov"
+,Title="The Elliptics Network"
+,month="April"
+,day="17"
+,year="2009"
+,note="Available:
+\url{http://www.ioremap.net/projects/elliptics}
+[Viewed April 30, 2009]"
+,annotation={
+       Distributed hash table with transactions, using elliptic
+       hash functions to distribute data.
+}
 }
 
 @unpublished{PaulEMcKenney2009expeditedRCU
@@ -2101,9 +2159,9 @@ lot of {Linux} into your technology!!!"
 ,note="Available:
 \url{http://lkml.org/lkml/2009/6/25/306}
 [Viewed August 16, 2009]"
-,annotation="
+,annotation={
        First posting of expedited RCU to be accepted into -tip.
-"
+}
 }
 
 @unpublished{PaulEMcKenney2009fastRTRCU
@@ -2115,21 +2173,21 @@ lot of {Linux} into your technology!!!"
 ,note="Available:
 \url{http://lkml.org/lkml/2009/7/23/294}
 [Viewed August 15, 2009]"
-,annotation="
+,annotation={
        First posting of simple and fast preemptable RCU.
-"
+}
 }
 
-@InProceedings{JoshTriplett2009RPHash
+@unpublished{JoshTriplett2009RPHash
 ,Author="Josh Triplett"
 ,Title="Scalable concurrent hash tables via relativistic programming"
 ,month="September"
 ,year="2009"
-,booktitle="Linux Plumbers Conference 2009"
-,annotation="
+,note="Linux Plumbers Conference presentation"
+,annotation={
        RP fun with hash tables.
-       See also JoshTriplett2010RPHash
-"
+       Superseded by JoshTriplett2010RPHash
+}
 }
 
 @phdthesis{MathieuDesnoyersPhD
@@ -2154,9 +2212,9 @@ lot of {Linux} into your technology!!!"
 ,note="Available:
 \url{http://wiki.cs.pdx.edu/rp/}
 [Viewed December 9, 2009]"
-,annotation="
+,annotation={
        Main Relativistic Programming Wiki.
-"
+}
 }
 
 @conference{PaulEMcKenney2009DeterministicRCU
@@ -2180,9 +2238,9 @@ lot of {Linux} into your technology!!!"
 ,note="Available:
 \url{http://paulmck.livejournal.com/14639.html}
 [Viewed June 4, 2010]"
-,annotation="
+,annotation={
        Day-one bug in Tree RCU that took forever to track down.
-"
+}
 }
 
 @unpublished{MathieuDesnoyers2009defer:rcu
@@ -2193,10 +2251,10 @@ lot of {Linux} into your technology!!!"
 ,note="Available:
 \url{http://lkml.org/lkml/2009/10/18/129}
 [Viewed December 29, 2009]"
-,annotation="
+,annotation={
        Mathieu proposed defer_rcu() with fixed-size per-thread pool
        of RCU callbacks.
-"
+}
 }
 
 @unpublished{MathieuDesnoyers2009VerifPrePub
@@ -2205,10 +2263,10 @@ lot of {Linux} into your technology!!!"
 ,month="December"
 ,year="2009"
 ,note="Submitted to IEEE TPDS"
-,annotation="
+,annotation={
        OOMem model for Mathieu's user-level RCU mechanical proof of
        correctness.
-"
+}
 }
 
 @unpublished{MathieuDesnoyers2009URCUPrePub
@@ -2216,15 +2274,15 @@ lot of {Linux} into your technology!!!"
 ,Title="User-Level Implementations of Read-Copy Update"
 ,month="December"
 ,year="2010"
-,url=\url{http://www.computer.org/csdl/trans/td/2012/02/ttd2012020375-abs.html}
-,annotation="
+,url={\url{http://www.computer.org/csdl/trans/td/2012/02/ttd2012020375-abs.html}}
+,annotation={
        RCU overview, desiderata, semi-formal semantics, user-level RCU
        usage scenarios, three classes of RCU implementation, wait-free
        RCU updates, RCU grace-period batching, update overhead,
        http://www.rdrop.com/users/paulmck/RCU/urcu-main-accepted.2011.08.30a.pdf
        http://www.rdrop.com/users/paulmck/RCU/urcu-supp-accepted.2011.08.30a.pdf
        Superseded by MathieuDesnoyers2012URCU.
-"
+}
 }
 
 @inproceedings{HariKannan2009DynamicAnalysisRCU
@@ -2240,7 +2298,8 @@ lot of {Linux} into your technology!!!"
 ,address = {New York, NY, USA}
 ,annotation={
        Uses RCU to protect metadata used in dynamic analysis.
-}}
+}
+}
 
 @conference{PaulEMcKenney2010SimpleOptRCU
 ,Author="Paul E. McKenney"
@@ -2252,10 +2311,10 @@ lot of {Linux} into your technology!!!"
 ,note="Available:
 \url{http://www.rdrop.com/users/paulmck/RCU/SimplicityThruOptimization.2010.01.21f.pdf}
 [Viewed October 10, 2010]"
-,annotation="
+,annotation={
        TREE_PREEMPT_RCU optimizations greatly simplified the old
        PREEMPT_RCU implementation.
-"
+}
 }
 
 @unpublished{PaulEMcKenney2010LockdepRCU
@@ -2264,12 +2323,11 @@ lot of {Linux} into your technology!!!"
 ,month="February"
 ,year="2010"
 ,day="1"
-,note="Available:
-\url{https://lwn.net/Articles/371986/}
-[Viewed June 4, 2010]"
-,annotation="
+,note="\url{https://lwn.net/Articles/371986/}"
+,annotation={
        CONFIG_PROVE_RCU, or at least an early version.
-"
+       [Viewed June 4, 2010]
+}
 }
 
 @unpublished{AviKivity2010KVM2RCU
@@ -2280,10 +2338,10 @@ lot of {Linux} into your technology!!!"
 ,note="Available:
 \url{http://www.mail-archive.com/kvm@vger.kernel.org/msg28640.html}
 [Viewed March 20, 2010]"
-,annotation="
+,annotation={
        Use of RCU permits KVM to increase the size of guest OSes from
        16 CPUs to 64 CPUs.
-"
+}
 }
 
 @unpublished{HerbertXu2010RCUResizeHash
@@ -2297,7 +2355,19 @@ lot of {Linux} into your technology!!!"
 ,annotation={
        Use a pair of list_head structures to support RCU-protected
        resizable hash tables.
-}}
+}
+}
+
+@mastersthesis{AbhinavDuggal2010Masters
+,author="Abhinav Duggal"
+,title="Stopping Data Races Using Redflag"
+,school="Stony Brook University"
+,year="2010"
+,annotation={
+       Data-race detector incorporating RCU.
+       http://www.filesystems.org/docs/abhinav-thesis/abhinav_thesis.pdf
+}
+}
 
 @article{JoshTriplett2010RPHash
 ,author="Josh Triplett and Paul E. McKenney and Jonathan Walpole"
@@ -2310,7 +2380,8 @@ lot of {Linux} into your technology!!!"
 ,annotation={
        RP fun with hash tables.
        http://portal.acm.org/citation.cfm?id=1842733.1842750
-}}
+}
+}
 
 @unpublished{PaulEMcKenney2010RCUAPI
 ,Author="Paul E. McKenney"
@@ -2318,12 +2389,11 @@ lot of {Linux} into your technology!!!"
 ,month="December"
 ,day="8"
 ,year="2010"
-,note="Available:
-\url{http://lwn.net/Articles/418853/}
-[Viewed December 8, 2010]"
-,annotation="
+,note="\url{http://lwn.net/Articles/418853/}"
+,annotation={
        Includes updated software-engineering features.
-"
+       [Viewed December 8, 2010]
+}
 }
 
 @mastersthesis{AndrejPodzimek2010masters
@@ -2338,7 +2408,8 @@ lot of {Linux} into your technology!!!"
        Reviews RCU implementations and creates a few for OpenSolaris.
        Drives quiescent-state detection from RCU read-side primitives,
        in a manner roughly similar to that of Jim Houston.
-}}
+}
+}
 
 @unpublished{LinusTorvalds2011Linux2:6:38:rc1:NPigginVFS
 ,Author="Linus Torvalds"
@@ -2358,7 +2429,8 @@ lot of {Linux} into your technology!!!"
        of the most expensive parts of path component lookup, which was the
        d_lock on every component lookup. So I'm seeing improvements of 30-50%
        on some seriously pathname-lookup intensive loads."
-}}
+}
+}
 
 @techreport{JoshTriplett2011RPScalableCorrectOrdering
 ,author = {Josh Triplett and Philip W. Howard and Paul E. McKenney and Jonathan Walpole}
@@ -2392,12 +2464,12 @@ lot of {Linux} into your technology!!!"
 ,number="US Patent 7,953,778"
 ,month="May"
 ,pages="34"
-,annotation="
+,annotation={
        Maintains an array of generation numbers to track in-flight
        updates and keeps an additional level of indirection to allow
        readers to confine themselves to the desired snapshot of the
        data structure.
-"
+}
 }
 
 @inproceedings{Triplett:2011:RPHash
@@ -2408,7 +2480,7 @@ lot of {Linux} into your technology!!!"
 ,year = {2011}
 ,pages = {145--158}
 ,numpages = {14}
-,url={http://www.usenix.org/event/atc11/tech/final_files/atc11_proceedings.pdf}
+,url={http://www.usenix.org/event/atc11/tech/final_files/Triplett.pdf}
 ,publisher = {The USENIX Association}
 ,address = {Portland, OR USA}
 }
@@ -2419,27 +2491,52 @@ lot of {Linux} into your technology!!!"
 ,month="July"
 ,day="27"
 ,year="2011"
-,note="Available:
-\url{http://lwn.net/Articles/453002/}
-[Viewed July 27, 2011]"
-,annotation="
+,note="\url{http://lwn.net/Articles/453002/}"
+,annotation={
        Analysis of the RCU trainwreck in Linux kernel 3.0.
-"
+       [Viewed July 27, 2011]
+}
 }
 
 @unpublished{NeilBrown2011MeetTheLockers
 ,Author="Neil Brown"
-,Title="Meet the Lockers"
+,Title="Meet the {Lockers}"
 ,month="August"
 ,day="3"
 ,year="2011"
 ,note="Available:
 \url{http://lwn.net/Articles/453685/}
 [Viewed September 2, 2011]"
-,annotation="
+,annotation={
        The Locker family as an analogy for locking, reference counting,
        RCU, and seqlock.
-"
+}
+}
+
+@inproceedings{Seyster:2011:RFA:2075416.2075425
+,author = {Seyster, Justin and Radhakrishnan, Prabakar and Katoch, Samriti and Duggal, Abhinav and Stoller, Scott D. and Zadok, Erez}
+,title = {Redflag: a framework for analysis of Kernel-level concurrency}
+,booktitle = {Proceedings of the 11th international conference on Algorithms and architectures for parallel processing - Volume Part I}
+,series = {ICA3PP'11}
+,year = {2011}
+,isbn = {978-3-642-24649-4}
+,location = {Melbourne, Australia}
+,pages = {66--79}
+,numpages = {14}
+,url = {http://dl.acm.org/citation.cfm?id=2075416.2075425}
+,acmid = {2075425}
+,publisher = {Springer-Verlag}
+,address = {Berlin, Heidelberg}
+}
+
+@phdthesis{JoshTriplettPhD
+,author="Josh Triplett"
+,title="Relativistic Causal Ordering A Memory Model for Scalable Concurrent Data Structures"
+,school="Portland State University"
+,year="2012"
+,annotation={
+       RCU-protected hash tables, barriers vs. read-side traversal order.
+}
 }
 
 @article{MathieuDesnoyers2012URCU
@@ -2459,5 +2556,153 @@ lot of {Linux} into your technology!!!"
        RCU updates, RCU grace-period batching, update overhead,
        http://www.rdrop.com/users/paulmck/RCU/urcu-main-accepted.2011.08.30a.pdf
        http://www.rdrop.com/users/paulmck/RCU/urcu-supp-accepted.2011.08.30a.pdf
+       http://www.computer.org/cms/Computer.org/dl/trans/td/2012/02/extras/ttd2012020375s.pdf
+}
+}
+
+@inproceedings{AustinClements2012RCULinux:mmapsem
+,author = {Austin Clements and Frans Kaashoek and Nickolai Zeldovich}
+,title = {Scalable Address Spaces Using {RCU} Balanced Trees}
+,booktitle = {Architectural Support for Programming Languages and Operating Systems (ASPLOS 2012)}
+,month = {March}
+,year = {2012}
+,pages = {199--210}
+,numpages = {12}
+,publisher = {ACM}
+,address = {London, UK}
+,url="http://people.csail.mit.edu/nickolai/papers/clements-bonsai.pdf"
+}
+
+@unpublished{PaulEMcKenney2012ELCbattery
+,Author="Paul E. McKenney"
+,Title="Making {RCU} Safe For Battery-Powered Devices"
+,month="February"
+,day="15"
+,year="2012"
+,note="Available:
+\url{http://www.rdrop.com/users/paulmck/RCU/RCUdynticks.2012.02.15b.pdf}
+[Viewed March 1, 2012]"
+,annotation={
+       RCU_FAST_NO_HZ, round 2.
+}
+}
+
+@article{GuillermoVigueras2012RCUCrowd
+,author = {Vigueras, Guillermo and Ordu\~{n}a, Juan M. and Lozano, Miguel}
+,citeulike-article-id = {10632151}
+,citeulike-linkout-0 = {http://dx.doi.org/10.1007/s11227-012-0766-x}
+,citeulike-linkout-1 = {http://www.springerlink.com/content/25762r0874163570}
+,day = {25}
+,doi = {10.1007/s11227-012-0766-x}
+,issn = {0920-8542}
+,journal = {The Journal of Supercomputing}
+,keywords = {linux, simulation}
+,month = apr
+,posted-at = {2012-05-03 09:12:04}
+,priority = {2}
+,title = {{A Read-Copy Update based parallel server for distributed crowd simulations}}
+,url = {http://dx.doi.org/10.1007/s11227-012-0766-x}
+,year = {2012}
+}
+
+
+@unpublished{JonCorbet2012ACCESS:ONCE
+,Author="Jon Corbet"
+,Title="{ACCESS\_ONCE()}"
+,month="August"
+,day="1"
+,year="2012"
+,note="\url{http://lwn.net/Articles/508991/}"
+,annotation={
+       A couple of simple specific compiler optimizations that motivate
+       ACCESS_ONCE().
+}
+}
+
+@unpublished{AlexeyGotsman2012VerifyGraceExtended
+,Author="Alexey Gotsman and Noam Rinetzky and Hongseok Yang"
+,Title="Verifying Highly Concurrent Algorithms with Grace (extended version)"
+,month="July"
+,day="10"
+,year="2012"
+,note="\url{http://software.imdea.org/~gotsman/papers/recycling-esop13-ext.pdf}"
+,annotation={
+       Separation-logic formulation of RCU uses.
+}
+}
+
+@unpublished{PaulMcKenney2012RCUUsage
+,Author="Paul E. McKenney and Silas Boyd-Wickizer and Jonathan Walpole"
+,Title="{RCU} Usage In the Linux Kernel: One Decade Later"
+,month="September"
+,day="17"
+,year="2012"
+,url=http://rdrop.com/users/paulmck/techreports/survey.2012.09.17a.pdf
+,note="Technical report paulmck.2012.09.17"
+,annotation={
+       Overview of the first variant of no-CBs CPUs for RCU.
+}
+}
+
+@unpublished{JonCorbet2012NOCB
+,Author="Jon Corbet"
+,Title="Relocating RCU callbacks"
+,month="October"
+,day="31"
+,year="2012"
+,note="\url{http://lwn.net/Articles/522262/}"
+,annotation={
+       Overview of the first variant of no-CBs CPUs for RCU.
+}
+}
+
+@phdthesis{JustinSeyster2012PhD
+,author="Justin Seyster"
+,title="Runtime Verification of Kernel-Level Concurrency Using Compiler-Based Instrumentation"
+,school="Stony Brook University"
+,year="2012"
+,annotation={
+       Looking for data races, including those involving RCU.
+       Proposal:
+       http://www.fsl.cs.sunysb.edu/docs/jseyster-proposal/redflag.pdf
+       Dissertation:
+       http://www.fsl.cs.sunysb.edu/docs/jseyster-dissertation/redflag.pdf
+}
+}
+
+@unpublished{PaulEMcKenney2013RCUUsage
+,Author="Paul E. McKenney and Silas Boyd-Wickizer and Jonathan Walpole"
+,Title="{RCU} Usage in the {Linux} Kernel: One Decade Later"
+,month="February"
+,day="24"
+,year="2013"
+,note="\url{http://rdrop.com/users/paulmck/techreports/RCUUsage.2013.02.24a.pdf}"
+,annotation={
+       Usage of RCU within the Linux kernel.
+}
+}
+
+@inproceedings{AlexeyGotsman2013ESOPRCU
+,author = {Alexey Gotsman and Noam Rinetzky and Hongseok Yang}
+,title = {Verifying concurrent memory reclamation algorithms with grace}
+,booktitle = {ESOP'13: European Symposium on Programming}
+,year = {2013}
+,pages = {249--269}
+,publisher = {Springer}
+,address = {Rome, Italy}
+,annotation={
+       http://software.imdea.org/~gotsman/papers/recycling-esop13.pdf
+}
+}
+
+@unpublished{PaulEMcKenney2013NoTinyPreempt
+,Author="Paul E. McKenney"
+,Title="Simplifying RCU"
+,month="March"
+,day="6"
+,year="2013"
+,note="\url{http://lwn.net/Articles/541037/}"
+,annotation={
+       Getting rid of TINY_PREEMPT_RCU.
 }
 }
index 2e319d1b9ef28c0d9c19505306063cfc6bc9f595..b10cfe711e68e48fe6d516ea531126dfc947fc13 100644 (file)
@@ -70,10 +70,14 @@ in realtime kernels in order to avoid excessive scheduling latencies.
 
 rcu_barrier()
 
-We instead need the rcu_barrier() primitive. This primitive is similar
-to synchronize_rcu(), but instead of waiting solely for a grace
-period to elapse, it also waits for all outstanding RCU callbacks to
-complete. Pseudo-code using rcu_barrier() is as follows:
+We instead need the rcu_barrier() primitive.  Rather than waiting for
+a grace period to elapse, rcu_barrier() waits for all outstanding RCU
+callbacks to complete.  Please note that rcu_barrier() does -not- imply
+synchronize_rcu(), in particular, if there are no RCU callbacks queued
+anywhere, rcu_barrier() is within its rights to return immediately,
+without waiting for a grace period to elapse.
+
+Pseudo-code using rcu_barrier() is as follows:
 
    1. Prevent any new RCU callbacks from being posted.
    2. Execute rcu_barrier().
index d8a50238739719b49aa0f04077860326cf98cc4d..dac02a6219b1cae3c657512b293b957627cec830 100644 (file)
@@ -42,6 +42,16 @@ fqs_holdoff  Holdoff time (in microseconds) between consecutive calls
 fqs_stutter    Wait time (in seconds) between consecutive bursts
                of calls to force_quiescent_state().
 
+gp_normal      Make the fake writers use normal synchronous grace-period
+               primitives.
+
+gp_exp         Make the fake writers use expedited synchronous grace-period
+               primitives.  If both gp_normal and gp_exp are set, or
+               if neither gp_normal nor gp_exp are set, then randomly
+               choose the primitive so that about 50% are normal and
+               50% expedited.  By default, neither are set, which
+               gives best overall test coverage.
+
 irqreader      Says to invoke RCU readers from irq level.  This is currently
                done via timers.  Defaults to "1" for variants of RCU that
                permit this.  (Or, more accurately, variants of RCU that do
index 9012bb03909443e4978d9d3a9fd6bbf0f095d907..4ae915a9f899cb7f34cb2bf13e6b1b79994d06e2 100644 (file)
@@ -78,7 +78,7 @@ to NULL.  Drivers should use the following idiom:
 The most common usage of these functions will probably be to specify
 the maximum time from when an interrupt occurs, to when the device
 becomes accessible.  To accomplish this, driver writers should use the
-set_max_mpu_wakeup_lat() function to to constrain the MPU wakeup
+set_max_mpu_wakeup_lat() function to constrain the MPU wakeup
 latency, and the set_max_dev_wakeup_lat() function to constrain the
 device wakeup latency (from clk_enable() to accessibility).  For
 example,
index 9887f0414c16642d204296d9c0b8abdc8096a5da..f3bc72945cbd3827872e4e25163830e3fef72571 100644 (file)
@@ -69,7 +69,7 @@ one, this value should be decreased relative to fifo_expire_async.
 group_idle
 -----------
 This parameter forces idling at the CFQ group level instead of CFQ
-queue level. This was introduced after after a bottleneck was observed
+queue level. This was introduced after a bottleneck was observed
 in higher end storage due to idle on sequential queue and allow dispatch
 from a single queue. The idea with this parameter is that it can be run with
 slice_idle=0 and group_idle=8, so that idling does not happen on individual
index 4823577c65092f967ef3d46eb024fa8a1366ab7e..2e0617936e8f7f7624d0920be7ff3ae3d6217f68 100644 (file)
@@ -276,7 +276,7 @@ mainline get there via -mm.
 The current -mm patch is available in the "mmotm" (-mm of the moment)
 directory at:
 
-       http://userweb.kernel.org/~akpm/mmotm/
+       http://www.ozlabs.org/~akpm/mmotm/
 
 Use of the MMOTM tree is likely to be a frustrating experience, though;
 there is a definite chance that it will not even compile.
@@ -287,7 +287,7 @@ the mainline is expected to look like after the next merge window closes.
 Linux-next trees are announced on the linux-kernel and linux-next mailing
 lists when they are assembled; they can be downloaded from:
 
-       http://www.kernel.org/pub/linux/kernel/people/sfr/linux-next/
+       http://www.kernel.org/pub/linux/kernel/next/
 
 Some information about linux-next has been gathered at:
 
index 69b5ab0b5f4b4eb4f330b820900d2eebf2dbf898..d11d80006a19037b50d0922054185ffe6371373c 100644 (file)
@@ -22,7 +22,7 @@ This contains the board-specific information.
 - compatible: must be "stericsson,s365".
 - vana15-supply: the regulator supplying the 1.5V to drive the
   board.
-- syscon: a pointer to the syscon node so we can acccess the
+- syscon: a pointer to the syscon node so we can access the
   syscon registers to set the board as self-powered.
 
 Example:
index 9cf3f25544c794607e07e331f35752d8f59d578c..5580e9c4bd8584034a9d9812c491962f08fa253e 100644 (file)
@@ -32,8 +32,8 @@ numbers - see motherboard's TRM for more details.
 The node describing a config device must refer to the sysreg node via
 "arm,vexpress,config-bridge" phandle (can be also defined in the node's
 parent) and relies on the board topology properties - see main vexpress
-node documentation for more details. It must must also define the
-following property:
+node documentation for more details. It must also define the following
+property:
 - arm,vexpress-sysreg,func : must contain two cells:
   - first cell defines function number (eg. 1 for clock generator,
     2 for voltage regulators etc.)
index a1201802f90d0d8fdcfd552c7d359c3cc7b79d31..75e2e1999f87dabdb7eccc94ba01d472533a69fd 100644 (file)
@@ -2,7 +2,7 @@
 
 The Samsung Audio Subsystem clock controller generates and supplies clocks
 to Audio Subsystem block available in the S5PV210 and Exynos SoCs. The clock
-binding described here is applicable to all SoC's in Exynos family.
+binding described here is applicable to all SoCs in Exynos family.
 
 Required Properties:
 
index c280a0e6f42dcb9bf4ccbf1549e7458856f4299f..e1f343c7a34b7b10ea462a39b5e9a320ef463ba6 100644 (file)
@@ -18,14 +18,14 @@ dma0: dma@ffffec00 {
 
 DMA clients connected to the Atmel DMA controller must use the format
 described in the dma.txt file, using a three-cell specifier for each channel:
-a phandle plus two interger cells.
+a phandle plus two integer cells.
 The three cells in order are:
 
 1. A phandle pointing to the DMA controller.
 2. The memory interface (16 most significant bits), the peripheral interface
 (16 less significant bits).
 3. Parameters for the at91 DMA configuration register which are device
-dependant:
+dependent:
   - bit 7-0: peripheral identifier for the hardware handshaking interface. The
   identifier can be different for tx and rx.
   - bit 11-8: FIFO configuration. 0 for half FIFO, 1 for ALAP, 1 for ASAP.
index 2717ecb47db9ac4a30448d4f6af6a361a9d8ec67..7bd8847d6394e6bbfb7df8b43eea2af4375cc883 100644 (file)
@@ -34,7 +34,7 @@ Clients have to specify the DMA requests with phandles in a list.
 Required properties:
 - dmas: List of one or more DMA request specifiers. One DMA request specifier
     consists of a phandle to the DMA controller followed by the integer
-    specifiying the request line.
+    specifying the request line.
 - dma-names: List of string identifiers for the DMA requests. For the correct
     names, have a look at the specific client driver.
 
index bea5b73a739009634c579d20e892c1c4a17ebc92..a8c21c256baa5afbcb4b1a43d150ca47a5c4e3ea 100644 (file)
@@ -37,14 +37,14 @@ Each dmas request consists of 4 cells:
   1. A phandle pointing to the DMA controller
   2. Device Type
   3. The DMA request line number (only when 'use fixed channel' is set)
-  4. A 32bit mask specifying; mode, direction and endianess [NB: This list will grow]
+  4. A 32bit mask specifying; mode, direction and endianness [NB: This list will grow]
         0x00000001: Mode:
                 Logical channel when unset
                 Physical channel when set
         0x00000002: Direction:
                 Memory to Device when unset
                 Device to Memory when set
-        0x00000004: Endianess:
+        0x00000004: Endianness:
                 Little endian when unset
                 Big endian when set
         0x00000008: Use fixed channel:
index d5176882d8b999563f11a25a6cb806caf0e863d6..a61727f9a6d171df79a83774b75a1462fea48865 100644 (file)
@@ -1,7 +1,7 @@
 Binding for TI/National Semiconductor LP55xx Led Drivers
 
 Required properties:
-- compatible: "national,lp5521" or "national,lp5523" or "ti,lp5562"
+- compatible: "national,lp5521" or "national,lp5523" or "ti,lp5562" or "ti,lp8501"
 - reg: I2C slave address
 - clock-mode: Input clock mode, (0: automode, 1: internal, 2: external)
 
@@ -11,6 +11,11 @@ Each child has own specific current settings
 
 Optional properties:
 - label: Used for naming LEDs
+- pwr-sel: LP8501 specific property. Power selection for output channels.
+         0: D1~9 are connected to VDD
+         1: D1~6 with VDD, D7~9 with VOUT
+         2: D1~6 with VOUT, D7~9 with VDD
+         3: D1~9 are connected to VOUT
 
 Alternatively, each child can have specific channel name
 - chan-name: Name of each channel name
@@ -145,3 +150,68 @@ lp5562@30 {
                max-cur = /bits/ 8 <0x60>;
        };
 };
+
+example 4) LP8501
+9 channels are defined. The 'pwr-sel' is LP8501 specific property.
+Others are same as LP5523.
+
+lp8501@32 {
+       compatible = "ti,lp8501";
+       reg = <0x32>;
+       clock-mode = /bits/ 8 <2>;
+       pwr-sel = /bits/ 8 <3>; /* D1~9 connected to VOUT */
+
+       chan0 {
+               chan-name = "d1";
+               led-cur = /bits/ 8 <0x14>;
+               max-cur = /bits/ 8 <0x20>;
+       };
+
+       chan1 {
+               chan-name = "d2";
+               led-cur = /bits/ 8 <0x14>;
+               max-cur = /bits/ 8 <0x20>;
+       };
+
+       chan2 {
+               chan-name = "d3";
+               led-cur = /bits/ 8 <0x14>;
+               max-cur = /bits/ 8 <0x20>;
+       };
+
+       chan3 {
+               chan-name = "d4";
+               led-cur = /bits/ 8 <0x14>;
+               max-cur = /bits/ 8 <0x20>;
+       };
+
+       chan4 {
+               chan-name = "d5";
+               led-cur = /bits/ 8 <0x14>;
+               max-cur = /bits/ 8 <0x20>;
+       };
+
+       chan5 {
+               chan-name = "d6";
+               led-cur = /bits/ 8 <0x14>;
+               max-cur = /bits/ 8 <0x20>;
+       };
+
+       chan6 {
+               chan-name = "d7";
+               led-cur = /bits/ 8 <0x14>;
+               max-cur = /bits/ 8 <0x20>;
+       };
+
+       chan7 {
+               chan-name = "d8";
+               led-cur = /bits/ 8 <0x14>;
+               max-cur = /bits/ 8 <0x20>;
+       };
+
+       chan8 {
+               chan-name = "d9";
+               led-cur = /bits/ 8 <0x14>;
+               max-cur = /bits/ 8 <0x20>;
+       };
+};
diff --git a/Documentation/devicetree/bindings/leds/pca9633.txt b/Documentation/devicetree/bindings/leds/pca9633.txt
new file mode 100644 (file)
index 0000000..6d9e1a9
--- /dev/null
@@ -0,0 +1,46 @@
+LEDs connected to pca9633 or pca9632
+
+Required properties:
+- compatible : should be : "nxp,pca963x"
+
+Optional properties:
+- nxp,totem-pole : use totem pole (push-pull) instead of default open-drain
+- nxp,hw-blink : use hardware blinking instead of software blinking
+
+Each led is represented as a sub-node of the nxp,pca9633 device.
+
+LED sub-node properties:
+- label : (optional) see Documentation/devicetree/bindings/leds/common.txt
+- reg : number of LED line (could be from 0 to 4)
+- linux,default-trigger : (optional)
+   see Documentation/devicetree/bindings/leds/common.txt
+
+Examples:
+
+pca9632: pca9632 {
+       compatible = "nxp,pca9632", "nxp,pca963x";
+       #address-cells = <1>;
+       #size-cells = <0>;
+       reg = <0x62>;
+
+       red@0 {
+               label = "red";
+               reg = <0>;
+               linux,default-trigger = "none";
+       };
+       green@1 {
+               label = "green";
+               reg = <1>;
+               linux,default-trigger = "none";
+       };
+       blue@2 {
+               label = "blue";
+               reg = <2>;
+               linux,default-trigger = "none";
+       };
+       unused@3 {
+               label = "unused";
+               reg = <3>;
+               linux,default-trigger = "none";
+       };
+};
index e0e59c58a1f92120864af95355655abb2805c34b..5f229c5f6da96c09d011fe5bec75eda2ab2ba56d 100644 (file)
@@ -4,7 +4,7 @@ Google's ChromeOS EC is a Cortex-M device which talks to the AP and
 implements various function such as keyboard and battery charging.
 
 The EC can be connect through various means (I2C, SPI, LPC) and the
-compatible string used depends on the inteface. Each connection method has
+compatible string used depends on the interface. Each connection method has
 its own driver which connects to the top level interface-agnostic EC driver.
 Other Linux driver (such as cros-ec-keyb for the matrix keyboard) connect to
 the top-level driver.
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 {
                        ...
index c2dbcec0ee31d33482858367e097140a766516d4..f2105a47ec87c547fcd88d383d136ec4d11eb65b 100644 (file)
@@ -37,7 +37,7 @@ Optional properties:
        If not specified or if the specified value is 0, the CLKOUT pin
        will be disabled.
 
-- nxp,no-comparator-bypass : Allows to disable the CAN input comperator.
+- nxp,no-comparator-bypass : Allows to disable the CAN input comparator.
 
 For further information, please have a look to the SJA1000 data sheet.
 
index 648d60eb9fd8f505be140b6d58a6cb771ed04220..7ccae490ff6dcc6936f7c9e5791435685d3ded30 100644 (file)
@@ -37,7 +37,7 @@ Bank: 3 (A, B and C)
   0xffffffff 0x7fff3ccf  /* pioB */
   0xffffffff 0x007fffff  /* pioC */
 
-For each peripheral/bank we will descibe in a u32 if a pin can can be
+For each peripheral/bank we will descibe in a u32 if a pin can be
 configured in it by putting 1 to the pin bit (1 << pin)
 
 Let's take the pioA on peripheral B
diff --git a/Documentation/devicetree/bindings/regulator/88pm800.txt b/Documentation/devicetree/bindings/regulator/88pm800.txt
new file mode 100644 (file)
index 0000000..e8a54c2
--- /dev/null
@@ -0,0 +1,38 @@
+Marvell 88PM800 regulator
+
+Required properties:
+- compatible: "marvell,88pm800"
+- reg: I2C slave address
+- regulators: A node that houses a sub-node for each regulator within the
+  device. Each sub-node is identified using the node's name (or the deprecated
+  regulator-compatible property if present), with valid values listed below.
+  The content of each sub-node is defined by the standard binding for
+  regulators; see regulator.txt.
+
+The valid names for regulators are:
+
+  buck1, buck2, buck3, buck4, buck5, ldo1, ldo2, ldo3, ldo4, ldo5, ldo6, ldo7,
+  ldo8, ldo9, ldo10, ldo11, ldo12, ldo13, ldo14, ldo15, ldo16, ldo17, ldo18, ldo19
+
+Example:
+
+       pmic: 88pm800@31 {
+               compatible = "marvell,88pm800";
+               reg = <0x31>;
+
+               regulators {
+                       buck1 {
+                               regulator-min-microvolt = <600000>;
+                               regulator-max-microvolt = <3950000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+                       ldo1 {
+                               regulator-min-microvolt = <600000>;
+                               regulator-max-microvolt = <15000000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+...
+               };
+       };
index d5a308629c5765093cf4111d8e42186cbe6b06d3..30b0581bb1ce63cbea673888e9fec22a5df72aa5 100644 (file)
@@ -31,9 +31,8 @@ Optional nodes:
               Optional sub-node properties:
               ti,warm-reset - maintain voltage during warm reset(boolean)
               ti,roof-floor - control voltage selection by pin(boolean)
-              ti,sleep-mode - mode to adopt in pmic sleep 0 - off, 1 - auto,
+              ti,mode-sleep - mode to adopt in pmic sleep 0 - off, 1 - auto,
               2 - eco, 3 - forced pwm
-              ti,tstep - slope control 0 - Jump, 1 10mV/us, 2 5mV/us, 3 2.5mV/us
               ti,smps-range - OTP has the wrong range set for the hardware so override
               0 - low range, 1 - high range.
 
@@ -59,7 +58,6 @@ pmic {
                        ti,warm-reset;
                        ti,roof-floor;
                        ti,mode-sleep = <0>;
-                       ti,tstep = <0>;
                        ti,smps-range = <1>;
                };
 
diff --git a/Documentation/devicetree/bindings/regulator/pfuze100.txt b/Documentation/devicetree/bindings/regulator/pfuze100.txt
new file mode 100644 (file)
index 0000000..fc989b2
--- /dev/null
@@ -0,0 +1,115 @@
+PFUZE100 family of regulators
+
+Required properties:
+- compatible: "fsl,pfuze100"
+- reg: I2C slave address
+
+Required child node:
+- regulators: This is the list of child nodes that specify the regulator
+  initialization data for defined regulators. Please refer to below doc
+  Documentation/devicetree/bindings/regulator/regulator.txt.
+
+  The valid names for regulators are:
+  sw1ab,sw1c,sw2,sw3a,sw3b,sw4,swbst,vsnvs,vrefddr,vgen1~vgen6
+
+Each regulator is defined using the standard binding for regulators.
+
+Example:
+
+       pmic: pfuze100@08 {
+               compatible = "fsl,pfuze100";
+               reg = <0x08>;
+
+               regulators {
+                       sw1a_reg: sw1ab {
+                               regulator-min-microvolt = <300000>;
+                               regulator-max-microvolt = <1875000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                               regulator-ramp-delay = <6250>;
+                       };
+
+                       sw1c_reg: sw1c {
+                               regulator-min-microvolt = <300000>;
+                               regulator-max-microvolt = <1875000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       sw2_reg: sw2 {
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       sw3a_reg: sw3a {
+                               regulator-min-microvolt = <400000>;
+                               regulator-max-microvolt = <1975000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       sw3b_reg: sw3b {
+                               regulator-min-microvolt = <400000>;
+                               regulator-max-microvolt = <1975000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       sw4_reg: sw4 {
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <3300000>;
+                       };
+
+                       swbst_reg: swbst {
+                               regulator-min-microvolt = <5000000>;
+                               regulator-max-microvolt = <5150000>;
+                       };
+
+                       snvs_reg: vsnvs {
+                               regulator-min-microvolt = <1000000>;
+                               regulator-max-microvolt = <3000000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       vref_reg: vrefddr {
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       vgen1_reg: vgen1 {
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <1550000>;
+                       };
+
+                       vgen2_reg: vgen2 {
+                               regulator-min-microvolt = <800000>;
+                               regulator-max-microvolt = <1550000>;
+                       };
+
+                       vgen3_reg: vgen3 {
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                       };
+
+                       vgen4_reg: vgen4 {
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                       };
+
+                       vgen5_reg: vgen5 {
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                       };
+
+                       vgen6_reg: vgen6 {
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-always-on;
+                       };
+               };
+       };
index 48a3b8e5d6bde80fce883c7db83f99dc4bcc7da7..2bd8f09787659269bb03847b3517cff2b52cfca9 100644 (file)
@@ -12,6 +12,8 @@ Optional properties:
 - regulator-allow-bypass: allow the regulator to go into bypass mode
 - <name>-supply: phandle to the parent supply/regulator node
 - regulator-ramp-delay: ramp delay for regulator(in uV/uS)
+  For hardwares which support disabling ramp rate, it should be explicitly
+  intialised to zero (regulator-ramp-delay = <0>) for disabling ramp delay.
 
 Deprecated properties:
 - regulator-compatible: If a regulator chip contains multiple
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>;
+};
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/timer/moxa,moxart-timer.txt b/Documentation/devicetree/bindings/timer/moxa,moxart-timer.txt
new file mode 100644 (file)
index 0000000..77c4cfa
--- /dev/null
@@ -0,0 +1,17 @@
+MOXA ART timer
+
+Required properties:
+
+- compatible : Should be "moxa,moxart-timer"
+- reg : Should contain registers location and length
+- interrupts : Should contain the timer interrupt number
+- clocks : Should contain phandle for APB clock "clkapb"
+
+Example:
+
+       timer: timer@98400000 {
+               compatible = "moxa,moxart-timer";
+               reg = <0x98400000 0x42>;
+               interrupts = <19 1>;
+               clocks = <&clkapb>;
+       };
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;
+       };
diff --git a/Documentation/devicetree/bindings/video/atmel,lcdc.txt b/Documentation/devicetree/bindings/video/atmel,lcdc.txt
new file mode 100644 (file)
index 0000000..1ec175e
--- /dev/null
@@ -0,0 +1,75 @@
+Atmel LCDC Framebuffer
+-----------------------------------------------------
+
+Required properties:
+- compatible :
+       "atmel,at91sam9261-lcdc" , 
+       "atmel,at91sam9263-lcdc" ,
+       "atmel,at91sam9g10-lcdc" ,
+       "atmel,at91sam9g45-lcdc" ,
+       "atmel,at91sam9g45es-lcdc" ,
+       "atmel,at91sam9rl-lcdc" ,
+       "atmel,at32ap-lcdc"
+- reg : Should contain 1 register ranges(address and length)
+- interrupts : framebuffer controller interrupt
+- display: a phandle pointing to the display node
+
+Required nodes:
+- display: a display node is required to initialize the lcd panel
+       This should be in the board dts.
+- default-mode: a videomode within the display with timing parameters
+       as specified below.
+
+Example:
+
+       fb0: fb@0x00500000 {
+               compatible = "atmel,at91sam9g45-lcdc";
+               reg = <0x00500000 0x1000>;
+               interrupts = <23 3 0>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_fb>;
+               display = <&display0>;
+               status = "okay";
+               #address-cells = <1>;
+               #size-cells = <1>;
+
+       };
+
+Atmel LCDC Display
+-----------------------------------------------------
+Required properties (as per of_videomode_helper):
+
+ - atmel,dmacon: dma controler configuration
+ - atmel,lcdcon2: lcd controler configuration
+ - atmel,guard-time: lcd guard time (Delay in frame periods)
+ - bits-per-pixel: lcd panel bit-depth.
+
+Optional properties (as per of_videomode_helper):
+ - atmel,lcdcon-backlight: enable backlight
+ - atmel,lcd-wiring-mode: lcd wiring mode "RGB" or "BRG"
+ - atmel,power-control-gpio: gpio to power on or off the LCD (as many as needed)
+
+Example:
+       display0: display {
+               bits-per-pixel = <32>;
+               atmel,lcdcon-backlight;
+               atmel,dmacon = <0x1>;
+               atmel,lcdcon2 = <0x80008002>;
+               atmel,guard-time = <9>;
+               atmel,lcd-wiring-mode = <1>;
+
+               display-timings {
+                       native-mode = <&timing0>;
+                       timing0: timing0 {
+                               clock-frequency = <9000000>;
+                               hactive = <480>;
+                               vactive = <272>;
+                               hback-porch = <1>;
+                               hfront-porch = <1>;
+                               vback-porch = <40>;
+                               vfront-porch = <1>;
+                               hsync-len = <45>;
+                               vsync-len = <1>;
+                       };
+               };
+       };
index 0b23261561d28818fdbd630d420211836b6aad6a..e31a2a9d2b075e9dda835218b63fd103cb91d6fa 100644 (file)
@@ -321,7 +321,7 @@ Access to a dma_buf from the kernel context involves three steps:
 
    When the importer is done accessing the range specified in begin_cpu_access,
    it needs to announce this to the exporter (to facilitate cache flushing and
-   unpinning of any pinned resources). The result of of any dma_buf kmap calls
+   unpinning of any pinned resources). The result of any dma_buf kmap calls
    after end_cpu_access is undefined.
 
    Interface:
index 99ea58e65eff66ff326590b8657032f234fd7f9f..4a9739abc860651825f62e6ffb71f9b592d57015 100644 (file)
@@ -150,7 +150,7 @@ C. Boot options
 
 C. Attaching, Detaching and Unloading
 
-Before going on on how to attach, detach and unload the framebuffer console, an
+Before going on how to attach, detach and unload the framebuffer console, an
 illustration of the dependencies may help.
 
 The console layer, as with most subsystems, needs a driver that interfaces with
index 444e34b52ae164019c77c74ea83384a5ac006f63..1cb2462a71ce6d41a0dc5cfb771aa367adf2d033 100644 (file)
@@ -32,7 +32,7 @@
     Start viafb with default settings:
         #modprobe viafb
 
-    Start viafb with with user options:
+    Start viafb with user options:
         #modprobe viafb viafb_mode=800x600 viafb_bpp=16 viafb_refresh=60
                   viafb_active_dev=CRT+DVI viafb_dvi_port=DVP1
                   viafb_mode1=1024x768 viafb_bpp=16 viafb_refresh1=60
index f7cbf574a875271296d93bee53b290ca36c44a66..a92c5aa8ce22ef11e48d1192d2f063f674fc65a4 100644 (file)
@@ -2,7 +2,7 @@
 Ext4 Filesystem
 ===============
 
-Ext4 is an an advanced level of the ext3 filesystem which incorporates
+Ext4 is an advanced level of the ext3 filesystem which incorporates
 scalability and reliability enhancements for supporting large filesystems
 (64 bit) in keeping with increasing disk capacities and state-of-the-art
 feature requirements.
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 52ae07f5f578bc44af9bf02b1bc3530510750fdc..adc81a35fe2d98026bf8cf0f778d315bcb78f407 100644 (file)
@@ -12,7 +12,7 @@ struct pnfs_layout_hdr
 ----------------------
 The on-the-wire command LAYOUTGET corresponds to struct
 pnfs_layout_segment, usually referred to by the variable name lseg.
-Each nfs_inode may hold a pointer to a cache of of these layout
+Each nfs_inode may hold a pointer to a cache of these layout
 segments in nfsi->layout, of type struct pnfs_layout_hdr.
 
 We reference the header for the inode pointing to it, across each
index 510b722667ac885cf7abed3732961941a5ad1c14..33e2f369473375b691f15583c836903728be1c39 100644 (file)
@@ -31,7 +31,7 @@ Semantics
 
 Each relay channel has one buffer per CPU, each buffer has one or more
 sub-buffers.  Messages are written to the first sub-buffer until it is
-too full to contain a new message, in which case it it is written to
+too full to contain a new message, in which case it is written to
 the next (if available).  Messages are never split across sub-buffers.
 At this point, userspace can be notified so it empties the first
 sub-buffer, while the kernel continues writing to the next.
index caaaf1266d8f33d37be423f7556ad69bbb1c535a..eb843e49c5a39d558d3bb91b043f47512b2edc59 100644 (file)
@@ -24,7 +24,7 @@ flag between KOBJ_NS_TYPE_NONE and KOBJ_NS_TYPES, and s_ns will
 point to the namespace to which it belongs.
 
 Each sysfs superblock's sysfs_super_info contains an array void
-*ns[KOBJ_NS_TYPES].  When a task in a tagging namespace
+*ns[KOBJ_NS_TYPES].  When a task in a tagging namespace
 kobj_nstype first mounts sysfs, a new superblock is created.  It
 will be differentiated from other sysfs mounts by having its
 s_fs_info->ns[kobj_nstype] set to the new namespace.  Note that
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 d6991625c407d41102f25a008c4f4801396ec1b7..8e5fbd88c7d1472af8f6d1da1ed5798340cfc345 100644 (file)
@@ -196,8 +196,8 @@ static int example_probe(struct i2c_client *i2c_client,
 
 Update the detach method, by changing the name to _remove and
 to delete the i2c_detach_client call. It is possible that you
-can also remove the ret variable as it is not not needed for
-any of the core functions.
+can also remove the ret variable as it is not needed for any
+of the core functions.
 
 - static int example_detach(struct i2c_client *client)
 + static int example_remove(struct i2c_client *client)
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 eec8fa2ffe4e5126cc63520d52f48f825ed81aca..82713ff92eb3e5c72a82ff6f1dc9d637e7f04376 100644 (file)
@@ -1,11 +1,11 @@
-LP5521/LP5523/LP55231 Common Driver
-===================================
+LP5521/LP5523/LP55231/LP5562/LP8501 Common Driver
+=================================================
 
 Authors: Milo(Woogyom) Kim <milo.kim@ti.com>
 
 Description
 -----------
-LP5521, LP5523/55231 and LP5562 have common features as below.
+LP5521, LP5523/55231, LP5562 and LP8501 have common features as below.
 
   Register access via the I2C
   Device initialization/deinitialization
@@ -109,6 +109,30 @@ As soon as 'loading' is set to 0, registered callback is called.
 Inside the callback, the selected engine is loaded and memory is updated.
 To run programmed pattern, 'run_engine' attribute should be enabled.
 
+The pattern sqeuence of LP8501 is same as LP5523.
+However pattern data is specific.
+Ex 1) Engine 1 is used
+echo 1 > /sys/bus/i2c/devices/xxxx/select_engine
+echo 1 > /sys/class/firmware/lp8501/loading
+echo "9d0140ff7e0040007e00a001c000" > /sys/class/firmware/lp8501/data
+echo 0 > /sys/class/firmware/lp8501/loading
+echo 1 > /sys/bus/i2c/devices/xxxx/run_engine
+
+Ex 2) Engine 2 and 3 are used at the same time
+echo 2 > /sys/bus/i2c/devices/xxxx/select_engine
+sleep 1
+echo 1 > /sys/class/firmware/lp8501/loading
+echo "9d0140ff7e0040007e00a001c000" > /sys/class/firmware/lp8501/data
+echo 0 > /sys/class/firmware/lp8501/loading
+sleep 1
+echo 3 > /sys/bus/i2c/devices/xxxx/select_engine
+sleep 1
+echo 1 > /sys/class/firmware/lp8501/loading
+echo "9d0340ff7e0040007e00a001c000" > /sys/class/firmware/lp8501/data
+echo 0 > /sys/class/firmware/lp8501/loading
+sleep 1
+echo 1 > /sys/class/leds/d1/device/run_engine
+
 ( 'run_engine' and 'firmware_cb' )
 The sequence of running the program data is common.
 But each device has own specific register addresses for commands.
index fa5d8a9ae2051184ddba6ce3d1dd769414d2e59f..c8c42e64e953b4cd47d23da125ac5e057d1c158d 100644 (file)
@@ -531,9 +531,10 @@ dependency barrier to make it work correctly.  Consider the following bit of
 code:
 
        q = &a;
-       if (p)
+       if (p) {
+               <data dependency barrier>
                q = &b;
-       <data dependency barrier>
+       }
        x = *q;
 
 This will not have the desired effect because there is no actual data
@@ -542,9 +543,10 @@ attempting to predict the outcome in advance.  In such a case what's actually
 required is:
 
        q = &a;
-       if (p)
+       if (p) {
+               <read barrier>
                q = &b;
-       <read barrier>
+       }
        x = *q;
 
 
index 8e5eacbdcfa3f44115ccbc66fff89601c1af38ed..8fd254c735897af37c4544e5a6ecc514819f1760 100644 (file)
@@ -210,13 +210,15 @@ If memory device is found, memory hotplug code will be called.
 
 4.2 Notify memory hot-add event by hand
 ------------
-In some environments, especially virtualized environment, firmware will not
-notify memory hotplug event to the kernel. For such environment, "probe"
-interface is supported. This interface depends on CONFIG_ARCH_MEMORY_PROBE.
-
-Now, CONFIG_ARCH_MEMORY_PROBE is supported only by powerpc but it does not
-contain highly architecture codes. Please add config if you need "probe"
-interface.
+On powerpc, the firmware does not notify a memory hotplug event to the kernel.
+Therefore, "probe" interface is supported to notify the event to the kernel.
+This interface depends on CONFIG_ARCH_MEMORY_PROBE.
+
+CONFIG_ARCH_MEMORY_PROBE is supported on powerpc only. On x86, this config
+option is disabled by default since ACPI notifies a memory hotplug event to
+the kernel, which performs its hotplug operation as the result. Please
+enable this option if you need the "probe" interface for testing purposes
+on x86.
 
 Probe interface is located at
 /sys/devices/system/memory/probe
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.
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 3e8cb73ac43c2be41b7537c156f7d87a1efbba90..22b4bc51fb4f18a08d06e93d0a8bce8d4b9bf0e4 100644 (file)
@@ -97,7 +97,7 @@ IPv4 addresses:
 
        %pI4    1.2.3.4
        %pi4    001.002.003.004
-       %p[Ii][hnbl]
+       %p[Ii]4[hnbl]
 
        For printing IPv4 dot-separated decimal addresses. The 'I4' and 'i4'
        specifiers result in a printed address with ('i4') or without ('I4')
index 717f5aa388b171bcdffa8115191491aac64f4bd2..28fbd877f85a7971ce446e75278d5cd0f2750318 100644 (file)
@@ -300,7 +300,7 @@ initialization.
 -------------------------------------------
 
 RapidIO subsystem code organization allows addition of new enumeration/discovery
-methods as new configuration options without significant impact to to the core
+methods as new configuration options without significant impact to the core
 RapidIO code.
 
 A new enumeration/discovery method has to be attached to one or more mport
index 0bcc55155911083345120cb15cc1afb78094e75d..ac8d20b833227f276148f045f85f1addc47dd4d9 100644 (file)
@@ -73,7 +73,7 @@ The main requirements are:
 
 Design
 
-The new API shares a number of concepts with with the PCM API for flow
+The new API shares a number of concepts with the PCM API for flow
 control. Start, pause, resume, drain and stop commands have the same
 semantics no matter what the content is.
 
index c1a1fd636bf9e0c5ce6152d8cbe26f7c251bf770..a5f985ee1822fe37497d09c08a75acf599cba887 100644 (file)
@@ -47,7 +47,7 @@ versions of the sysfs interface.
         at device creation and removal
       - the unique key to the device at that point in time
       - the kernel's path to the device directory without the leading
-        /sys, and always starting with with a slash
+        /sys, and always starting with a slash
       - all elements of a devpath must be real directories. Symlinks
         pointing to /sys/devices must always be resolved to their real
         target and the target path must be used to access the device.
index 88697584242b604945dac74ff8f3ff2a11df9c36..cca122f25120b310fc1816b342d61adb29f832c6 100644 (file)
@@ -24,8 +24,8 @@ There are three main ways of managing scheduling-clock interrupts
        workloads, you will normally -not- want this option.
 
 These three cases are described in the following three sections, followed
-by a third section on RCU-specific considerations and a fourth and final
-section listing known issues.
+by a third section on RCU-specific considerations, a fourth section
+discussing testing, and a fifth and final section listing known issues.
 
 
 NEVER OMIT SCHEDULING-CLOCK TICKS
@@ -121,14 +121,15 @@ boot parameter specifies the adaptive-ticks CPUs.  For example,
 "nohz_full=1,6-8" says that CPUs 1, 6, 7, and 8 are to be adaptive-ticks
 CPUs.  Note that you are prohibited from marking all of the CPUs as
 adaptive-tick CPUs:  At least one non-adaptive-tick CPU must remain
-online to handle timekeeping tasks in order to ensure that system calls
-like gettimeofday() returns accurate values on adaptive-tick CPUs.
-(This is not an issue for CONFIG_NO_HZ_IDLE=y because there are no
-running user processes to observe slight drifts in clock rate.)
-Therefore, the boot CPU is prohibited from entering adaptive-ticks
-mode.  Specifying a "nohz_full=" mask that includes the boot CPU will
-result in a boot-time error message, and the boot CPU will be removed
-from the mask.
+online to handle timekeeping tasks in order to ensure that system
+calls like gettimeofday() returns accurate values on adaptive-tick CPUs.
+(This is not an issue for CONFIG_NO_HZ_IDLE=y because there are no running
+user processes to observe slight drifts in clock rate.)  Therefore, the
+boot CPU is prohibited from entering adaptive-ticks mode.  Specifying a
+"nohz_full=" mask that includes the boot CPU will result in a boot-time
+error message, and the boot CPU will be removed from the mask.  Note that
+this means that your system must have at least two CPUs in order for
+CONFIG_NO_HZ_FULL=y to do anything for you.
 
 Alternatively, the CONFIG_NO_HZ_FULL_ALL=y Kconfig parameter specifies
 that all CPUs other than the boot CPU are adaptive-ticks CPUs.  This
@@ -232,6 +233,29 @@ scheduler will decide where to run them, which might or might not be
 where you want them to run.
 
 
+TESTING
+
+So you enable all the OS-jitter features described in this document,
+but do not see any change in your workload's behavior.  Is this because
+your workload isn't affected that much by OS jitter, or is it because
+something else is in the way?  This section helps answer this question
+by providing a simple OS-jitter test suite, which is available on branch
+master of the following git archive:
+
+git://git.kernel.org/pub/scm/linux/kernel/git/frederic/dynticks-testing.git
+
+Clone this archive and follow the instructions in the README file.
+This test procedure will produce a trace that will allow you to evaluate
+whether or not you have succeeded in removing OS jitter from your system.
+If this trace shows that you have removed OS jitter as much as is
+possible, then you can conclude that your workload is not all that
+sensitive to OS jitter.
+
+Note: this test requires that your system have at least two CPUs.
+We do not currently have a good way to remove OS jitter from single-CPU
+systems.
+
+
 KNOWN ISSUES
 
 o      Dyntick-idle slows transitions to and from idle slightly.
index ef925eaa14608fc806c9a58fd032d9aeaeea6305..858aecf21db2c9d449d984af406a838ed5143ed4 100644 (file)
@@ -53,7 +53,7 @@ incompatible change are allowed.  However, there is an extension
 facility that allows backward-compatible extensions to the API to be
 queried and used.
 
-The extension mechanism is not based on on the Linux version number.
+The extension mechanism is not based on the Linux version number.
 Instead, kvm defines extension identifiers and a facility to query
 whether a particular extension identifier is available.  If it is, a
 set of ioctls is available for application use.
index a6ab4b62d9261cc9b7690076019fe3bec04a79b4..67113f622880fd55a4858e9bc07283a3d4d1fe5d 100644 (file)
@@ -100,8 +100,8 @@ Subsystems and drivers can create and queue work items through special
 workqueue API functions as they see fit. They can influence some
 aspects of the way the work items are executed by setting flags on the
 workqueue they are putting the work item on. These flags include
-things like CPU locality, reentrancy, concurrency limits, priority and
-more.  To get a detailed overview refer to the API description of
+things like CPU locality, concurrency limits, priority and more.  To
+get a detailed overview refer to the API description of
 alloc_workqueue() below.
 
 When a work item is queued to a workqueue, the target gcwq and
@@ -166,16 +166,6 @@ resources, scheduled and executed.
 
 @flags:
 
-  WQ_NON_REENTRANT
-
-       By default, a wq guarantees non-reentrance only on the same
-       CPU.  A work item may not be executed concurrently on the same
-       CPU by multiple workers but is allowed to be executed
-       concurrently on multiple CPUs.  This flag makes sure
-       non-reentrance is enforced across all CPUs.  Work items queued
-       to a non-reentrant wq are guaranteed to be executed by at most
-       one worker system-wide at any given time.
-
   WQ_UNBOUND
 
        Work items queued to an unbound wq are served by a special
@@ -233,6 +223,10 @@ resources, scheduled and executed.
 
        This flag is meaningless for unbound wq.
 
+Note that the flag WQ_NON_REENTRANT no longer exists as all workqueues
+are now non-reentrant - any work item is guaranteed to be executed by
+at most one worker system-wide at any given time.
+
 @max_active:
 
 @max_active determines the maximum number of execution contexts per
index fc66d42422eef8ba30d52b0a49fae515fd46625b..f4f268c2b826de7f03b1c2bd2478a85eacd58f2e 100644 (file)
@@ -58,7 +58,7 @@ Protocol 2.11:        (Kernel 3.6) Added a field for offset of EFI handover
                protocol entry point.
 
 Protocol 2.12: (Kernel 3.8) Added the xloadflags field and extension fields
-               to struct boot_params for for loading bzImage and ramdisk
+               to struct boot_params for loading bzImage and ramdisk
                above 4G in 64bit.
 
 **** MEMORY LAYOUT
index e9e8ddbbf376253bd093db46d1695dccd9e06f1e..1228b22e142b2c5da2f749cb7922b357209c01a0 100644 (file)
@@ -176,6 +176,11 @@ ACPI
 
   acpi=noirq   Don't route interrupts
 
+  acpi=nocmcff Disable firmware first mode for corrected errors. This
+               disables parsing the HEST CMC error source to check if
+               firmware has set the FF flag. This may result in
+               duplicate corrected error reports.
+
 PCI
 
   pci=off              Don't use PCI
index a26b10e52aea18cf39b61095cc563cd940ff1dac..87bd234977f9496043a9864d331e83b7fd26564f 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/
 
@@ -2107,6 +2107,13 @@ M:       Russell King <linux@arm.linux.org.uk>
 S:     Maintained
 F:     include/linux/clk.h
 
+CLOCKSOURCE, CLOCKEVENT DRIVERS
+M:     Daniel Lezcano <daniel.lezcano@linaro.org>
+M:     Thomas Gleixner <tglx@linutronix.de>
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
+S:     Supported
+F:     drivers/clocksource
+
 CISCO FCOE HBA DRIVER
 M:     Hiral Patel <hiralpat@cisco.com>
 M:     Suma Ramars <sramars@cisco.com>
@@ -5391,6 +5398,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 +6734,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 +7134,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/
@@ -7130,7 +7147,7 @@ S:        Maintained
 F:     include/linux/mmc/dw_mmc.h
 F:     drivers/mmc/host/dw_mmc*
 
-TIMEKEEPING, NTP
+TIMEKEEPING, CLOCKSOURCE CORE, NTP
 M:     John Stultz <john.stultz@linaro.org>
 M:     Thomas Gleixner <tglx@linutronix.de>
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
@@ -7143,7 +7160,6 @@ F:        include/uapi/linux/timex.h
 F:     kernel/time/clocksource.c
 F:     kernel/time/time*.c
 F:     kernel/time/ntp.c
-F:     drivers/clocksource
 
 TLG2300 VIDEO4LINUX-2 DRIVER
 M:     Huang Shijie <shijie8@gmail.com>
@@ -7223,6 +7239,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/
 
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 a08ce71854233e05510d45fc1183c19ecd35cb7c..81279ec73a6a7873b4a10fc8ec4c3546413bfd05 100644 (file)
@@ -127,9 +127,8 @@ void __init free_initrd_mem(unsigned long start, unsigned long end)
 #endif
 
 #ifdef CONFIG_OF_FLATTREE
-void __init early_init_dt_setup_initrd_arch(unsigned long start,
-                                           unsigned long end)
+void __init early_init_dt_setup_initrd_arch(u64 start, u64 end)
 {
-       pr_err("%s(%lx, %lx)\n", __func__, start, end);
+       pr_err("%s(%llx, %llx)\n", __func__, start, end);
 }
 #endif /* CONFIG_OF_FLATTREE */
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..205923d60fc51000c4b617bcc17b6a365cb0f14a 100644 (file)
@@ -2175,6 +2175,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 3ed37b4d93dade5c688410eae876ccb53364ef72..e072bb2ba1b12761d579b44cf951ba97d28b0386 100644 (file)
@@ -2,7 +2,7 @@
 #define ASMARM_DMA_CONTIGUOUS_H
 
 #ifdef __KERNEL__
-#ifdef CONFIG_CMA
+#ifdef CONFIG_DMA_CMA
 
 #include <linux/types.h>
 #include <asm-generic/dma-contiguous.h>
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
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 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 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 63af9a7ae5124f82484feb8b33a88114b915753d..96286cb383bde3139e5a805596cfc329bbd2abeb 100644 (file)
@@ -971,6 +971,7 @@ static const char *hwcap_str[] = {
        "vfpv4",
        "idiva",
        "idivt",
+       "vfpd32",
        "lpae",
        NULL
 };
index 741f66a2edbd77bf3ddce5a53c6cb760e491c7fe..9c697db2787e2a524cf59db4519f5272fa2918b0 100644 (file)
@@ -219,6 +219,10 @@ long kvm_arch_dev_ioctl(struct file *filp,
        return -EINVAL;
 }
 
+void kvm_arch_memslots_updated(struct kvm *kvm)
+{
+}
+
 int kvm_arch_prepare_memory_region(struct kvm *kvm,
                                   struct kvm_memory_slot *memslot,
                                   struct kvm_userspace_memory_region *mem,
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 629ea5fc95cf74e2cf72a145d3ea80c4d98aa4b3..b2a34740146aaab4d3af99b741979c670be6402e 100644 (file)
@@ -465,7 +465,7 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
 
 #if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
 static u64 lcdc_dmamask = DMA_BIT_MASK(32);
-static struct atmel_lcdfb_info lcdc_data;
+static struct atmel_lcdfb_pdata lcdc_data;
 
 static struct resource lcdc_resources[] = {
        [0] = {
@@ -498,7 +498,7 @@ static struct platform_device at91_lcdc_device = {
        .num_resources  = ARRAY_SIZE(lcdc_resources),
 };
 
-void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
+void __init at91_add_device_lcdc(struct atmel_lcdfb_pdata *data)
 {
        if (!data) {
                return;
@@ -559,7 +559,7 @@ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
        platform_device_register(&at91_lcdc_device);
 }
 #else
-void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {}
+void __init at91_add_device_lcdc(struct atmel_lcdfb_pdata *data) {}
 #endif
 
 
index 858c8aac2daf06328ed99de3b56987647f81b33d..4aeadddbc18108918b883150bef49b3a770eeb42 100644 (file)
@@ -832,7 +832,7 @@ void __init at91_add_device_can(struct at91_can_data *data) {}
 
 #if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
 static u64 lcdc_dmamask = DMA_BIT_MASK(32);
-static struct atmel_lcdfb_info lcdc_data;
+static struct atmel_lcdfb_pdata lcdc_data;
 
 static struct resource lcdc_resources[] = {
        [0] = {
@@ -859,7 +859,7 @@ static struct platform_device at91_lcdc_device = {
        .num_resources  = ARRAY_SIZE(lcdc_resources),
 };
 
-void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
+void __init at91_add_device_lcdc(struct atmel_lcdfb_pdata *data)
 {
        if (!data)
                return;
@@ -891,7 +891,7 @@ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
        platform_device_register(&at91_lcdc_device);
 }
 #else
-void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {}
+void __init at91_add_device_lcdc(struct atmel_lcdfb_pdata *data) {}
 #endif
 
 
index acb703e13331e2a9931bb321d7c1f9f71d550f11..cb36fa872d305d6f22b9133d48d3bdaaa678789d 100644 (file)
@@ -965,7 +965,7 @@ void __init at91_add_device_isi(struct isi_platform_data *data,
 
 #if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
 static u64 lcdc_dmamask = DMA_BIT_MASK(32);
-static struct atmel_lcdfb_info lcdc_data;
+static struct atmel_lcdfb_pdata lcdc_data;
 
 static struct resource lcdc_resources[] = {
        [0] = {
@@ -991,7 +991,7 @@ static struct platform_device at91_lcdc_device = {
        .num_resources  = ARRAY_SIZE(lcdc_resources),
 };
 
-void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
+void __init at91_add_device_lcdc(struct atmel_lcdfb_pdata *data)
 {
        if (!data)
                return;
@@ -1037,7 +1037,7 @@ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
        platform_device_register(&at91_lcdc_device);
 }
 #else
-void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {}
+void __init at91_add_device_lcdc(struct atmel_lcdfb_pdata *data) {}
 #endif
 
 
index 352468f265a9616bb411fecc503a13a933e926b2..a698bdab2cce682fee2983e0942d5bc2126139e4 100644 (file)
@@ -498,7 +498,7 @@ void __init at91_add_device_ac97(struct ac97c_platform_data *data) {}
 
 #if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
 static u64 lcdc_dmamask = DMA_BIT_MASK(32);
-static struct atmel_lcdfb_info lcdc_data;
+static struct atmel_lcdfb_pdata lcdc_data;
 
 static struct resource lcdc_resources[] = {
        [0] = {
@@ -525,7 +525,7 @@ static struct platform_device at91_lcdc_device = {
        .num_resources  = ARRAY_SIZE(lcdc_resources),
 };
 
-void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
+void __init at91_add_device_lcdc(struct atmel_lcdfb_pdata *data)
 {
        if (!data) {
                return;
@@ -557,7 +557,7 @@ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
        platform_device_register(&at91_lcdc_device);
 }
 #else
-void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {}
+void __init at91_add_device_lcdc(struct atmel_lcdfb_pdata *data) {}
 #endif
 
 
index d3437624ca4e213092132bd6a16195e8668a9d7e..473546b9408bf087a6b1a38950a9cf2157b3497f 100644 (file)
@@ -389,7 +389,7 @@ static struct fb_monspecs at91fb_default_stn_monspecs = {
                                        | ATMEL_LCDC_IFWIDTH_4 \
                                        | ATMEL_LCDC_SCANMOD_SINGLE)
 
-static void at91_lcdc_stn_power_control(int on)
+static void at91_lcdc_stn_power_control(struct atmel_lcdfb_pdata *pdata, int on)
 {
        /* backlight */
        if (on) {       /* power up */
@@ -401,7 +401,7 @@ static void at91_lcdc_stn_power_control(int on)
        }
 }
 
-static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
+static struct atmel_lcdfb_pdata __initdata ek_lcdc_data = {
        .default_bpp                    = 1,
        .default_dmacon                 = ATMEL_LCDC_DMAEN,
        .default_lcdcon2                = AT91SAM9261_DEFAULT_STN_LCDCON2,
@@ -445,7 +445,7 @@ static struct fb_monspecs at91fb_default_tft_monspecs = {
                                        | ATMEL_LCDC_DISTYPE_TFT    \
                                        | ATMEL_LCDC_CLKMOD_ALWAYSACTIVE)
 
-static void at91_lcdc_tft_power_control(int on)
+static void at91_lcdc_tft_power_control(struct atmel_lcdfb_pdata *pdata, int on)
 {
        if (on)
                at91_set_gpio_value(AT91_PIN_PA12, 0);  /* power up */
@@ -453,7 +453,7 @@ static void at91_lcdc_tft_power_control(int on)
                at91_set_gpio_value(AT91_PIN_PA12, 1);  /* power down */
 }
 
-static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
+static struct atmel_lcdfb_pdata __initdata ek_lcdc_data = {
        .lcdcon_is_backlight            = true,
        .default_bpp                    = 16,
        .default_dmacon                 = ATMEL_LCDC_DMAEN,
@@ -465,7 +465,7 @@ static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
 #endif
 
 #else
-static struct atmel_lcdfb_info __initdata ek_lcdc_data;
+static struct atmel_lcdfb_pdata __initdata ek_lcdc_data;
 #endif
 
 
index 3284df05df14be82b8bf7acce98ef090ccf09b56..8b4942cbb6d9a62ffdb1f88e9676670817b7a107 100644 (file)
@@ -275,13 +275,13 @@ static struct fb_monspecs at91fb_default_monspecs = {
                                        | ATMEL_LCDC_DISTYPE_TFT \
                                        | ATMEL_LCDC_CLKMOD_ALWAYSACTIVE)
 
-static void at91_lcdc_power_control(int on)
+static void at91_lcdc_power_control(struct atmel_lcdfb_pdata *pdata, int on)
 {
        at91_set_gpio_value(AT91_PIN_PA30, on);
 }
 
 /* Driver datas */
-static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
+static struct atmel_lcdfb_pdata __initdata ek_lcdc_data = {
        .lcdcon_is_backlight            = true,
        .default_bpp                    = 16,
        .default_dmacon                 = ATMEL_LCDC_DMAEN,
@@ -292,7 +292,7 @@ static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
 };
 
 #else
-static struct atmel_lcdfb_info __initdata ek_lcdc_data;
+static struct atmel_lcdfb_pdata __initdata ek_lcdc_data;
 #endif
 
 
index 2a94896a1375029b8eb34e030981480ad35acd10..ef39078c8ce214973352a22055421d7404cb4952 100644 (file)
@@ -284,7 +284,7 @@ static struct fb_monspecs at91fb_default_monspecs = {
                                        | ATMEL_LCDC_CLKMOD_ALWAYSACTIVE)
 
 /* Driver datas */
-static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
+static struct atmel_lcdfb_pdata __initdata ek_lcdc_data = {
        .lcdcon_is_backlight            = true,
        .default_bpp                    = 32,
        .default_dmacon                 = ATMEL_LCDC_DMAEN,
@@ -295,7 +295,7 @@ static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
 };
 
 #else
-static struct atmel_lcdfb_info __initdata ek_lcdc_data;
+static struct atmel_lcdfb_pdata __initdata ek_lcdc_data;
 #endif
 
 
index aa265dcf212875651da778e9213177b7e41803de..604eecf6cd70d03b57c34e6a2736f9feceb5be98 100644 (file)
@@ -170,7 +170,7 @@ static struct fb_monspecs at91fb_default_monspecs = {
                                        | ATMEL_LCDC_DISTYPE_TFT \
                                        | ATMEL_LCDC_CLKMOD_ALWAYSACTIVE)
 
-static void at91_lcdc_power_control(int on)
+static void at91_lcdc_power_control(struct atmel_lcdfb_pdata *pdata, int on)
 {
        if (on)
                at91_set_gpio_value(AT91_PIN_PC1, 0);   /* power up */
@@ -179,7 +179,7 @@ static void at91_lcdc_power_control(int on)
 }
 
 /* Driver datas */
-static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
+static struct atmel_lcdfb_pdata __initdata ek_lcdc_data = {
        .lcdcon_is_backlight            = true,
        .default_bpp                    = 16,
        .default_dmacon                 = ATMEL_LCDC_DMAEN,
@@ -191,7 +191,7 @@ static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
 };
 
 #else
-static struct atmel_lcdfb_info __initdata ek_lcdc_data;
+static struct atmel_lcdfb_pdata __initdata ek_lcdc_data;
 #endif
 
 
index 4a234fb2ab3b80d73dbdfa6bafc1cf7a08253287..6c08b341167d308df456eb1a0e79b4f10b5a9e00 100644 (file)
@@ -107,8 +107,8 @@ extern void __init at91_add_device_pwm(u32 mask);
 extern void __init at91_add_device_ssc(unsigned id, unsigned pins);
 
  /* LCD Controller */
-struct atmel_lcdfb_info;
-extern void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data);
+struct atmel_lcdfb_pdata;
+extern void __init at91_add_device_lcdc(struct atmel_lcdfb_pdata *data);
 
  /* AC97 */
 extern void __init at91_add_device_ac97(struct ac97c_platform_data *data);
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>
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 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 7f9b1798c6cf12f08e55496b27082722e16a30f3..dbddc07a3bbd9abc6d2ba9169085457d4fc86dc5 100644 (file)
@@ -358,7 +358,7 @@ static int __init atomic_pool_init(void)
        if (!pages)
                goto no_pages;
 
-       if (IS_ENABLED(CONFIG_CMA))
+       if (IS_ENABLED(CONFIG_DMA_CMA))
                ptr = __alloc_from_contiguous(NULL, pool->size, prot, &page,
                                              atomic_pool_init);
        else
@@ -670,7 +670,7 @@ static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
                addr = __alloc_simple_buffer(dev, size, gfp, &page);
        else if (!(gfp & __GFP_WAIT))
                addr = __alloc_from_pool(size, &page);
-       else if (!IS_ENABLED(CONFIG_CMA))
+       else if (!IS_ENABLED(CONFIG_DMA_CMA))
                addr = __alloc_remap_buffer(dev, size, gfp, prot, &page, caller);
        else
                addr = __alloc_from_contiguous(dev, size, prot, &page, caller);
@@ -759,7 +759,7 @@ static void __arm_dma_free(struct device *dev, size_t size, void *cpu_addr,
                __dma_free_buffer(page, size);
        } else if (__free_from_pool(cpu_addr, size)) {
                return;
-       } else if (!IS_ENABLED(CONFIG_CMA)) {
+       } else if (!IS_ENABLED(CONFIG_DMA_CMA)) {
                __dma_free_remap(cpu_addr, size);
                __dma_free_buffer(page, size);
        } else {
index 15225d829d7173b6169076ad063a388ceefe1248..81484177c9b86f571efd9e88cd91a402306c7d9a 100644 (file)
@@ -77,7 +77,7 @@ static int __init parse_tag_initrd2(const struct tag *tag)
 __tagtable(ATAG_INITRD2, parse_tag_initrd2);
 
 #ifdef CONFIG_OF_FLATTREE
-void __init early_init_dt_setup_initrd_arch(unsigned long start, unsigned long end)
+void __init early_init_dt_setup_initrd_arch(u64 start, u64 end)
 {
        phys_initrd_start = start;
        phys_initrd_size = end - start;
index 4f56617a2392d58e52f96582a3631c4c49a4f5f2..b3fdb63783e373b6a522b25166dc2b4f68c5fd85 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)
@@ -1276,8 +1311,6 @@ void __init paging_init(struct machine_desc *mdesc)
 {
        void *zero_page;
 
-       memblock_set_current_limit(arm_lowmem_limit);
-
        build_mem_type_table();
        prepare_page_table();
        map_lowmem();
index f64afb9f1bd595a9fb1b9c0cd8bb442c9fda0337..bdd3be4be77aa50c93dcc20c8afdaa3af3c0cf5f 100644 (file)
@@ -110,7 +110,7 @@ ENTRY(cpu_v7_set_pte_ext)
  ARM(  str     r3, [r0, #2048]! )
  THUMB(        add     r0, r0, #2048 )
  THUMB(        str     r3, [r0] )
-       ALT_SMP(mov     pc,lr)
+       ALT_SMP(W(nop))
        ALT_UP (mcr     p15, 0, r0, c7, c10, 1)         @ flush_pte
 #endif
        mov     pc, lr
index c36ac69488c8fa60b17d91d085d1f8efcae42cb6..01a719e18bb047c655694c336d5a42e1388d1062 100644 (file)
@@ -81,7 +81,7 @@ ENTRY(cpu_v7_set_pte_ext)
        tst     r3, #1 << (55 - 32)             @ L_PTE_DIRTY
        orreq   r2, #L_PTE_RDONLY
 1:     strd    r2, r3, [r0]
-       ALT_SMP(mov     pc, lr)
+       ALT_SMP(W(nop))
        ALT_UP (mcr     p15, 0, r0, c7, c10, 1)         @ flush_pte
 #endif
        mov     pc, lr
index 5c6d5a3050eac65f1f2f89465d8398c971f866e4..73398bcf9bd8ea8d7293803828cb837306742fb7 100644 (file)
@@ -75,13 +75,14 @@ ENTRY(cpu_v7_do_idle)
 ENDPROC(cpu_v7_do_idle)
 
 ENTRY(cpu_v7_dcache_clean_area)
-       ALT_SMP(mov     pc, lr)                 @ MP extensions imply L1 PTW
-       ALT_UP(W(nop))
-       dcache_line_size r2, r3
-1:     mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
+       ALT_SMP(W(nop))                 @ MP extensions imply L1 PTW
+       ALT_UP_B(1f)
+       mov     pc, lr
+1:     dcache_line_size r2, r3
+2:     mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
        add     r0, r0, r2
        subs    r1, r1, r2
-       bhi     1b
+       bhi     2b
        dsb
        mov     pc, lr
 ENDPROC(cpu_v7_dcache_clean_area)
index 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 67e8d7ce3fe7a68ac1c974058de83b8d6226086e..de2de5db628de2382e555b4256b9ad1f0f92ada5 100644 (file)
@@ -44,8 +44,7 @@ static unsigned long phys_initrd_size __initdata = 0;
 
 phys_addr_t memstart_addr __read_mostly = 0;
 
-void __init early_init_dt_setup_initrd_arch(unsigned long start,
-                                           unsigned long end)
+void __init early_init_dt_setup_initrd_arch(u64 start, u64 end)
 {
        phys_initrd_start = start;
        phys_initrd_size = end - start;
index 20388750d56447ee92324ee50cadfc0dacb5c89b..64919b0da7aa53a5464a4dff92452c5aa94b46b1 100644 (file)
@@ -58,7 +58,7 @@ static struct fb_monspecs __initdata atevklcd10x_default_monspecs = {
        .dclkmax                = 28330000,
 };
 
-static struct atmel_lcdfb_info __initdata atevklcd10x_lcdc_data = {
+static struct atmel_lcdfb_pdata __initdata atevklcd10x_lcdc_data = {
        .default_bpp            = 16,
        .default_dmacon         = ATMEL_LCDC_DMAEN | ATMEL_LCDC_DMA2DEN,
        .default_lcdcon2        = (ATMEL_LCDC_DISTYPE_TFT
@@ -96,7 +96,7 @@ static struct fb_monspecs __initdata atevklcd10x_default_monspecs = {
        .dclkmax                = 7000000,
 };
 
-static struct atmel_lcdfb_info __initdata atevklcd10x_lcdc_data = {
+static struct atmel_lcdfb_pdata __initdata atevklcd10x_lcdc_data = {
        .default_bpp            = 16,
        .default_dmacon         = ATMEL_LCDC_DMAEN | ATMEL_LCDC_DMA2DEN,
        .default_lcdcon2        = (ATMEL_LCDC_DISTYPE_TFT
@@ -134,7 +134,7 @@ static struct fb_monspecs __initdata atevklcd10x_default_monspecs = {
        .dclkmax                = 6400000,
 };
 
-static struct atmel_lcdfb_info __initdata atevklcd10x_lcdc_data = {
+static struct atmel_lcdfb_pdata __initdata atevklcd10x_lcdc_data = {
        .default_bpp            = 16,
        .default_dmacon         = ATMEL_LCDC_DMAEN | ATMEL_LCDC_DMA2DEN,
        .default_lcdcon2        = (ATMEL_LCDC_DISTYPE_TFT
@@ -145,7 +145,7 @@ static struct atmel_lcdfb_info __initdata atevklcd10x_lcdc_data = {
 };
 #endif
 
-static void atevklcd10x_lcdc_power_control(int on)
+static void atevklcd10x_lcdc_power_control(struct atmel_lcdfb_pdata *pdata, int on)
 {
        gpio_set_value(GPIO_PIN_PB(15), on);
 }
index f9143196345271698a674b360769cf05c8173de4..ccc9599b53b9a72897dac59af7962ba1af06246a 100644 (file)
@@ -83,7 +83,7 @@ static struct fb_monspecs __initdata lcd_fb_default_monspecs = {
        .dclkmax                = 9260000,
 };
 
-static struct atmel_lcdfb_info __initdata rmt_lcdc_data = {
+static struct atmel_lcdfb_pdata __initdata rmt_lcdc_data = {
        .default_bpp            = 24,
        .default_dmacon         = ATMEL_LCDC_DMAEN | ATMEL_LCDC_DMA2DEN,
        .default_lcdcon2        = (ATMEL_LCDC_DISTYPE_TFT
@@ -126,7 +126,7 @@ static struct fb_monspecs __initdata lcd_fb_default_monspecs = {
        .dclkmax                = 9260000,
 };
 
-static struct atmel_lcdfb_info __initdata rmt_lcdc_data = {
+static struct atmel_lcdfb_pdata __initdata rmt_lcdc_data = {
        .default_bpp            = 24,
        .default_dmacon         = ATMEL_LCDC_DMAEN | ATMEL_LCDC_DMA2DEN,
        .default_lcdcon2        = (ATMEL_LCDC_DISTYPE_TFT
index 9392d3252865a6886025167fe151e7356acf8f64..653cc09e536c7555272b2d2988f6db67ffa61ce9 100644 (file)
@@ -10,7 +10,7 @@
 #ifndef __ARCH_AVR32_BOARDS_ATSTK1000_ATSTK1000_H
 #define __ARCH_AVR32_BOARDS_ATSTK1000_ATSTK1000_H
 
-extern struct atmel_lcdfb_info atstk1000_lcdc_data;
+extern struct atmel_lcdfb_pdata atstk1000_lcdc_data;
 
 void atstk1000_setup_j2_leds(void);
 
index 2d6b560115d9fa19c250f52a0a6e7c27bea27e81..b6b88f5e0b43a6d1e8c330e512021ec27935e7d5 100644 (file)
@@ -55,7 +55,7 @@ static struct fb_monspecs __initdata atstk1000_default_monspecs = {
        .dclkmax                = 30000000,
 };
 
-struct atmel_lcdfb_info __initdata atstk1000_lcdc_data = {
+struct atmel_lcdfb_pdata __initdata atstk1000_lcdc_data = {
        .default_bpp            = 24,
        .default_dmacon         = ATMEL_LCDC_DMAEN | ATMEL_LCDC_DMA2DEN,
        .default_lcdcon2        = (ATMEL_LCDC_DISTYPE_TFT
index 27bd6fbe21cb5f76253ad88f50f4a12c13f9778e..7b1f2cd854008c16117cf5c39c06f4bd2115a9fa 100644 (file)
@@ -125,7 +125,7 @@ static struct fb_monspecs __initdata favr32_default_monspecs = {
        .dclkmax                = 28000000,
 };
 
-struct atmel_lcdfb_info __initdata favr32_lcdc_data = {
+struct atmel_lcdfb_pdata __initdata favr32_lcdc_data = {
        .default_bpp            = 16,
        .default_dmacon         = ATMEL_LCDC_DMAEN | ATMEL_LCDC_DMA2DEN,
        .default_lcdcon2        = (ATMEL_LCDC_DISTYPE_TFT
index 9d1efd1cd42534076307d59c1444a663c3b8764d..dc0e317f2ecdddc62c23939dd0863749c4491de8 100644 (file)
@@ -77,7 +77,7 @@ static struct fb_monspecs __initdata hammerhead_hda350t_monspecs = {
        .dclkmax                = 10000000,
 };
 
-struct atmel_lcdfb_info __initdata hammerhead_lcdc_data = {
+struct atmel_lcdfb_pdata __initdata hammerhead_lcdc_data = {
        .default_bpp            = 24,
        .default_dmacon         = ATMEL_LCDC_DMAEN | ATMEL_LCDC_DMA2DEN,
        .default_lcdcon2        = (ATMEL_LCDC_DISTYPE_TFT
index 85a543cd4abcf26c3e517975029b8b694f197999..e7683ee7ed408d8ebe46930bf9ee4cb6a0885e91 100644 (file)
@@ -45,7 +45,7 @@ static struct fb_monspecs merisc_fb_monspecs = {
        .dclkmax        = 30000000,
 };
 
-struct atmel_lcdfb_info merisc_lcdc_data = {
+struct atmel_lcdfb_pdata merisc_lcdc_data = {
        .default_bpp            = 24,
        .default_dmacon         = ATMEL_LCDC_DMAEN | ATMEL_LCDC_DMA2DEN,
        .default_lcdcon2        = (ATMEL_LCDC_DISTYPE_TFT
index 05358aa5ef7d210ed42d2bb6f68be48b3fa4c690..1cb8e9cc5cfaedb6d00ed8e589393531c37bf4ed 100644 (file)
@@ -8,7 +8,7 @@
  * published by the Free Software Foundation.
  */
 
-extern struct atmel_lcdfb_info mimc200_lcdc_data;
+extern struct atmel_lcdfb_pdata mimc200_lcdc_data;
 
 #include <linux/clk.h>
 #include <linux/etherdevice.h>
@@ -71,7 +71,7 @@ static struct fb_monspecs __initdata mimc200_default_monspecs = {
        .dclkmax                = 25200000,
 };
 
-struct atmel_lcdfb_info __initdata mimc200_lcdc_data = {
+struct atmel_lcdfb_pdata __initdata mimc200_lcdc_data = {
        .default_bpp            = 16,
        .default_dmacon         = ATMEL_LCDC_DMAEN | ATMEL_LCDC_DMA2DEN,
        .default_lcdcon2        = (ATMEL_LCDC_DISTYPE_TFT
index 7f8759a8a92a08b8ed8e772d9f08c9d3404d8697..a1f4d1e91b522e03f486b41759a1b25a2d44e36f 100644 (file)
@@ -1439,7 +1439,7 @@ fail:
  *  LCDC
  * -------------------------------------------------------------------- */
 #if defined(CONFIG_CPU_AT32AP7000) || defined(CONFIG_CPU_AT32AP7002)
-static struct atmel_lcdfb_info atmel_lcdfb0_data;
+static struct atmel_lcdfb_pdata atmel_lcdfb0_data;
 static struct resource atmel_lcdfb0_resource[] = {
        {
                .start          = 0xff000000,
@@ -1467,12 +1467,12 @@ static struct clk atmel_lcdfb0_pixclk = {
 };
 
 struct platform_device *__init
-at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
+at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_pdata *data,
                     unsigned long fbmem_start, unsigned long fbmem_len,
                     u64 pin_mask)
 {
        struct platform_device *pdev;
-       struct atmel_lcdfb_info *info;
+       struct atmel_lcdfb_pdata *info;
        struct fb_monspecs *monspecs;
        struct fb_videomode *modedb;
        unsigned int modedb_size;
@@ -1529,7 +1529,7 @@ at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
        }
 
        info = pdev->dev.platform_data;
-       memcpy(info, data, sizeof(struct atmel_lcdfb_info));
+       memcpy(info, data, sizeof(struct atmel_lcdfb_pdata));
        info->default_monspecs = monspecs;
 
        pdev->name = "at32ap-lcdfb";
@@ -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 d485b0391357cab467faefab4e07ba20e0aad2ac..f1a316d52c738b0bac6653c876c3c7c817f28a66 100644 (file)
@@ -44,9 +44,9 @@ struct platform_device *
 at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n);
 void at32_spi_setup_slaves(unsigned int bus_num, struct spi_board_info *b, unsigned int n);
 
-struct atmel_lcdfb_info;
+struct atmel_lcdfb_pdata;
 struct platform_device *
-at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
+at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_pdata *data,
                     unsigned long fbmem_start, unsigned long fbmem_len,
                     u64 pin_mask);
 
index bdb56f09d0acc42eacf87398e48e08645ac727c8..287d0e64dfba58b955c10b4b8d4268140271c9c8 100644 (file)
@@ -33,8 +33,7 @@ void __init early_init_devtree(void *params)
 
 
 #ifdef CONFIG_BLK_DEV_INITRD
-void __init early_init_dt_setup_initrd_arch(unsigned long start,
-               unsigned long end)
+void __init early_init_dt_setup_initrd_arch(u64 start, u64 end)
 {
        initrd_start = (unsigned long)__va(start);
        initrd_end = (unsigned long)__va(end);
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 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 5b2dc0d10c8f4211d28e044a2071306d1ef955ed..bdfd8789b37661da691bdf320841a21043cd4cd4 100644 (file)
@@ -1560,6 +1560,10 @@ int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages)
        return 0;
 }
 
+void kvm_arch_memslots_updated(struct kvm *kvm)
+{
+}
+
 int kvm_arch_prepare_memory_region(struct kvm *kvm,
                struct kvm_memory_slot *memslot,
                struct kvm_userspace_memory_region *mem,
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 28813f164730f7110ccf470d6ef610932f166580..123919534b80fe3724612b61697441305d5b10a6 100644 (file)
@@ -407,10 +407,9 @@ void free_initrd_mem(unsigned long start, unsigned long end)
 #endif
 
 #ifdef CONFIG_OF_FLATTREE
-void __init early_init_dt_setup_initrd_arch(unsigned long start,
-                                           unsigned long end)
+void __init early_init_dt_setup_initrd_arch(u64 start, u64 end)
 {
-       pr_err("%s(%lx, %lx)\n",
+       pr_err("%s(%llx, %llx)\n",
               __func__, start, end);
 }
 #endif /* CONFIG_OF_FLATTREE */
index 0a2c68f9f9b0d61cf14e3f28de7ef23d87adcced..62e2e8f2c5d617a2a1c3271166441630b63b85cf 100644 (file)
@@ -136,8 +136,7 @@ void __init early_init_devtree(void *params)
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
-void __init early_init_dt_setup_initrd_arch(unsigned long start,
-               unsigned long end)
+void __init early_init_dt_setup_initrd_arch(u64 start, u64 end)
 {
        initrd_start = (unsigned long)__va(start);
        initrd_end = (unsigned long)__va(end);
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 7e954042f2526e66f21579f73d609452a5b1d726..0fa0b69cdd53bcc7e7d7d0bf836d3e40c767b4a4 100644 (file)
@@ -58,8 +58,7 @@ void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
-void __init early_init_dt_setup_initrd_arch(unsigned long start,
-                                           unsigned long end)
+void __init early_init_dt_setup_initrd_arch(u64 start, u64 end)
 {
        initrd_start = (unsigned long)__va(start);
        initrd_end = (unsigned long)__va(end);
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 dd203e59e6fd650767a3ae5286e0599f4dbc15b7..a7b044536de48e0f804d2270fc69a3cdbe6a3335 100644 (file)
@@ -208,6 +208,10 @@ int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages)
        return 0;
 }
 
+void kvm_arch_memslots_updated(struct kvm *kvm)
+{
+}
+
 int kvm_arch_prepare_memory_region(struct kvm *kvm,
                                 struct kvm_memory_slot *memslot,
                                 struct kvm_userspace_memory_region *mem,
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 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 5869e3fa5dd3ac4f9b31cd63140ac01592593ddd..150215a9171145655a5973cd376916699810f3aa 100644 (file)
@@ -96,8 +96,7 @@ void __init early_init_devtree(void *params)
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
-void __init early_init_dt_setup_initrd_arch(unsigned long start,
-               unsigned long end)
+void __init early_init_dt_setup_initrd_arch(u64 start, u64 end)
 {
        initrd_start = (unsigned long)__va(start);
        initrd_end = (unsigned long)__va(end);
diff --git a/arch/parisc/configs/c8000_defconfig b/arch/parisc/configs/c8000_defconfig
new file mode 100644 (file)
index 0000000..f110063
--- /dev/null
@@ -0,0 +1,279 @@
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_FHANDLE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_RD_LZO=y
+CONFIG_EXPERT=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_BLK_DEV_INTEGRITY=y
+CONFIG_PA8X00=y
+CONFIG_MLONGCALLS=y
+CONFIG_64BIT=y
+CONFIG_SMP=y
+CONFIG_PREEMPT=y
+# CONFIG_CROSS_MEMORY_ATTACH is not set
+CONFIG_IOMMU_CCIO=y
+CONFIG_PCI=y
+CONFIG_PCI_LBA=y
+# CONFIG_SUPERIO is not set
+# CONFIG_CHASSIS_LCD_LED is not set
+# CONFIG_PDC_CHASSIS is not set
+# CONFIG_PDC_CHASSIS_WARN is not set
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_BINFMT_MISC=m
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=m
+CONFIG_XFRM_SUB_POLICY=y
+CONFIG_NET_KEY=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_NET_IPIP=m
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_MODE_BEET=m
+CONFIG_INET_DIAG=m
+# CONFIG_IPV6 is not set
+CONFIG_IP_DCCP=m
+# CONFIG_IP_DCCP_CCID3 is not set
+CONFIG_TIPC=m
+CONFIG_LLC2=m
+CONFIG_DNS_RESOLVER=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_STANDALONE is not set
+CONFIG_PARPORT=y
+CONFIG_PARPORT_PC=y
+CONFIG_PARPORT_PC_FIFO=y
+CONFIG_BLK_DEV_UMEM=m
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_SX8=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=6144
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CDROM_PKTCDVD_WCACHE=y
+CONFIG_ATA_OVER_ETH=m
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDECD=y
+CONFIG_BLK_DEV_PLATFORM=y
+CONFIG_BLK_DEV_GENERIC=y
+CONFIG_BLK_DEV_SIIMAGE=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=m
+CONFIG_BLK_DEV_SR=m
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=m
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_FC_ATTRS=y
+CONFIG_SCSI_SAS_LIBSAS=m
+CONFIG_ISCSI_TCP=m
+CONFIG_ISCSI_BOOT_SYSFS=m
+CONFIG_FUSION=y
+CONFIG_FUSION_SPI=y
+CONFIG_FUSION_SAS=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+CONFIG_NETCONSOLE=m
+CONFIG_TUN=y
+CONFIG_E1000=y
+CONFIG_PPP=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+# CONFIG_WLAN is not set
+CONFIG_INPUT_FF_MEMLESS=m
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_HIL_OLD is not set
+# CONFIG_KEYBOARD_HIL is not set
+CONFIG_MOUSE_PS2=m
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_CM109=m
+CONFIG_SERIO_SERPORT=m
+CONFIG_SERIO_PARKBD=m
+CONFIG_SERIO_GSCPS2=m
+# CONFIG_HP_SDC is not set
+CONFIG_SERIO_PCIPS2=m
+CONFIG_SERIO_LIBPS2=y
+CONFIG_SERIO_RAW=m
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=8
+CONFIG_SERIAL_8250_RUNTIME_UARTS=8
+CONFIG_SERIAL_8250_EXTENDED=y
+# CONFIG_SERIAL_MUX is not set
+CONFIG_SERIAL_JSM=m
+CONFIG_PRINTER=y
+CONFIG_HW_RANDOM=y
+CONFIG_RAW_DRIVER=m
+CONFIG_PTP_1588_CLOCK=y
+CONFIG_SSB=m
+CONFIG_SSB_DRIVER_PCICORE=y
+CONFIG_AGP=y
+CONFIG_AGP_PARISC=y
+CONFIG_DRM=y
+CONFIG_DRM_RADEON=y
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FB_FOREIGN_ENDIAN=y
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+# CONFIG_FB_STI is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_STI_CONSOLE is not set
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+CONFIG_SOUND=m
+CONFIG_SND=m
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_SEQUENCER_OSS=y
+CONFIG_SND_VERBOSE_PRINTK=y
+CONFIG_SND_AD1889=m
+# CONFIG_SND_USB is not set
+# CONFIG_SND_GSC is not set
+CONFIG_HID_A4TECH=m
+CONFIG_HID_APPLE=m
+CONFIG_HID_BELKIN=m
+CONFIG_HID_CHERRY=m
+CONFIG_HID_CHICONY=m
+CONFIG_HID_CYPRESS=m
+CONFIG_HID_DRAGONRISE=m
+CONFIG_HID_EZKEY=m
+CONFIG_HID_KYE=m
+CONFIG_HID_GYRATION=m
+CONFIG_HID_TWINHAN=m
+CONFIG_HID_KENSINGTON=m
+CONFIG_HID_LOGITECH=m
+CONFIG_HID_LOGITECH_DJ=m
+CONFIG_HID_MICROSOFT=m
+CONFIG_HID_MONTEREY=m
+CONFIG_HID_NTRIG=m
+CONFIG_HID_ORTEK=m
+CONFIG_HID_PANTHERLORD=m
+CONFIG_HID_PETALYNX=m
+CONFIG_HID_SAMSUNG=m
+CONFIG_HID_SUNPLUS=m
+CONFIG_HID_GREENASIA=m
+CONFIG_HID_SMARTJOYPLUS=m
+CONFIG_HID_TOPSEED=m
+CONFIG_HID_THRUSTMASTER=m
+CONFIG_HID_ZEROPLUS=m
+CONFIG_USB_HID=m
+CONFIG_USB=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT4_FS=m
+CONFIG_REISERFS_FS=m
+CONFIG_REISERFS_PROC_INFO=y
+CONFIG_XFS_FS=m
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_QUOTA=y
+CONFIG_QFMT_V1=m
+CONFIG_QFMT_V2=m
+CONFIG_AUTOFS4_FS=m
+CONFIG_FUSE_FS=m
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_XATTR=y
+CONFIG_NFS_FS=m
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+CONFIG_UNUSED_SYMBOLS=y
+CONFIG_DEBUG_FS=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_SLAB=y
+CONFIG_DEBUG_SLAB_LEAK=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_STACKOVERFLOW=y
+CONFIG_LOCKUP_DETECTOR=y
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
+CONFIG_PANIC_ON_OOPS=y
+CONFIG_DEBUG_RT_MUTEXES=y
+CONFIG_RT_MUTEX_TESTER=y
+CONFIG_PROVE_RCU_DELAY=y
+CONFIG_DEBUG_BLOCK_EXT_DEVT=y
+CONFIG_LATENCYTOP=y
+CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y
+CONFIG_KEYS=y
+# CONFIG_CRYPTO_HW is not set
+CONFIG_FONTS=y
diff --git a/arch/parisc/configs/generic-32bit_defconfig b/arch/parisc/configs/generic-32bit_defconfig
new file mode 100644 (file)
index 0000000..7f03614
--- /dev/null
@@ -0,0 +1,340 @@
+CONFIG_LOCALVERSION="-32bit"
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_FHANDLE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=16
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_RD_LZO=y
+CONFIG_EXPERT=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_PERF_EVENTS=y
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PA7100LC=y
+CONFIG_SMP=y
+CONFIG_HZ_100=y
+CONFIG_IOMMU_CCIO=y
+CONFIG_GSC_LASI=y
+CONFIG_GSC_WAX=y
+CONFIG_EISA=y
+CONFIG_PCI=y
+CONFIG_GSC_DINO=y
+CONFIG_PCI_LBA=y
+CONFIG_PCCARD=m
+CONFIG_YENTA=m
+CONFIG_PD6729=m
+CONFIG_I82092=m
+# CONFIG_PDC_CHASSIS is not set
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_BINFMT_MISC=m
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=m
+CONFIG_NET_KEY=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=m
+CONFIG_LLC2=m
+# CONFIG_WIRELESS is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+CONFIG_PARPORT=y
+CONFIG_PARPORT_PC=m
+CONFIG_PARPORT_PC_PCMCIA=m
+CONFIG_PARPORT_1284=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=6144
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDECS=m
+CONFIG_BLK_DEV_IDECD=y
+CONFIG_BLK_DEV_GENERIC=y
+CONFIG_BLK_DEV_NS87415=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_SCSI_LASI700=y
+CONFIG_SCSI_SYM53C8XX_2=y
+CONFIG_SCSI_ZALON=y
+CONFIG_SCSI_DH=y
+CONFIG_ATA=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID10=m
+CONFIG_MD_RAID456=m
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_UEVENT=y
+CONFIG_NETDEVICES=y
+CONFIG_BONDING=m
+CONFIG_DUMMY=m
+CONFIG_TUN=m
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_ADAPTEC is not set
+# CONFIG_NET_VENDOR_ALTEON is not set
+# CONFIG_NET_VENDOR_AMD is not set
+# CONFIG_NET_VENDOR_ATHEROS is not set
+# CONFIG_NET_CADENCE is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_BROCADE is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_NET_VENDOR_CISCO is not set
+CONFIG_NET_TULIP=y
+CONFIG_TULIP=y
+# CONFIG_NET_VENDOR_DLINK is not set
+# CONFIG_NET_VENDOR_EMULEX is not set
+# CONFIG_NET_VENDOR_EXAR is not set
+# CONFIG_NET_VENDOR_FUJITSU is not set
+# CONFIG_NET_VENDOR_HP is not set
+CONFIG_LASI_82596=y
+# CONFIG_NET_VENDOR_MELLANOX is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MYRI is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_NVIDIA is not set
+# CONFIG_NET_VENDOR_OKI is not set
+# CONFIG_NET_PACKET_ENGINE is not set
+# CONFIG_NET_VENDOR_QLOGIC is not set
+# CONFIG_NET_VENDOR_REALTEK is not set
+# CONFIG_NET_VENDOR_RDC is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SILAN is not set
+# CONFIG_NET_VENDOR_SIS is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_NET_VENDOR_SUN is not set
+# CONFIG_NET_VENDOR_TEHUTI is not set
+# CONFIG_NET_VENDOR_TI is not set
+# CONFIG_NET_VENDOR_VIA is not set
+# CONFIG_NET_VENDOR_XIRCOM is not set
+CONFIG_PPP=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPPOE=m
+# CONFIG_WLAN is not set
+CONFIG_INPUT_POLLDEV=y
+CONFIG_KEYBOARD_HIL_OLD=m
+CONFIG_KEYBOARD_HIL=m
+CONFIG_MOUSE_SERIAL=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=m
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_LEGACY_PTY_COUNT=64
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_CS=m
+CONFIG_SERIAL_8250_NR_UARTS=8
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_PRINTER=m
+CONFIG_PPDEV=m
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+CONFIG_POWER_SUPPLY=y
+# CONFIG_HWMON is not set
+CONFIG_AGP=y
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+CONFIG_FB_FOREIGN_ENDIAN=y
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_MATROX=m
+CONFIG_FB_MATROX_G=y
+CONFIG_FB_VOODOO1=m
+CONFIG_DUMMY_CONSOLE_COLUMNS=128
+CONFIG_DUMMY_CONSOLE_ROWS=48
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+CONFIG_SOUND=m
+CONFIG_SND=m
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_SEQUENCER_OSS=y
+CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_AD1889=m
+# CONFIG_SND_PCMCIA is not set
+CONFIG_SND_HARMONY=m
+CONFIG_HIDRAW=y
+CONFIG_HID_A4TECH=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_CYPRESS=y
+CONFIG_HID_DRAGONRISE=y
+CONFIG_HID_EZKEY=y
+CONFIG_HID_KYE=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_TWINHAN=y
+CONFIG_HID_KENSINGTON=y
+CONFIG_HID_LOGITECH=y
+CONFIG_HID_LOGITECH_DJ=m
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+CONFIG_HID_NTRIG=y
+CONFIG_HID_ORTEK=y
+CONFIG_HID_PANTHERLORD=y
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SONY=y
+CONFIG_HID_SUNPLUS=y
+CONFIG_HID_GREENASIA=y
+CONFIG_HID_SMARTJOYPLUS=y
+CONFIG_HID_TOPSEED=y
+CONFIG_HID_THRUSTMASTER=y
+CONFIG_HID_ZEROPLUS=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_MON=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_UHCI_HCD=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_IDE_DISK=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+CONFIG_DMADEVICES=y
+CONFIG_AUXDISPLAY=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_XFS_FS=m
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_XFS_RT=y
+CONFIG_QUOTA=y
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+CONFIG_QFMT_V2=y
+CONFIG_AUTOFS4_FS=y
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_VFAT_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_NFS_FS=m
+# CONFIG_NFS_V2 is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V3_ACL=y
+CONFIG_CIFS=m
+CONFIG_CIFS_WEAK_PW_HASH=y
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+# CONFIG_CIFS_DEBUG is not set
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=y
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=y
+CONFIG_UNUSED_SYMBOLS=y
+CONFIG_DEBUG_FS=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_STACKOVERFLOW=y
+CONFIG_DEBUG_SHIRQ=y
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_RT_MUTEXES=y
+CONFIG_RT_MUTEX_TESTER=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_RCU_CPU_STALL_INFO=y
+CONFIG_LATENCYTOP=y
+CONFIG_LKDTM=m
+CONFIG_KEYS=y
+CONFIG_KEYS_DEBUG_PROC_KEYS=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_TEST=m
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_DEFLATE=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRC_CCITT=m
+CONFIG_CRC_T10DIF=y
+CONFIG_FONTS=y
diff --git a/arch/parisc/configs/generic-64bit_defconfig b/arch/parisc/configs/generic-64bit_defconfig
new file mode 100644 (file)
index 0000000..6952cb5
--- /dev/null
@@ -0,0 +1,350 @@
+CONFIG_LOCALVERSION="-64bit"
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_BLK_DEV_INTEGRITY=y
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_PA8X00=y
+CONFIG_MLONGCALLS=y
+CONFIG_64BIT=y
+CONFIG_SMP=y
+# CONFIG_COMPACTION is not set
+CONFIG_HPPB=y
+CONFIG_IOMMU_CCIO=y
+CONFIG_GSC_LASI=y
+CONFIG_GSC_WAX=y
+CONFIG_PCI=y
+CONFIG_PCI_STUB=m
+CONFIG_PCI_IOV=y
+CONFIG_GSC_DINO=y
+CONFIG_PCI_LBA=y
+CONFIG_BINFMT_MISC=m
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=m
+CONFIG_XFRM_SUB_POLICY=y
+CONFIG_XFRM_MIGRATE=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=m
+CONFIG_INET_XFRM_MODE_TUNNEL=m
+CONFIG_INET_XFRM_MODE_BEET=m
+CONFIG_INET_LRO=m
+CONFIG_INET_DIAG=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_ADVANCED is not set
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_DCB=y
+CONFIG_AF_RXRPC=y
+# CONFIG_WIRELESS is not set
+CONFIG_DEVTMPFS=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_IDE=y
+CONFIG_IDE_GD=m
+CONFIG_IDE_GD_ATAPI=y
+CONFIG_BLK_DEV_IDECD=m
+CONFIG_BLK_DEV_NS87415=y
+CONFIG_BLK_DEV_SIIMAGE=y
+# CONFIG_SCSI_PROC_FS is not set
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_SCSI_ISCSI_ATTRS=y
+CONFIG_SCSI_SRP_ATTRS=y
+CONFIG_ISCSI_BOOT_SYSFS=y
+CONFIG_SCSI_MPT2SAS=y
+CONFIG_SCSI_LASI700=m
+CONFIG_SCSI_SYM53C8XX_2=y
+CONFIG_SCSI_ZALON=y
+CONFIG_SCSI_QLA_ISCSI=m
+CONFIG_SCSI_DH=y
+CONFIG_ATA=y
+CONFIG_ATA_GENERIC=y
+CONFIG_MD=y
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_RAID=m
+CONFIG_DM_UEVENT=y
+CONFIG_FUSION=y
+CONFIG_FUSION_SPI=y
+CONFIG_FUSION_SAS=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+CONFIG_MACVLAN=m
+CONFIG_MACVTAP=m
+CONFIG_NETCONSOLE=m
+CONFIG_NETCONSOLE_DYNAMIC=y
+CONFIG_TUN=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_ADAPTEC is not set
+# CONFIG_NET_VENDOR_ALTEON is not set
+# CONFIG_NET_VENDOR_AMD is not set
+# CONFIG_NET_VENDOR_ARC is not set
+# CONFIG_NET_VENDOR_ATHEROS is not set
+# CONFIG_NET_CADENCE is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_BROCADE is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_CISCO is not set
+CONFIG_NET_TULIP=y
+CONFIG_TULIP=y
+# CONFIG_NET_VENDOR_DLINK is not set
+# CONFIG_NET_VENDOR_EMULEX is not set
+# CONFIG_NET_VENDOR_EXAR is not set
+CONFIG_HP100=m
+CONFIG_E1000=y
+CONFIG_LASI_82596=y
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MELLANOX is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MYRI is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_NVIDIA is not set
+# CONFIG_NET_VENDOR_OKI is not set
+CONFIG_QLA3XXX=m
+CONFIG_QLCNIC=m
+CONFIG_QLGE=m
+# CONFIG_NET_VENDOR_REALTEK is not set
+# CONFIG_NET_VENDOR_RDC is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SILAN is not set
+# CONFIG_NET_VENDOR_SIS is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_NET_VENDOR_SUN is not set
+# CONFIG_NET_VENDOR_TEHUTI is not set
+# CONFIG_NET_VENDOR_TI is not set
+# CONFIG_NET_VENDOR_VIA is not set
+# CONFIG_NET_VENDOR_WIZNET is not set
+CONFIG_PHYLIB=y
+CONFIG_MARVELL_PHY=m
+CONFIG_DAVICOM_PHY=m
+CONFIG_QSEMI_PHY=m
+CONFIG_LXT_PHY=m
+CONFIG_CICADA_PHY=m
+CONFIG_VITESSE_PHY=m
+CONFIG_SMSC_PHY=m
+CONFIG_BROADCOM_PHY=m
+CONFIG_ICPLUS_PHY=m
+CONFIG_REALTEK_PHY=m
+CONFIG_NATIONAL_PHY=m
+CONFIG_STE10XP=m
+CONFIG_LSI_ET1011C_PHY=m
+CONFIG_MDIO_BITBANG=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+# CONFIG_WLAN is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_KEYBOARD_HIL_OLD is not set
+# CONFIG_KEYBOARD_HIL is not set
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_MISC=y
+CONFIG_HP_SDC_RTC=m
+CONFIG_SERIO_SERPORT=m
+CONFIG_HP_SDC=m
+CONFIG_HIL_MLC=m
+CONFIG_SERIO_RAW=m
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_NOZOMI=m
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=8
+CONFIG_SERIAL_8250_RUNTIME_UARTS=8
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_JSM=m
+CONFIG_HW_RANDOM_TIMERIOMEM=m
+CONFIG_TCG_TPM=m
+CONFIG_TCG_ATMEL=m
+CONFIG_PTP_1588_CLOCK=m
+CONFIG_SENSORS_I5K_AMB=m
+CONFIG_SENSORS_F71882FG=m
+CONFIG_SENSORS_PC87427=m
+CONFIG_SENSORS_VT1211=m
+CONFIG_SENSORS_VT8231=m
+CONFIG_SENSORS_W83627EHF=m
+CONFIG_WATCHDOG=y
+CONFIG_SOFT_WATCHDOG=m
+CONFIG_SSB=m
+CONFIG_SSB_DRIVER_PCICORE=y
+CONFIG_HTC_PASIC3=m
+CONFIG_LPC_SCH=m
+CONFIG_MFD_SM501=m
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=m
+CONFIG_REGULATOR_USERSPACE_CONSUMER=m
+CONFIG_MEDIA_SUPPORT=m
+CONFIG_AGP=y
+CONFIG_AGP_PARISC=y
+CONFIG_DRM=y
+CONFIG_DRM_RADEON=y
+CONFIG_DRM_RADEON_UMS=y
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+CONFIG_HID=m
+CONFIG_HIDRAW=y
+CONFIG_HID_DRAGONRISE=m
+CONFIG_DRAGONRISE_FF=y
+CONFIG_HID_KYE=m
+CONFIG_HID_GYRATION=m
+CONFIG_HID_TWINHAN=m
+CONFIG_LOGITECH_FF=y
+CONFIG_LOGIRUMBLEPAD2_FF=y
+CONFIG_HID_NTRIG=m
+CONFIG_HID_PANTHERLORD=m
+CONFIG_PANTHERLORD_FF=y
+CONFIG_HID_PETALYNX=m
+CONFIG_HID_SAMSUNG=m
+CONFIG_HID_SONY=m
+CONFIG_HID_SUNPLUS=m
+CONFIG_HID_GREENASIA=m
+CONFIG_GREENASIA_FF=y
+CONFIG_HID_SMARTJOYPLUS=m
+CONFIG_SMARTJOYPLUS_FF=y
+CONFIG_HID_TOPSEED=m
+CONFIG_HID_THRUSTMASTER=m
+CONFIG_THRUSTMASTER_FF=y
+CONFIG_HID_ZEROPLUS=m
+CONFIG_ZEROPLUS_FF=y
+CONFIG_USB_HID=m
+CONFIG_HID_PID=y
+CONFIG_USB_HIDDEV=y
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_DYNAMIC_MINORS=y
+CONFIG_USB_MON=m
+CONFIG_USB_WUSB_CBAF=m
+CONFIG_USB_XHCI_HCD=m
+CONFIG_USB_EHCI_HCD=m
+CONFIG_USB_OHCI_HCD=m
+CONFIG_USB_R8A66597_HCD=m
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+CONFIG_USB_WDM=m
+CONFIG_USB_TMC=m
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_ONESHOT=y
+CONFIG_LEDS_TRIGGER_IDE_DISK=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=m
+CONFIG_LEDS_TRIGGER_BACKLIGHT=m
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=m
+CONFIG_UIO=y
+CONFIG_UIO_PDRV_GENIRQ=m
+CONFIG_UIO_AEC=m
+CONFIG_UIO_SERCOS3=m
+CONFIG_UIO_PCI_GENERIC=m
+CONFIG_STAGING=y
+# CONFIG_NET_VENDOR_SILICOM is not set
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_XFS_FS=m
+CONFIG_BTRFS_FS=m
+CONFIG_QUOTA=y
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+CONFIG_QFMT_V2=y
+CONFIG_AUTOFS4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_CUSE=y
+CONFIG_ISO9660_FS=y
+CONFIG_UDF_FS=y
+CONFIG_VFAT_FS=m
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_CONFIGFS_FS=y
+CONFIG_SYSV_FS=y
+CONFIG_NFS_FS=m
+CONFIG_NFS_V4=m
+CONFIG_NFS_V4_1=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V4=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_UTF8=m
+CONFIG_PRINTK_TIME=y
+CONFIG_STRIP_ASM_SYMS=y
+CONFIG_UNUSED_SYMBOLS=y
+CONFIG_DEBUG_FS=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_STACKOVERFLOW=y
+CONFIG_LOCKUP_DETECTOR=y
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC=y
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_FCRYPT=m
+CONFIG_CRYPTO_DEFLATE=m
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC_CCITT=m
+CONFIG_LIBCRC32C=y
+CONFIG_XZ_DEC_X86=y
+CONFIG_XZ_DEC_POWERPC=y
+CONFIG_XZ_DEC_IA64=y
+CONFIG_XZ_DEC_ARM=y
+CONFIG_XZ_DEC_ARMTHUMB=y
+CONFIG_XZ_DEC_SPARC=y
index 9afdad6c2ffb81db7f8ffb68dd003bd3b5cd4980..eaf4dc1c729440688a169bd11fe81b250b8c776f 100644 (file)
@@ -23,6 +23,7 @@ struct parisc_device {
        /* generic info returned from pdc_pat_cell_module() */
        unsigned long   mod_info;       /* PAT specific - Misc Module info */
        unsigned long   pmod_loc;       /* physical Module location */
+       unsigned long   mod0;
 #endif
        u64             dma_mask;       /* DMA mask for I/O */
        struct device   dev;
@@ -61,4 +62,6 @@ parisc_get_drvdata(struct parisc_device *d)
 
 extern struct bus_type parisc_bus_type;
 
+int iosapic_serial_irq(struct parisc_device *dev);
+
 #endif /*_ASM_PARISC_PARISC_DEVICE_H_*/
index 2e65aa54bd101b7dc5600297858929687e90d549..c035673209f732f0850aaa4dc98d2d49eee3b74c 100644 (file)
@@ -71,18 +71,27 @@ flush_cache_all_local(void)
 }
 EXPORT_SYMBOL(flush_cache_all_local);
 
+/* Virtual address of pfn.  */
+#define pfn_va(pfn)    __va(PFN_PHYS(pfn))
+
 void
 update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep)
 {
-       struct page *page = pte_page(*ptep);
+       unsigned long pfn = pte_pfn(*ptep);
+       struct page *page;
 
-       if (pfn_valid(page_to_pfn(page)) && page_mapping(page) &&
-           test_bit(PG_dcache_dirty, &page->flags)) {
+       /* We don't have pte special.  As a result, we can be called with
+          an invalid pfn and we don't need to flush the kernel dcache page.
+          This occurs with FireGL card in C8000.  */
+       if (!pfn_valid(pfn))
+               return;
 
-               flush_kernel_dcache_page(page);
+       page = pfn_to_page(pfn);
+       if (page_mapping(page) && test_bit(PG_dcache_dirty, &page->flags)) {
+               flush_kernel_dcache_page_addr(pfn_va(pfn));
                clear_bit(PG_dcache_dirty, &page->flags);
        } else if (parisc_requires_coherency())
-               flush_kernel_dcache_page(page);
+               flush_kernel_dcache_page_addr(pfn_va(pfn));
 }
 
 void
@@ -495,44 +504,42 @@ static inline pte_t *get_ptep(pgd_t *pgd, unsigned long addr)
 
 void flush_cache_mm(struct mm_struct *mm)
 {
+       struct vm_area_struct *vma;
+       pgd_t *pgd;
+
        /* Flushing the whole cache on each cpu takes forever on
           rp3440, etc.  So, avoid it if the mm isn't too big.  */
-       if (mm_total_size(mm) < parisc_cache_flush_threshold) {
-               struct vm_area_struct *vma;
-
-               if (mm->context == mfsp(3)) {
-                       for (vma = mm->mmap; vma; vma = vma->vm_next) {
-                               flush_user_dcache_range_asm(vma->vm_start,
-                                       vma->vm_end);
-                               if (vma->vm_flags & VM_EXEC)
-                                       flush_user_icache_range_asm(
-                                         vma->vm_start, vma->vm_end);
-                       }
-               } else {
-                       pgd_t *pgd = mm->pgd;
-
-                       for (vma = mm->mmap; vma; vma = vma->vm_next) {
-                               unsigned long addr;
-
-                               for (addr = vma->vm_start; addr < vma->vm_end;
-                                    addr += PAGE_SIZE) {
-                                       pte_t *ptep = get_ptep(pgd, addr);
-                                       if (ptep != NULL) {
-                                               pte_t pte = *ptep;
-                                               __flush_cache_page(vma, addr,
-                                                 page_to_phys(pte_page(pte)));
-                                       }
-                               }
-                       }
+       if (mm_total_size(mm) >= parisc_cache_flush_threshold) {
+               flush_cache_all();
+               return;
+       }
+
+       if (mm->context == mfsp(3)) {
+               for (vma = mm->mmap; vma; vma = vma->vm_next) {
+                       flush_user_dcache_range_asm(vma->vm_start, vma->vm_end);
+                       if ((vma->vm_flags & VM_EXEC) == 0)
+                               continue;
+                       flush_user_icache_range_asm(vma->vm_start, vma->vm_end);
                }
                return;
        }
 
-#ifdef CONFIG_SMP
-       flush_cache_all();
-#else
-       flush_cache_all_local();
-#endif
+       pgd = mm->pgd;
+       for (vma = mm->mmap; vma; vma = vma->vm_next) {
+               unsigned long addr;
+
+               for (addr = vma->vm_start; addr < vma->vm_end;
+                    addr += PAGE_SIZE) {
+                       unsigned long pfn;
+                       pte_t *ptep = get_ptep(pgd, addr);
+                       if (!ptep)
+                               continue;
+                       pfn = pte_pfn(*ptep);
+                       if (!pfn_valid(pfn))
+                               continue;
+                       __flush_cache_page(vma, addr, PFN_PHYS(pfn));
+               }
+       }
 }
 
 void
@@ -556,33 +563,32 @@ flush_user_icache_range(unsigned long start, unsigned long end)
 void flush_cache_range(struct vm_area_struct *vma,
                unsigned long start, unsigned long end)
 {
+       unsigned long addr;
+       pgd_t *pgd;
+
        BUG_ON(!vma->vm_mm->context);
 
-       if ((end - start) < parisc_cache_flush_threshold) {
-               if (vma->vm_mm->context == mfsp(3)) {
-                       flush_user_dcache_range_asm(start, end);
-                       if (vma->vm_flags & VM_EXEC)
-                               flush_user_icache_range_asm(start, end);
-               } else {
-                       unsigned long addr;
-                       pgd_t *pgd = vma->vm_mm->pgd;
-
-                       for (addr = start & PAGE_MASK; addr < end;
-                            addr += PAGE_SIZE) {
-                               pte_t *ptep = get_ptep(pgd, addr);
-                               if (ptep != NULL) {
-                                       pte_t pte = *ptep;
-                                       flush_cache_page(vma,
-                                          addr, pte_pfn(pte));
-                               }
-                       }
-               }
-       } else {
-#ifdef CONFIG_SMP
+       if ((end - start) >= parisc_cache_flush_threshold) {
                flush_cache_all();
-#else
-               flush_cache_all_local();
-#endif
+               return;
+       }
+
+       if (vma->vm_mm->context == mfsp(3)) {
+               flush_user_dcache_range_asm(start, end);
+               if (vma->vm_flags & VM_EXEC)
+                       flush_user_icache_range_asm(start, end);
+               return;
+       }
+
+       pgd = vma->vm_mm->pgd;
+       for (addr = start & PAGE_MASK; addr < end; addr += PAGE_SIZE) {
+               unsigned long pfn;
+               pte_t *ptep = get_ptep(pgd, addr);
+               if (!ptep)
+                       continue;
+               pfn = pte_pfn(*ptep);
+               if (pfn_valid(pfn))
+                       __flush_cache_page(vma, addr, PFN_PHYS(pfn));
        }
 }
 
@@ -591,9 +597,10 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long
 {
        BUG_ON(!vma->vm_mm->context);
 
-       flush_tlb_page(vma, vmaddr);
-       __flush_cache_page(vma, vmaddr, page_to_phys(pfn_to_page(pfn)));
-
+       if (pfn_valid(pfn)) {
+               flush_tlb_page(vma, vmaddr);
+               __flush_cache_page(vma, vmaddr, PFN_PHYS(pfn));
+       }
 }
 
 #ifdef CONFIG_PARISC_TMPALIAS
index 3295ef4a185d06327c84b806276f31ac4c7cdaab..f0b6722fc706169b37a407a1fad6b063984722e8 100644 (file)
@@ -211,6 +211,7 @@ pat_query_module(ulong pcell_loc, ulong mod_index)
        /* REVISIT: who is the consumer of this? not sure yet... */
        dev->mod_info = pa_pdc_cell->mod_info;  /* pass to PAT_GET_ENTITY() */
        dev->pmod_loc = pa_pdc_cell->mod_location;
+       dev->mod0 = pa_pdc_cell->mod[0];
 
        register_parisc_device(dev);    /* advertise device */
 
index 940188d1942caeb993ffc58aa7148fea50c91683..07349b00268750581d1badb79b2c2487732831b8 100644 (file)
  * this. */
 #define A(__x) ((unsigned long)(__x))
 
-/*
- * Atomically swap in the new signal mask, and wait for a signal.
- */
-#ifdef CONFIG_64BIT
-#include "sys32.h"
-#endif
-
 /*
  * Do a signal return - restore sigcontext.
  */
index 33eca1b04926ad09184d703e9c2fcb55cd127069..6c6a271a6140e639183334a70a470860f906d7bf 100644 (file)
@@ -34,7 +34,6 @@
 #include <asm/uaccess.h>
 
 #include "signal32.h"
-#include "sys32.h"
 
 #define DEBUG_COMPAT_SIG 0 
 #define DEBUG_COMPAT_SIG_LEVEL 2
diff --git a/arch/parisc/kernel/sys32.h b/arch/parisc/kernel/sys32.h
deleted file mode 100644 (file)
index 60dd470..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/* 
- *    Copyright (C) 2002 Richard Hirst <rhirst at parisc-linux.org>
- *    Copyright (C) 2003 James Bottomley <jejb at parisc-linux.org>
- *    Copyright (C) 2003 Randolph Chung <tausq with parisc-linux.org>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-#ifndef _PARISC64_KERNEL_SYS32_H
-#define _PARISC64_KERNEL_SYS32_H
-
-#include <linux/compat.h>
-
-/* Call a kernel syscall which will use kernel space instead of user
- * space for its copy_to/from_user.
- */
-#define KERNEL_SYSCALL(ret, syscall, args...) \
-{ \
-    mm_segment_t old_fs = get_fs(); \
-    set_fs(KERNEL_DS); \
-    ret = syscall(args); \
-    set_fs (old_fs); \
-}
-
-#endif
index a134ff4da12ee1e4ad39a78e514328f578573ca3..bb9f3b64de55b2583f9fc930b6a1fa368237fd49 100644 (file)
@@ -42,8 +42,6 @@
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
 
-#include "sys32.h"
-
 #undef DEBUG
 
 #ifdef DEBUG
index 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..cc5f45b95b032ec0276105da29976dac66bd749c 100644 (file)
@@ -142,11 +142,11 @@ extern ssize_t power_events_sysfs_show(struct device *dev,
 #define        EVENT_PTR(_id, _suffix)         &EVENT_VAR(_id, _suffix).attr.attr
 
 #define        EVENT_ATTR(_name, _id, _suffix)                                 \
-       PMU_EVENT_ATTR(_name, EVENT_VAR(_id, _suffix), PME_PM_##_id,    \
+       PMU_EVENT_ATTR(_name, EVENT_VAR(_id, _suffix), PME_##_id,       \
                        power_events_sysfs_show)
 
 #define        GENERIC_EVENT_ATTR(_name, _id)  EVENT_ATTR(_name, _id, _g)
 #define        GENERIC_EVENT_PTR(_id)          EVENT_PTR(_id, _g)
 
-#define        POWER_EVENT_ATTR(_name, _id)    EVENT_ATTR(PM_##_name, _id, _p)
+#define        POWER_EVENT_ATTR(_name, _id)    EVENT_ATTR(_name, _id, _p)
 #define        POWER_EVENT_PTR(_id)            EVENT_PTR(_id, _p)
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 eb23ac92abb9089cea9ebc7fa19fd3a7e1404dbd..67d18dad43688d81d137225a03957c1b1e01a8d1 100644 (file)
@@ -550,8 +550,7 @@ void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
-void __init early_init_dt_setup_initrd_arch(unsigned long start,
-               unsigned long end)
+void __init early_init_dt_setup_initrd_arch(u64 start, u64 end)
 {
        initrd_start = (unsigned long)__va(start);
        initrd_end = (unsigned long)__va(end);
index 6316ee336e888e22636f557d1623c54b30d7a207..ae63ae4a1a5f713960561ee3507d319045b73c97 100644 (file)
@@ -420,6 +420,10 @@ int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages)
        return kvmppc_core_create_memslot(slot, npages);
 }
 
+void kvm_arch_memslots_updated(struct kvm *kvm)
+{
+}
+
 int kvm_arch_prepare_memory_region(struct kvm *kvm,
                                   struct kvm_memory_slot *memslot,
                                   struct kvm_userspace_memory_region *mem,
diff --git a/arch/powerpc/perf/power7-events-list.h b/arch/powerpc/perf/power7-events-list.h
new file mode 100644 (file)
index 0000000..687790a
--- /dev/null
@@ -0,0 +1,548 @@
+/*
+ * Performance counter support for POWER7 processors.
+ *
+ * Copyright 2013 Runzhen Wang, IBM 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 the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+EVENT(PM_IC_DEMAND_L2_BR_ALL,                 0x04898)
+EVENT(PM_GCT_UTIL_7_TO_10_SLOTS,              0x020a0)
+EVENT(PM_PMC2_SAVED,                          0x10022)
+EVENT(PM_CMPLU_STALL_DFU,                     0x2003c)
+EVENT(PM_VSU0_16FLOP,                         0x0a0a4)
+EVENT(PM_MRK_LSU_DERAT_MISS,                  0x3d05a)
+EVENT(PM_MRK_ST_CMPL,                         0x10034)
+EVENT(PM_NEST_PAIR3_ADD,                      0x40881)
+EVENT(PM_L2_ST_DISP,                          0x46180)
+EVENT(PM_L2_CASTOUT_MOD,                      0x16180)
+EVENT(PM_ISEG,                                0x020a4)
+EVENT(PM_MRK_INST_TIMEO,                      0x40034)
+EVENT(PM_L2_RCST_DISP_FAIL_ADDR,              0x36282)
+EVENT(PM_LSU1_DC_PREF_STREAM_CONFIRM,         0x0d0b6)
+EVENT(PM_IERAT_WR_64K,                        0x040be)
+EVENT(PM_MRK_DTLB_MISS_16M,                   0x4d05e)
+EVENT(PM_IERAT_MISS,                          0x100f6)
+EVENT(PM_MRK_PTEG_FROM_LMEM,                  0x4d052)
+EVENT(PM_FLOP,                                0x100f4)
+EVENT(PM_THRD_PRIO_4_5_CYC,                   0x040b4)
+EVENT(PM_BR_PRED_TA,                          0x040aa)
+EVENT(PM_CMPLU_STALL_FXU,                     0x20014)
+EVENT(PM_EXT_INT,                             0x200f8)
+EVENT(PM_VSU_FSQRT_FDIV,                      0x0a888)
+EVENT(PM_MRK_LD_MISS_EXPOSED_CYC,             0x1003e)
+EVENT(PM_LSU1_LDF,                            0x0c086)
+EVENT(PM_IC_WRITE_ALL,                        0x0488c)
+EVENT(PM_LSU0_SRQ_STFWD,                      0x0c0a0)
+EVENT(PM_PTEG_FROM_RL2L3_MOD,                 0x1c052)
+EVENT(PM_MRK_DATA_FROM_L31_SHR,               0x1d04e)
+EVENT(PM_DATA_FROM_L21_MOD,                   0x3c046)
+EVENT(PM_VSU1_SCAL_DOUBLE_ISSUED,             0x0b08a)
+EVENT(PM_VSU0_8FLOP,                          0x0a0a0)
+EVENT(PM_POWER_EVENT1,                        0x1006e)
+EVENT(PM_DISP_CLB_HELD_BAL,                   0x02092)
+EVENT(PM_VSU1_2FLOP,                          0x0a09a)
+EVENT(PM_LWSYNC_HELD,                         0x0209a)
+EVENT(PM_PTEG_FROM_DL2L3_SHR,                 0x3c054)
+EVENT(PM_INST_FROM_L21_MOD,                   0x34046)
+EVENT(PM_IERAT_XLATE_WR_16MPLUS,              0x040bc)
+EVENT(PM_IC_REQ_ALL,                          0x04888)
+EVENT(PM_DSLB_MISS,                           0x0d090)
+EVENT(PM_L3_MISS,                             0x1f082)
+EVENT(PM_LSU0_L1_PREF,                        0x0d0b8)
+EVENT(PM_VSU_SCALAR_SINGLE_ISSUED,            0x0b884)
+EVENT(PM_LSU1_DC_PREF_STREAM_CONFIRM_STRIDE,  0x0d0be)
+EVENT(PM_L2_INST,                             0x36080)
+EVENT(PM_VSU0_FRSP,                           0x0a0b4)
+EVENT(PM_FLUSH_DISP,                          0x02082)
+EVENT(PM_PTEG_FROM_L2MISS,                    0x4c058)
+EVENT(PM_VSU1_DQ_ISSUED,                      0x0b09a)
+EVENT(PM_CMPLU_STALL_LSU,                     0x20012)
+EVENT(PM_MRK_DATA_FROM_DMEM,                  0x1d04a)
+EVENT(PM_LSU_FLUSH_ULD,                       0x0c8b0)
+EVENT(PM_PTEG_FROM_LMEM,                      0x4c052)
+EVENT(PM_MRK_DERAT_MISS_16M,                  0x3d05c)
+EVENT(PM_THRD_ALL_RUN_CYC,                    0x2000c)
+EVENT(PM_MEM0_PREFETCH_DISP,                  0x20083)
+EVENT(PM_MRK_STALL_CMPLU_CYC_COUNT,           0x3003f)
+EVENT(PM_DATA_FROM_DL2L3_MOD,                 0x3c04c)
+EVENT(PM_VSU_FRSP,                            0x0a8b4)
+EVENT(PM_MRK_DATA_FROM_L21_MOD,               0x3d046)
+EVENT(PM_PMC1_OVERFLOW,                       0x20010)
+EVENT(PM_VSU0_SINGLE,                         0x0a0a8)
+EVENT(PM_MRK_PTEG_FROM_L3MISS,                0x2d058)
+EVENT(PM_MRK_PTEG_FROM_L31_SHR,               0x2d056)
+EVENT(PM_VSU0_VECTOR_SP_ISSUED,               0x0b090)
+EVENT(PM_VSU1_FEST,                           0x0a0ba)
+EVENT(PM_MRK_INST_DISP,                       0x20030)
+EVENT(PM_VSU0_COMPLEX_ISSUED,                 0x0b096)
+EVENT(PM_LSU1_FLUSH_UST,                      0x0c0b6)
+EVENT(PM_INST_CMPL,                           0x00002)
+EVENT(PM_FXU_IDLE,                            0x1000e)
+EVENT(PM_LSU0_FLUSH_ULD,                      0x0c0b0)
+EVENT(PM_MRK_DATA_FROM_DL2L3_MOD,             0x3d04c)
+EVENT(PM_LSU_LMQ_SRQ_EMPTY_ALL_CYC,           0x3001c)
+EVENT(PM_LSU1_REJECT_LMQ_FULL,                0x0c0a6)
+EVENT(PM_INST_PTEG_FROM_L21_MOD,              0x3e056)
+EVENT(PM_INST_FROM_RL2L3_MOD,                 0x14042)
+EVENT(PM_SHL_CREATED,                         0x05082)
+EVENT(PM_L2_ST_HIT,                           0x46182)
+EVENT(PM_DATA_FROM_DMEM,                      0x1c04a)
+EVENT(PM_L3_LD_MISS,                          0x2f082)
+EVENT(PM_FXU1_BUSY_FXU0_IDLE,                 0x4000e)
+EVENT(PM_DISP_CLB_HELD_RES,                   0x02094)
+EVENT(PM_L2_SN_SX_I_DONE,                     0x36382)
+EVENT(PM_GRP_CMPL,                            0x30004)
+EVENT(PM_STCX_CMPL,                           0x0c098)
+EVENT(PM_VSU0_2FLOP,                          0x0a098)
+EVENT(PM_L3_PREF_MISS,                        0x3f082)
+EVENT(PM_LSU_SRQ_SYNC_CYC,                    0x0d096)
+EVENT(PM_LSU_REJECT_ERAT_MISS,                0x20064)
+EVENT(PM_L1_ICACHE_MISS,                      0x200fc)
+EVENT(PM_LSU1_FLUSH_SRQ,                      0x0c0be)
+EVENT(PM_LD_REF_L1_LSU0,                      0x0c080)
+EVENT(PM_VSU0_FEST,                           0x0a0b8)
+EVENT(PM_VSU_VECTOR_SINGLE_ISSUED,            0x0b890)
+EVENT(PM_FREQ_UP,                             0x4000c)
+EVENT(PM_DATA_FROM_LMEM,                      0x3c04a)
+EVENT(PM_LSU1_LDX,                            0x0c08a)
+EVENT(PM_PMC3_OVERFLOW,                       0x40010)
+EVENT(PM_MRK_BR_MPRED,                        0x30036)
+EVENT(PM_SHL_MATCH,                           0x05086)
+EVENT(PM_MRK_BR_TAKEN,                        0x10036)
+EVENT(PM_CMPLU_STALL_BRU,                     0x4004e)
+EVENT(PM_ISLB_MISS,                           0x0d092)
+EVENT(PM_CYC,                                 0x0001e)
+EVENT(PM_DISP_HELD_THERMAL,                   0x30006)
+EVENT(PM_INST_PTEG_FROM_RL2L3_SHR,            0x2e054)
+EVENT(PM_LSU1_SRQ_STFWD,                      0x0c0a2)
+EVENT(PM_GCT_NOSLOT_BR_MPRED,                 0x4001a)
+EVENT(PM_1PLUS_PPC_CMPL,                      0x100f2)
+EVENT(PM_PTEG_FROM_DMEM,                      0x2c052)
+EVENT(PM_VSU_2FLOP,                           0x0a898)
+EVENT(PM_GCT_FULL_CYC,                        0x04086)
+EVENT(PM_MRK_DATA_FROM_L3_CYC,                0x40020)
+EVENT(PM_LSU_SRQ_S0_ALLOC,                    0x0d09d)
+EVENT(PM_MRK_DERAT_MISS_4K,                   0x1d05c)
+EVENT(PM_BR_MPRED_TA,                         0x040ae)
+EVENT(PM_INST_PTEG_FROM_L2MISS,               0x4e058)
+EVENT(PM_DPU_HELD_POWER,                      0x20006)
+EVENT(PM_RUN_INST_CMPL,                       0x400fa)
+EVENT(PM_MRK_VSU_FIN,                         0x30032)
+EVENT(PM_LSU_SRQ_S0_VALID,                    0x0d09c)
+EVENT(PM_GCT_EMPTY_CYC,                       0x20008)
+EVENT(PM_IOPS_DISP,                           0x30014)
+EVENT(PM_RUN_SPURR,                           0x10008)
+EVENT(PM_PTEG_FROM_L21_MOD,                   0x3c056)
+EVENT(PM_VSU0_1FLOP,                          0x0a080)
+EVENT(PM_SNOOP_TLBIE,                         0x0d0b2)
+EVENT(PM_DATA_FROM_L3MISS,                    0x2c048)
+EVENT(PM_VSU_SINGLE,                          0x0a8a8)
+EVENT(PM_DTLB_MISS_16G,                       0x1c05e)
+EVENT(PM_CMPLU_STALL_VECTOR,                  0x2001c)
+EVENT(PM_FLUSH,                               0x400f8)
+EVENT(PM_L2_LD_HIT,                           0x36182)
+EVENT(PM_NEST_PAIR2_AND,                      0x30883)
+EVENT(PM_VSU1_1FLOP,                          0x0a082)
+EVENT(PM_IC_PREF_REQ,                         0x0408a)
+EVENT(PM_L3_LD_HIT,                           0x2f080)
+EVENT(PM_GCT_NOSLOT_IC_MISS,                  0x2001a)
+EVENT(PM_DISP_HELD,                           0x10006)
+EVENT(PM_L2_LD,                               0x16080)
+EVENT(PM_LSU_FLUSH_SRQ,                       0x0c8bc)
+EVENT(PM_BC_PLUS_8_CONV,                      0x040b8)
+EVENT(PM_MRK_DATA_FROM_L31_MOD_CYC,           0x40026)
+EVENT(PM_CMPLU_STALL_VECTOR_LONG,             0x4004a)
+EVENT(PM_L2_RCST_BUSY_RC_FULL,                0x26282)
+EVENT(PM_TB_BIT_TRANS,                        0x300f8)
+EVENT(PM_THERMAL_MAX,                         0x40006)
+EVENT(PM_LSU1_FLUSH_ULD,                      0x0c0b2)
+EVENT(PM_LSU1_REJECT_LHS,                     0x0c0ae)
+EVENT(PM_LSU_LRQ_S0_ALLOC,                    0x0d09f)
+EVENT(PM_L3_CO_L31,                           0x4f080)
+EVENT(PM_POWER_EVENT4,                        0x4006e)
+EVENT(PM_DATA_FROM_L31_SHR,                   0x1c04e)
+EVENT(PM_BR_UNCOND,                           0x0409e)
+EVENT(PM_LSU1_DC_PREF_STREAM_ALLOC,           0x0d0aa)
+EVENT(PM_PMC4_REWIND,                         0x10020)
+EVENT(PM_L2_RCLD_DISP,                        0x16280)
+EVENT(PM_THRD_PRIO_2_3_CYC,                   0x040b2)
+EVENT(PM_MRK_PTEG_FROM_L2MISS,                0x4d058)
+EVENT(PM_IC_DEMAND_L2_BHT_REDIRECT,           0x04098)
+EVENT(PM_LSU_DERAT_MISS,                      0x200f6)
+EVENT(PM_IC_PREF_CANCEL_L2,                   0x04094)
+EVENT(PM_MRK_FIN_STALL_CYC_COUNT,             0x1003d)
+EVENT(PM_BR_PRED_CCACHE,                      0x040a0)
+EVENT(PM_GCT_UTIL_1_TO_2_SLOTS,               0x0209c)
+EVENT(PM_MRK_ST_CMPL_INT,                     0x30034)
+EVENT(PM_LSU_TWO_TABLEWALK_CYC,               0x0d0a6)
+EVENT(PM_MRK_DATA_FROM_L3MISS,                0x2d048)
+EVENT(PM_GCT_NOSLOT_CYC,                      0x100f8)
+EVENT(PM_LSU_SET_MPRED,                       0x0c0a8)
+EVENT(PM_FLUSH_DISP_TLBIE,                    0x0208a)
+EVENT(PM_VSU1_FCONV,                          0x0a0b2)
+EVENT(PM_DERAT_MISS_16G,                      0x4c05c)
+EVENT(PM_INST_FROM_LMEM,                      0x3404a)
+EVENT(PM_IC_DEMAND_L2_BR_REDIRECT,            0x0409a)
+EVENT(PM_CMPLU_STALL_SCALAR_LONG,             0x20018)
+EVENT(PM_INST_PTEG_FROM_L2,                   0x1e050)
+EVENT(PM_PTEG_FROM_L2,                        0x1c050)
+EVENT(PM_MRK_DATA_FROM_L21_SHR_CYC,           0x20024)
+EVENT(PM_MRK_DTLB_MISS_4K,                    0x2d05a)
+EVENT(PM_VSU0_FPSCR,                          0x0b09c)
+EVENT(PM_VSU1_VECT_DOUBLE_ISSUED,             0x0b082)
+EVENT(PM_MRK_PTEG_FROM_RL2L3_MOD,             0x1d052)
+EVENT(PM_MEM0_RQ_DISP,                        0x10083)
+EVENT(PM_L2_LD_MISS,                          0x26080)
+EVENT(PM_VMX_RESULT_SAT_1,                    0x0b0a0)
+EVENT(PM_L1_PREF,                             0x0d8b8)
+EVENT(PM_MRK_DATA_FROM_LMEM_CYC,              0x2002c)
+EVENT(PM_GRP_IC_MISS_NONSPEC,                 0x1000c)
+EVENT(PM_PB_NODE_PUMP,                        0x10081)
+EVENT(PM_SHL_MERGED,                          0x05084)
+EVENT(PM_NEST_PAIR1_ADD,                      0x20881)
+EVENT(PM_DATA_FROM_L3,                        0x1c048)
+EVENT(PM_LSU_FLUSH,                           0x0208e)
+EVENT(PM_LSU_SRQ_SYNC_COUNT,                  0x0d097)
+EVENT(PM_PMC2_OVERFLOW,                       0x30010)
+EVENT(PM_LSU_LDF,                             0x0c884)
+EVENT(PM_POWER_EVENT3,                        0x3006e)
+EVENT(PM_DISP_WT,                             0x30008)
+EVENT(PM_CMPLU_STALL_REJECT,                  0x40016)
+EVENT(PM_IC_BANK_CONFLICT,                    0x04082)
+EVENT(PM_BR_MPRED_CR_TA,                      0x048ae)
+EVENT(PM_L2_INST_MISS,                        0x36082)
+EVENT(PM_CMPLU_STALL_ERAT_MISS,               0x40018)
+EVENT(PM_NEST_PAIR2_ADD,                      0x30881)
+EVENT(PM_MRK_LSU_FLUSH,                       0x0d08c)
+EVENT(PM_L2_LDST,                             0x16880)
+EVENT(PM_INST_FROM_L31_SHR,                   0x1404e)
+EVENT(PM_VSU0_FIN,                            0x0a0bc)
+EVENT(PM_LARX_LSU,                            0x0c894)
+EVENT(PM_INST_FROM_RMEM,                      0x34042)
+EVENT(PM_DISP_CLB_HELD_TLBIE,                 0x02096)
+EVENT(PM_MRK_DATA_FROM_DMEM_CYC,              0x2002e)
+EVENT(PM_BR_PRED_CR,                          0x040a8)
+EVENT(PM_LSU_REJECT,                          0x10064)
+EVENT(PM_GCT_UTIL_3_TO_6_SLOTS,               0x0209e)
+EVENT(PM_CMPLU_STALL_END_GCT_NOSLOT,          0x10028)
+EVENT(PM_LSU0_REJECT_LMQ_FULL,                0x0c0a4)
+EVENT(PM_VSU_FEST,                            0x0a8b8)
+EVENT(PM_NEST_PAIR0_AND,                      0x10883)
+EVENT(PM_PTEG_FROM_L3,                        0x2c050)
+EVENT(PM_POWER_EVENT2,                        0x2006e)
+EVENT(PM_IC_PREF_CANCEL_PAGE,                 0x04090)
+EVENT(PM_VSU0_FSQRT_FDIV,                     0x0a088)
+EVENT(PM_MRK_GRP_CMPL,                        0x40030)
+EVENT(PM_VSU0_SCAL_DOUBLE_ISSUED,             0x0b088)
+EVENT(PM_GRP_DISP,                            0x3000a)
+EVENT(PM_LSU0_LDX,                            0x0c088)
+EVENT(PM_DATA_FROM_L2,                        0x1c040)
+EVENT(PM_MRK_DATA_FROM_RL2L3_MOD,             0x1d042)
+EVENT(PM_LD_REF_L1,                           0x0c880)
+EVENT(PM_VSU0_VECT_DOUBLE_ISSUED,             0x0b080)
+EVENT(PM_VSU1_2FLOP_DOUBLE,                   0x0a08e)
+EVENT(PM_THRD_PRIO_6_7_CYC,                   0x040b6)
+EVENT(PM_BC_PLUS_8_RSLV_TAKEN,                0x040ba)
+EVENT(PM_BR_MPRED_CR,                         0x040ac)
+EVENT(PM_L3_CO_MEM,                           0x4f082)
+EVENT(PM_LD_MISS_L1,                          0x400f0)
+EVENT(PM_DATA_FROM_RL2L3_MOD,                 0x1c042)
+EVENT(PM_LSU_SRQ_FULL_CYC,                    0x1001a)
+EVENT(PM_TABLEWALK_CYC,                       0x10026)
+EVENT(PM_MRK_PTEG_FROM_RMEM,                  0x3d052)
+EVENT(PM_LSU_SRQ_STFWD,                       0x0c8a0)
+EVENT(PM_INST_PTEG_FROM_RMEM,                 0x3e052)
+EVENT(PM_FXU0_FIN,                            0x10004)
+EVENT(PM_LSU1_L1_SW_PREF,                     0x0c09e)
+EVENT(PM_PTEG_FROM_L31_MOD,                   0x1c054)
+EVENT(PM_PMC5_OVERFLOW,                       0x10024)
+EVENT(PM_LD_REF_L1_LSU1,                      0x0c082)
+EVENT(PM_INST_PTEG_FROM_L21_SHR,              0x4e056)
+EVENT(PM_CMPLU_STALL_THRD,                    0x1001c)
+EVENT(PM_DATA_FROM_RMEM,                      0x3c042)
+EVENT(PM_VSU0_SCAL_SINGLE_ISSUED,             0x0b084)
+EVENT(PM_BR_MPRED_LSTACK,                     0x040a6)
+EVENT(PM_MRK_DATA_FROM_RL2L3_MOD_CYC,         0x40028)
+EVENT(PM_LSU0_FLUSH_UST,                      0x0c0b4)
+EVENT(PM_LSU_NCST,                            0x0c090)
+EVENT(PM_BR_TAKEN,                            0x20004)
+EVENT(PM_INST_PTEG_FROM_LMEM,                 0x4e052)
+EVENT(PM_GCT_NOSLOT_BR_MPRED_IC_MISS,         0x4001c)
+EVENT(PM_DTLB_MISS_4K,                        0x2c05a)
+EVENT(PM_PMC4_SAVED,                          0x30022)
+EVENT(PM_VSU1_PERMUTE_ISSUED,                 0x0b092)
+EVENT(PM_SLB_MISS,                            0x0d890)
+EVENT(PM_LSU1_FLUSH_LRQ,                      0x0c0ba)
+EVENT(PM_DTLB_MISS,                           0x300fc)
+EVENT(PM_VSU1_FRSP,                           0x0a0b6)
+EVENT(PM_VSU_VECTOR_DOUBLE_ISSUED,            0x0b880)
+EVENT(PM_L2_CASTOUT_SHR,                      0x16182)
+EVENT(PM_DATA_FROM_DL2L3_SHR,                 0x3c044)
+EVENT(PM_VSU1_STF,                            0x0b08e)
+EVENT(PM_ST_FIN,                              0x200f0)
+EVENT(PM_PTEG_FROM_L21_SHR,                   0x4c056)
+EVENT(PM_L2_LOC_GUESS_WRONG,                  0x26480)
+EVENT(PM_MRK_STCX_FAIL,                       0x0d08e)
+EVENT(PM_LSU0_REJECT_LHS,                     0x0c0ac)
+EVENT(PM_IC_PREF_CANCEL_HIT,                  0x04092)
+EVENT(PM_L3_PREF_BUSY,                        0x4f080)
+EVENT(PM_MRK_BRU_FIN,                         0x2003a)
+EVENT(PM_LSU1_NCLD,                           0x0c08e)
+EVENT(PM_INST_PTEG_FROM_L31_MOD,              0x1e054)
+EVENT(PM_LSU_NCLD,                            0x0c88c)
+EVENT(PM_LSU_LDX,                             0x0c888)
+EVENT(PM_L2_LOC_GUESS_CORRECT,                0x16480)
+EVENT(PM_THRESH_TIMEO,                        0x10038)
+EVENT(PM_L3_PREF_ST,                          0x0d0ae)
+EVENT(PM_DISP_CLB_HELD_SYNC,                  0x02098)
+EVENT(PM_VSU_SIMPLE_ISSUED,                   0x0b894)
+EVENT(PM_VSU1_SINGLE,                         0x0a0aa)
+EVENT(PM_DATA_TABLEWALK_CYC,                  0x3001a)
+EVENT(PM_L2_RC_ST_DONE,                       0x36380)
+EVENT(PM_MRK_PTEG_FROM_L21_MOD,               0x3d056)
+EVENT(PM_LARX_LSU1,                           0x0c096)
+EVENT(PM_MRK_DATA_FROM_RMEM,                  0x3d042)
+EVENT(PM_DISP_CLB_HELD,                       0x02090)
+EVENT(PM_DERAT_MISS_4K,                       0x1c05c)
+EVENT(PM_L2_RCLD_DISP_FAIL_ADDR,              0x16282)
+EVENT(PM_SEG_EXCEPTION,                       0x028a4)
+EVENT(PM_FLUSH_DISP_SB,                       0x0208c)
+EVENT(PM_L2_DC_INV,                           0x26182)
+EVENT(PM_PTEG_FROM_DL2L3_MOD,                 0x4c054)
+EVENT(PM_DSEG,                                0x020a6)
+EVENT(PM_BR_PRED_LSTACK,                      0x040a2)
+EVENT(PM_VSU0_STF,                            0x0b08c)
+EVENT(PM_LSU_FX_FIN,                          0x10066)
+EVENT(PM_DERAT_MISS_16M,                      0x3c05c)
+EVENT(PM_MRK_PTEG_FROM_DL2L3_MOD,             0x4d054)
+EVENT(PM_GCT_UTIL_11_PLUS_SLOTS,              0x020a2)
+EVENT(PM_INST_FROM_L3,                        0x14048)
+EVENT(PM_MRK_IFU_FIN,                         0x3003a)
+EVENT(PM_ITLB_MISS,                           0x400fc)
+EVENT(PM_VSU_STF,                             0x0b88c)
+EVENT(PM_LSU_FLUSH_UST,                       0x0c8b4)
+EVENT(PM_L2_LDST_MISS,                        0x26880)
+EVENT(PM_FXU1_FIN,                            0x40004)
+EVENT(PM_SHL_DEALLOCATED,                     0x05080)
+EVENT(PM_L2_SN_M_WR_DONE,                     0x46382)
+EVENT(PM_LSU_REJECT_SET_MPRED,                0x0c8a8)
+EVENT(PM_L3_PREF_LD,                          0x0d0ac)
+EVENT(PM_L2_SN_M_RD_DONE,                     0x46380)
+EVENT(PM_MRK_DERAT_MISS_16G,                  0x4d05c)
+EVENT(PM_VSU_FCONV,                           0x0a8b0)
+EVENT(PM_ANY_THRD_RUN_CYC,                    0x100fa)
+EVENT(PM_LSU_LMQ_FULL_CYC,                    0x0d0a4)
+EVENT(PM_MRK_LSU_REJECT_LHS,                  0x0d082)
+EVENT(PM_MRK_LD_MISS_L1_CYC,                  0x4003e)
+EVENT(PM_MRK_DATA_FROM_L2_CYC,                0x20020)
+EVENT(PM_INST_IMC_MATCH_DISP,                 0x30016)
+EVENT(PM_MRK_DATA_FROM_RMEM_CYC,              0x4002c)
+EVENT(PM_VSU0_SIMPLE_ISSUED,                  0x0b094)
+EVENT(PM_CMPLU_STALL_DIV,                     0x40014)
+EVENT(PM_MRK_PTEG_FROM_RL2L3_SHR,             0x2d054)
+EVENT(PM_VSU_FMA_DOUBLE,                      0x0a890)
+EVENT(PM_VSU_4FLOP,                           0x0a89c)
+EVENT(PM_VSU1_FIN,                            0x0a0be)
+EVENT(PM_NEST_PAIR1_AND,                      0x20883)
+EVENT(PM_INST_PTEG_FROM_RL2L3_MOD,            0x1e052)
+EVENT(PM_RUN_CYC,                             0x200f4)
+EVENT(PM_PTEG_FROM_RMEM,                      0x3c052)
+EVENT(PM_LSU_LRQ_S0_VALID,                    0x0d09e)
+EVENT(PM_LSU0_LDF,                            0x0c084)
+EVENT(PM_FLUSH_COMPLETION,                    0x30012)
+EVENT(PM_ST_MISS_L1,                          0x300f0)
+EVENT(PM_L2_NODE_PUMP,                        0x36480)
+EVENT(PM_INST_FROM_DL2L3_SHR,                 0x34044)
+EVENT(PM_MRK_STALL_CMPLU_CYC,                 0x3003e)
+EVENT(PM_VSU1_DENORM,                         0x0a0ae)
+EVENT(PM_MRK_DATA_FROM_L31_SHR_CYC,           0x20026)
+EVENT(PM_NEST_PAIR0_ADD,                      0x10881)
+EVENT(PM_INST_FROM_L3MISS,                    0x24048)
+EVENT(PM_EE_OFF_EXT_INT,                      0x02080)
+EVENT(PM_INST_PTEG_FROM_DMEM,                 0x2e052)
+EVENT(PM_INST_FROM_DL2L3_MOD,                 0x3404c)
+EVENT(PM_PMC6_OVERFLOW,                       0x30024)
+EVENT(PM_VSU_2FLOP_DOUBLE,                    0x0a88c)
+EVENT(PM_TLB_MISS,                            0x20066)
+EVENT(PM_FXU_BUSY,                            0x2000e)
+EVENT(PM_L2_RCLD_DISP_FAIL_OTHER,             0x26280)
+EVENT(PM_LSU_REJECT_LMQ_FULL,                 0x0c8a4)
+EVENT(PM_IC_RELOAD_SHR,                       0x04096)
+EVENT(PM_GRP_MRK,                             0x10031)
+EVENT(PM_MRK_ST_NEST,                         0x20034)
+EVENT(PM_VSU1_FSQRT_FDIV,                     0x0a08a)
+EVENT(PM_LSU0_FLUSH_LRQ,                      0x0c0b8)
+EVENT(PM_LARX_LSU0,                           0x0c094)
+EVENT(PM_IBUF_FULL_CYC,                       0x04084)
+EVENT(PM_MRK_DATA_FROM_DL2L3_SHR_CYC,         0x2002a)
+EVENT(PM_LSU_DC_PREF_STREAM_ALLOC,            0x0d8a8)
+EVENT(PM_GRP_MRK_CYC,                         0x10030)
+EVENT(PM_MRK_DATA_FROM_RL2L3_SHR_CYC,         0x20028)
+EVENT(PM_L2_GLOB_GUESS_CORRECT,               0x16482)
+EVENT(PM_LSU_REJECT_LHS,                      0x0c8ac)
+EVENT(PM_MRK_DATA_FROM_LMEM,                  0x3d04a)
+EVENT(PM_INST_PTEG_FROM_L3,                   0x2e050)
+EVENT(PM_FREQ_DOWN,                           0x3000c)
+EVENT(PM_PB_RETRY_NODE_PUMP,                  0x30081)
+EVENT(PM_INST_FROM_RL2L3_SHR,                 0x1404c)
+EVENT(PM_MRK_INST_ISSUED,                     0x10032)
+EVENT(PM_PTEG_FROM_L3MISS,                    0x2c058)
+EVENT(PM_RUN_PURR,                            0x400f4)
+EVENT(PM_MRK_GRP_IC_MISS,                     0x40038)
+EVENT(PM_MRK_DATA_FROM_L3,                    0x1d048)
+EVENT(PM_CMPLU_STALL_DCACHE_MISS,             0x20016)
+EVENT(PM_PTEG_FROM_RL2L3_SHR,                 0x2c054)
+EVENT(PM_LSU_FLUSH_LRQ,                       0x0c8b8)
+EVENT(PM_MRK_DERAT_MISS_64K,                  0x2d05c)
+EVENT(PM_INST_PTEG_FROM_DL2L3_MOD,            0x4e054)
+EVENT(PM_L2_ST_MISS,                          0x26082)
+EVENT(PM_MRK_PTEG_FROM_L21_SHR,               0x4d056)
+EVENT(PM_LWSYNC,                              0x0d094)
+EVENT(PM_LSU0_DC_PREF_STREAM_CONFIRM_STRIDE,  0x0d0bc)
+EVENT(PM_MRK_LSU_FLUSH_LRQ,                   0x0d088)
+EVENT(PM_INST_IMC_MATCH_CMPL,                 0x100f0)
+EVENT(PM_NEST_PAIR3_AND,                      0x40883)
+EVENT(PM_PB_RETRY_SYS_PUMP,                   0x40081)
+EVENT(PM_MRK_INST_FIN,                        0x30030)
+EVENT(PM_MRK_PTEG_FROM_DL2L3_SHR,             0x3d054)
+EVENT(PM_INST_FROM_L31_MOD,                   0x14044)
+EVENT(PM_MRK_DTLB_MISS_64K,                   0x3d05e)
+EVENT(PM_LSU_FIN,                             0x30066)
+EVENT(PM_MRK_LSU_REJECT,                      0x40064)
+EVENT(PM_L2_CO_FAIL_BUSY,                     0x16382)
+EVENT(PM_MEM0_WQ_DISP,                        0x40083)
+EVENT(PM_DATA_FROM_L31_MOD,                   0x1c044)
+EVENT(PM_THERMAL_WARN,                        0x10016)
+EVENT(PM_VSU0_4FLOP,                          0x0a09c)
+EVENT(PM_BR_MPRED_CCACHE,                     0x040a4)
+EVENT(PM_CMPLU_STALL_IFU,                     0x4004c)
+EVENT(PM_L1_DEMAND_WRITE,                     0x0408c)
+EVENT(PM_FLUSH_BR_MPRED,                      0x02084)
+EVENT(PM_MRK_DTLB_MISS_16G,                   0x1d05e)
+EVENT(PM_MRK_PTEG_FROM_DMEM,                  0x2d052)
+EVENT(PM_L2_RCST_DISP,                        0x36280)
+EVENT(PM_CMPLU_STALL,                         0x4000a)
+EVENT(PM_LSU_PARTIAL_CDF,                     0x0c0aa)
+EVENT(PM_DISP_CLB_HELD_SB,                    0x020a8)
+EVENT(PM_VSU0_FMA_DOUBLE,                     0x0a090)
+EVENT(PM_FXU0_BUSY_FXU1_IDLE,                 0x3000e)
+EVENT(PM_IC_DEMAND_CYC,                       0x10018)
+EVENT(PM_MRK_DATA_FROM_L21_SHR,               0x3d04e)
+EVENT(PM_MRK_LSU_FLUSH_UST,                   0x0d086)
+EVENT(PM_INST_PTEG_FROM_L3MISS,               0x2e058)
+EVENT(PM_VSU_DENORM,                          0x0a8ac)
+EVENT(PM_MRK_LSU_PARTIAL_CDF,                 0x0d080)
+EVENT(PM_INST_FROM_L21_SHR,                   0x3404e)
+EVENT(PM_IC_PREF_WRITE,                       0x0408e)
+EVENT(PM_BR_PRED,                             0x0409c)
+EVENT(PM_INST_FROM_DMEM,                      0x1404a)
+EVENT(PM_IC_PREF_CANCEL_ALL,                  0x04890)
+EVENT(PM_LSU_DC_PREF_STREAM_CONFIRM,          0x0d8b4)
+EVENT(PM_MRK_LSU_FLUSH_SRQ,                   0x0d08a)
+EVENT(PM_MRK_FIN_STALL_CYC,                   0x1003c)
+EVENT(PM_L2_RCST_DISP_FAIL_OTHER,             0x46280)
+EVENT(PM_VSU1_DD_ISSUED,                      0x0b098)
+EVENT(PM_PTEG_FROM_L31_SHR,                   0x2c056)
+EVENT(PM_DATA_FROM_L21_SHR,                   0x3c04e)
+EVENT(PM_LSU0_NCLD,                           0x0c08c)
+EVENT(PM_VSU1_4FLOP,                          0x0a09e)
+EVENT(PM_VSU1_8FLOP,                          0x0a0a2)
+EVENT(PM_VSU_8FLOP,                           0x0a8a0)
+EVENT(PM_LSU_LMQ_SRQ_EMPTY_CYC,               0x2003e)
+EVENT(PM_DTLB_MISS_64K,                       0x3c05e)
+EVENT(PM_THRD_CONC_RUN_INST,                  0x300f4)
+EVENT(PM_MRK_PTEG_FROM_L2,                    0x1d050)
+EVENT(PM_PB_SYS_PUMP,                         0x20081)
+EVENT(PM_VSU_FIN,                             0x0a8bc)
+EVENT(PM_MRK_DATA_FROM_L31_MOD,               0x1d044)
+EVENT(PM_THRD_PRIO_0_1_CYC,                   0x040b0)
+EVENT(PM_DERAT_MISS_64K,                      0x2c05c)
+EVENT(PM_PMC2_REWIND,                         0x30020)
+EVENT(PM_INST_FROM_L2,                        0x14040)
+EVENT(PM_GRP_BR_MPRED_NONSPEC,                0x1000a)
+EVENT(PM_INST_DISP,                           0x200f2)
+EVENT(PM_MEM0_RD_CANCEL_TOTAL,                0x30083)
+EVENT(PM_LSU0_DC_PREF_STREAM_CONFIRM,         0x0d0b4)
+EVENT(PM_L1_DCACHE_RELOAD_VALID,              0x300f6)
+EVENT(PM_VSU_SCALAR_DOUBLE_ISSUED,            0x0b888)
+EVENT(PM_L3_PREF_HIT,                         0x3f080)
+EVENT(PM_MRK_PTEG_FROM_L31_MOD,               0x1d054)
+EVENT(PM_CMPLU_STALL_STORE,                   0x2004a)
+EVENT(PM_MRK_FXU_FIN,                         0x20038)
+EVENT(PM_PMC4_OVERFLOW,                       0x10010)
+EVENT(PM_MRK_PTEG_FROM_L3,                    0x2d050)
+EVENT(PM_LSU0_LMQ_LHR_MERGE,                  0x0d098)
+EVENT(PM_BTAC_HIT,                            0x0508a)
+EVENT(PM_L3_RD_BUSY,                          0x4f082)
+EVENT(PM_LSU0_L1_SW_PREF,                     0x0c09c)
+EVENT(PM_INST_FROM_L2MISS,                    0x44048)
+EVENT(PM_LSU0_DC_PREF_STREAM_ALLOC,           0x0d0a8)
+EVENT(PM_L2_ST,                               0x16082)
+EVENT(PM_VSU0_DENORM,                         0x0a0ac)
+EVENT(PM_MRK_DATA_FROM_DL2L3_SHR,             0x3d044)
+EVENT(PM_BR_PRED_CR_TA,                       0x048aa)
+EVENT(PM_VSU0_FCONV,                          0x0a0b0)
+EVENT(PM_MRK_LSU_FLUSH_ULD,                   0x0d084)
+EVENT(PM_BTAC_MISS,                           0x05088)
+EVENT(PM_MRK_LD_MISS_EXPOSED_CYC_COUNT,       0x1003f)
+EVENT(PM_MRK_DATA_FROM_L2,                    0x1d040)
+EVENT(PM_LSU_DCACHE_RELOAD_VALID,             0x0d0a2)
+EVENT(PM_VSU_FMA,                             0x0a884)
+EVENT(PM_LSU0_FLUSH_SRQ,                      0x0c0bc)
+EVENT(PM_LSU1_L1_PREF,                        0x0d0ba)
+EVENT(PM_IOPS_CMPL,                           0x10014)
+EVENT(PM_L2_SYS_PUMP,                         0x36482)
+EVENT(PM_L2_RCLD_BUSY_RC_FULL,                0x46282)
+EVENT(PM_LSU_LMQ_S0_ALLOC,                    0x0d0a1)
+EVENT(PM_FLUSH_DISP_SYNC,                     0x02088)
+EVENT(PM_MRK_DATA_FROM_DL2L3_MOD_CYC,         0x4002a)
+EVENT(PM_L2_IC_INV,                           0x26180)
+EVENT(PM_MRK_DATA_FROM_L21_MOD_CYC,           0x40024)
+EVENT(PM_L3_PREF_LDST,                        0x0d8ac)
+EVENT(PM_LSU_SRQ_EMPTY_CYC,                   0x40008)
+EVENT(PM_LSU_LMQ_S0_VALID,                    0x0d0a0)
+EVENT(PM_FLUSH_PARTIAL,                       0x02086)
+EVENT(PM_VSU1_FMA_DOUBLE,                     0x0a092)
+EVENT(PM_1PLUS_PPC_DISP,                      0x400f2)
+EVENT(PM_DATA_FROM_L2MISS,                    0x200fe)
+EVENT(PM_SUSPENDED,                           0x00000)
+EVENT(PM_VSU0_FMA,                            0x0a084)
+EVENT(PM_CMPLU_STALL_SCALAR,                  0x40012)
+EVENT(PM_STCX_FAIL,                           0x0c09a)
+EVENT(PM_VSU0_FSQRT_FDIV_DOUBLE,              0x0a094)
+EVENT(PM_DC_PREF_DST,                         0x0d0b0)
+EVENT(PM_VSU1_SCAL_SINGLE_ISSUED,             0x0b086)
+EVENT(PM_L3_HIT,                              0x1f080)
+EVENT(PM_L2_GLOB_GUESS_WRONG,                 0x26482)
+EVENT(PM_MRK_DFU_FIN,                         0x20032)
+EVENT(PM_INST_FROM_L1,                        0x04080)
+EVENT(PM_BRU_FIN,                             0x10068)
+EVENT(PM_IC_DEMAND_REQ,                       0x04088)
+EVENT(PM_VSU1_FSQRT_FDIV_DOUBLE,              0x0a096)
+EVENT(PM_VSU1_FMA,                            0x0a086)
+EVENT(PM_MRK_LD_MISS_L1,                      0x20036)
+EVENT(PM_VSU0_2FLOP_DOUBLE,                   0x0a08c)
+EVENT(PM_LSU_DC_PREF_STRIDED_STREAM_CONFIRM,  0x0d8bc)
+EVENT(PM_INST_PTEG_FROM_L31_SHR,              0x2e056)
+EVENT(PM_MRK_LSU_REJECT_ERAT_MISS,            0x30064)
+EVENT(PM_MRK_DATA_FROM_L2MISS,                0x4d048)
+EVENT(PM_DATA_FROM_RL2L3_SHR,                 0x1c04c)
+EVENT(PM_INST_FROM_PREF,                      0x14046)
+EVENT(PM_VSU1_SQ,                             0x0b09e)
+EVENT(PM_L2_LD_DISP,                          0x36180)
+EVENT(PM_L2_DISP_ALL,                         0x46080)
+EVENT(PM_THRD_GRP_CMPL_BOTH_CYC,              0x10012)
+EVENT(PM_VSU_FSQRT_FDIV_DOUBLE,               0x0a894)
+EVENT(PM_BR_MPRED,                            0x400f6)
+EVENT(PM_INST_PTEG_FROM_DL2L3_SHR,            0x3e054)
+EVENT(PM_VSU_1FLOP,                           0x0a880)
+EVENT(PM_HV_CYC,                              0x2000a)
+EVENT(PM_MRK_LSU_FIN,                         0x40032)
+EVENT(PM_MRK_DATA_FROM_RL2L3_SHR,             0x1d04c)
+EVENT(PM_DTLB_MISS_16M,                       0x4c05e)
+EVENT(PM_LSU1_LMQ_LHR_MERGE,                  0x0d09a)
+EVENT(PM_IFU_FIN,                             0x40066)
index d1821b8bbc4c778024b9fbe424a0740671ca3c9d..56c67bca2f7558435110451b1e7659a20f84ef72 100644 (file)
 /*
  * Power7 event codes.
  */
-#define        PME_PM_CYC                      0x1e
-#define        PME_PM_GCT_NOSLOT_CYC           0x100f8
-#define        PME_PM_CMPLU_STALL              0x4000a
-#define        PME_PM_INST_CMPL                0x2
-#define        PME_PM_LD_REF_L1                0xc880
-#define        PME_PM_LD_MISS_L1               0x400f0
-#define        PME_PM_BRU_FIN                  0x10068
-#define        PME_PM_BR_MPRED                 0x400f6
-
-#define PME_PM_CMPLU_STALL_FXU                 0x20014
-#define PME_PM_CMPLU_STALL_DIV                 0x40014
-#define PME_PM_CMPLU_STALL_SCALAR              0x40012
-#define PME_PM_CMPLU_STALL_SCALAR_LONG         0x20018
-#define PME_PM_CMPLU_STALL_VECTOR              0x2001c
-#define PME_PM_CMPLU_STALL_VECTOR_LONG         0x4004a
-#define PME_PM_CMPLU_STALL_LSU                 0x20012
-#define PME_PM_CMPLU_STALL_REJECT              0x40016
-#define PME_PM_CMPLU_STALL_ERAT_MISS           0x40018
-#define PME_PM_CMPLU_STALL_DCACHE_MISS         0x20016
-#define PME_PM_CMPLU_STALL_STORE               0x2004a
-#define PME_PM_CMPLU_STALL_THRD                        0x1001c
-#define PME_PM_CMPLU_STALL_IFU                 0x4004c
-#define PME_PM_CMPLU_STALL_BRU                 0x4004e
-#define PME_PM_GCT_NOSLOT_IC_MISS              0x2001a
-#define PME_PM_GCT_NOSLOT_BR_MPRED             0x4001a
-#define PME_PM_GCT_NOSLOT_BR_MPRED_IC_MISS     0x4001c
-#define PME_PM_GRP_CMPL                                0x30004
-#define PME_PM_1PLUS_PPC_CMPL                  0x100f2
-#define PME_PM_CMPLU_STALL_DFU                 0x2003c
-#define PME_PM_RUN_CYC                         0x200f4
-#define PME_PM_RUN_INST_CMPL                   0x400fa
+#define EVENT(_name, _code) \
+       PME_##_name = _code,
+
+enum {
+#include "power7-events-list.h"
+};
+#undef EVENT
 
 /*
  * Layout of constraint bits:
@@ -398,96 +374,36 @@ static int power7_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
 };
 
 
-GENERIC_EVENT_ATTR(cpu-cycles,                 CYC);
-GENERIC_EVENT_ATTR(stalled-cycles-frontend,    GCT_NOSLOT_CYC);
-GENERIC_EVENT_ATTR(stalled-cycles-backend,     CMPLU_STALL);
-GENERIC_EVENT_ATTR(instructions,               INST_CMPL);
-GENERIC_EVENT_ATTR(cache-references,           LD_REF_L1);
-GENERIC_EVENT_ATTR(cache-misses,               LD_MISS_L1);
-GENERIC_EVENT_ATTR(branch-instructions,                BRU_FIN);
-GENERIC_EVENT_ATTR(branch-misses,              BR_MPRED);
-
-POWER_EVENT_ATTR(CYC,                          CYC);
-POWER_EVENT_ATTR(GCT_NOSLOT_CYC,               GCT_NOSLOT_CYC);
-POWER_EVENT_ATTR(CMPLU_STALL,                  CMPLU_STALL);
-POWER_EVENT_ATTR(INST_CMPL,                    INST_CMPL);
-POWER_EVENT_ATTR(LD_REF_L1,                    LD_REF_L1);
-POWER_EVENT_ATTR(LD_MISS_L1,                   LD_MISS_L1);
-POWER_EVENT_ATTR(BRU_FIN,                      BRU_FIN)
-POWER_EVENT_ATTR(BR_MPRED,                     BR_MPRED);
-
-POWER_EVENT_ATTR(CMPLU_STALL_FXU,              CMPLU_STALL_FXU);
-POWER_EVENT_ATTR(CMPLU_STALL_DIV,              CMPLU_STALL_DIV);
-POWER_EVENT_ATTR(CMPLU_STALL_SCALAR,           CMPLU_STALL_SCALAR);
-POWER_EVENT_ATTR(CMPLU_STALL_SCALAR_LONG,      CMPLU_STALL_SCALAR_LONG);
-POWER_EVENT_ATTR(CMPLU_STALL_VECTOR,           CMPLU_STALL_VECTOR);
-POWER_EVENT_ATTR(CMPLU_STALL_VECTOR_LONG,      CMPLU_STALL_VECTOR_LONG);
-POWER_EVENT_ATTR(CMPLU_STALL_LSU,              CMPLU_STALL_LSU);
-POWER_EVENT_ATTR(CMPLU_STALL_REJECT,           CMPLU_STALL_REJECT);
-
-POWER_EVENT_ATTR(CMPLU_STALL_ERAT_MISS,                CMPLU_STALL_ERAT_MISS);
-POWER_EVENT_ATTR(CMPLU_STALL_DCACHE_MISS,      CMPLU_STALL_DCACHE_MISS);
-POWER_EVENT_ATTR(CMPLU_STALL_STORE,            CMPLU_STALL_STORE);
-POWER_EVENT_ATTR(CMPLU_STALL_THRD,             CMPLU_STALL_THRD);
-POWER_EVENT_ATTR(CMPLU_STALL_IFU,              CMPLU_STALL_IFU);
-POWER_EVENT_ATTR(CMPLU_STALL_BRU,              CMPLU_STALL_BRU);
-POWER_EVENT_ATTR(GCT_NOSLOT_IC_MISS,           GCT_NOSLOT_IC_MISS);
-
-POWER_EVENT_ATTR(GCT_NOSLOT_BR_MPRED,          GCT_NOSLOT_BR_MPRED);
-POWER_EVENT_ATTR(GCT_NOSLOT_BR_MPRED_IC_MISS,  GCT_NOSLOT_BR_MPRED_IC_MISS);
-POWER_EVENT_ATTR(GRP_CMPL,                     GRP_CMPL);
-POWER_EVENT_ATTR(1PLUS_PPC_CMPL,               1PLUS_PPC_CMPL);
-POWER_EVENT_ATTR(CMPLU_STALL_DFU,              CMPLU_STALL_DFU);
-POWER_EVENT_ATTR(RUN_CYC,                      RUN_CYC);
-POWER_EVENT_ATTR(RUN_INST_CMPL,                        RUN_INST_CMPL);
+GENERIC_EVENT_ATTR(cpu-cycles,                 PM_CYC);
+GENERIC_EVENT_ATTR(stalled-cycles-frontend,    PM_GCT_NOSLOT_CYC);
+GENERIC_EVENT_ATTR(stalled-cycles-backend,     PM_CMPLU_STALL);
+GENERIC_EVENT_ATTR(instructions,               PM_INST_CMPL);
+GENERIC_EVENT_ATTR(cache-references,           PM_LD_REF_L1);
+GENERIC_EVENT_ATTR(cache-misses,               PM_LD_MISS_L1);
+GENERIC_EVENT_ATTR(branch-instructions,                PM_BRU_FIN);
+GENERIC_EVENT_ATTR(branch-misses,              PM_BR_MPRED);
+
+#define EVENT(_name, _code)     POWER_EVENT_ATTR(_name, _name);
+#include "power7-events-list.h"
+#undef EVENT
+
+#define EVENT(_name, _code)     POWER_EVENT_PTR(_name),
 
 static struct attribute *power7_events_attr[] = {
-       GENERIC_EVENT_PTR(CYC),
-       GENERIC_EVENT_PTR(GCT_NOSLOT_CYC),
-       GENERIC_EVENT_PTR(CMPLU_STALL),
-       GENERIC_EVENT_PTR(INST_CMPL),
-       GENERIC_EVENT_PTR(LD_REF_L1),
-       GENERIC_EVENT_PTR(LD_MISS_L1),
-       GENERIC_EVENT_PTR(BRU_FIN),
-       GENERIC_EVENT_PTR(BR_MPRED),
-
-       POWER_EVENT_PTR(CYC),
-       POWER_EVENT_PTR(GCT_NOSLOT_CYC),
-       POWER_EVENT_PTR(CMPLU_STALL),
-       POWER_EVENT_PTR(INST_CMPL),
-       POWER_EVENT_PTR(LD_REF_L1),
-       POWER_EVENT_PTR(LD_MISS_L1),
-       POWER_EVENT_PTR(BRU_FIN),
-       POWER_EVENT_PTR(BR_MPRED),
-
-       POWER_EVENT_PTR(CMPLU_STALL_FXU),
-       POWER_EVENT_PTR(CMPLU_STALL_DIV),
-       POWER_EVENT_PTR(CMPLU_STALL_SCALAR),
-       POWER_EVENT_PTR(CMPLU_STALL_SCALAR_LONG),
-       POWER_EVENT_PTR(CMPLU_STALL_VECTOR),
-       POWER_EVENT_PTR(CMPLU_STALL_VECTOR_LONG),
-       POWER_EVENT_PTR(CMPLU_STALL_LSU),
-       POWER_EVENT_PTR(CMPLU_STALL_REJECT),
-
-       POWER_EVENT_PTR(CMPLU_STALL_ERAT_MISS),
-       POWER_EVENT_PTR(CMPLU_STALL_DCACHE_MISS),
-       POWER_EVENT_PTR(CMPLU_STALL_STORE),
-       POWER_EVENT_PTR(CMPLU_STALL_THRD),
-       POWER_EVENT_PTR(CMPLU_STALL_IFU),
-       POWER_EVENT_PTR(CMPLU_STALL_BRU),
-       POWER_EVENT_PTR(GCT_NOSLOT_IC_MISS),
-       POWER_EVENT_PTR(GCT_NOSLOT_BR_MPRED),
-
-       POWER_EVENT_PTR(GCT_NOSLOT_BR_MPRED_IC_MISS),
-       POWER_EVENT_PTR(GRP_CMPL),
-       POWER_EVENT_PTR(1PLUS_PPC_CMPL),
-       POWER_EVENT_PTR(CMPLU_STALL_DFU),
-       POWER_EVENT_PTR(RUN_CYC),
-       POWER_EVENT_PTR(RUN_INST_CMPL),
+       GENERIC_EVENT_PTR(PM_CYC),
+       GENERIC_EVENT_PTR(PM_GCT_NOSLOT_CYC),
+       GENERIC_EVENT_PTR(PM_CMPLU_STALL),
+       GENERIC_EVENT_PTR(PM_INST_CMPL),
+       GENERIC_EVENT_PTR(PM_LD_REF_L1),
+       GENERIC_EVENT_PTR(PM_LD_MISS_L1),
+       GENERIC_EVENT_PTR(PM_BRU_FIN),
+       GENERIC_EVENT_PTR(PM_BR_MPRED),
+
+       #include "power7-events-list.h"
+       #undef EVENT
        NULL
 };
 
-
 static struct attribute_group power7_pmu_events_group = {
        .name = "events",
        .attrs = power7_events_attr,
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 3238d4004e8436aa1a7d1e5eb3d811fe065d0dcb..e87ecaa2c569860f0c9353fc3ed398a0eba034ad 100644 (file)
@@ -274,6 +274,14 @@ struct kvm_arch{
        int css_support;
 };
 
+#define KVM_HVA_ERR_BAD                (-1UL)
+#define KVM_HVA_ERR_RO_BAD     (-2UL)
+
+static inline bool kvm_is_error_hva(unsigned long addr)
+{
+       return IS_ERR_VALUE(addr);
+}
+
 extern int sie64a(struct kvm_s390_sie_block *, u64 *);
 extern char sie_exit;
 #endif
index 6340178748bf470bcb724eaa1e7feb066e261884..ff132ac64ddd0609f16c22021732c00355318bb3 100644 (file)
@@ -12,8 +12,6 @@ typedef struct {
        unsigned long asce_bits;
        unsigned long asce_limit;
        unsigned long vdso_base;
-       /* Cloned contexts will be created with extended page tables. */
-       unsigned int alloc_pgste:1;
        /* The mmu context has extended page tables. */
        unsigned int has_pgste:1;
 } mm_context_t;
index 084e7755ed9b7958f3f9cb9db9c02e8a4a8004b2..4fb67a0e4ddf263c5b156759247f98249e913536 100644 (file)
@@ -21,24 +21,7 @@ static inline int init_new_context(struct task_struct *tsk,
 #ifdef CONFIG_64BIT
        mm->context.asce_bits |= _ASCE_TYPE_REGION3;
 #endif
-       if (current->mm && current->mm->context.alloc_pgste) {
-               /*
-                * alloc_pgste indicates, that any NEW context will be created
-                * with extended page tables. The old context is unchanged. The
-                * page table allocation and the page table operations will
-                * look at has_pgste to distinguish normal and extended page
-                * tables. The only way to create extended page tables is to
-                * set alloc_pgste and then create a new context (e.g. dup_mm).
-                * The page table allocation is called after init_new_context
-                * and if has_pgste is set, it will create extended page
-                * tables.
-                */
-               mm->context.has_pgste = 1;
-               mm->context.alloc_pgste = 1;
-       } else {
-               mm->context.has_pgste = 0;
-               mm->context.alloc_pgste = 0;
-       }
+       mm->context.has_pgste = 0;
        mm->context.asce_limit = STACK_TOP_MAX;
        crst_table_init((unsigned long *) mm->pgd, pgd_entry_type(mm));
        return 0;
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..a54aafa3599677db58195fa671fe7f47866ab480 100644 (file)
@@ -217,63 +217,49 @@ 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    */
 
 /* 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.
  *
- *                     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
+ * The following table gives the different possible bit combinations for
+ * the pte hardware and software bits in the last 12 bits of a pte:
  *
- * 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.
+ *                     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_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 +273,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 +310,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 +319,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 +332,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 +373,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 +388,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 +454,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 +465,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 +481,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 +499,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 +508,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 +527,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 +547,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 +555,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 +618,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 +688,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 +716,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 +834,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 +873,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 +889,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 +950,6 @@ 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);
        return pte;
 }
 #endif
@@ -1076,7 +1068,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 +1109,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 +1131,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 +1155,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 +1239,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 +1302,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 +1313,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,13 +1356,24 @@ 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 */
 
+static inline void pmdp_flush_lazy(struct mm_struct *mm,
+                                  unsigned long address, pmd_t *pmdp)
+{
+       int active = (mm == current->active_mm) ? 1 : 0;
+
+       if ((atomic_read(&mm->context.attach_count) & 0xffff) > active)
+               __pmd_idte(address, pmdp);
+       else
+               mm->context.flush_mm = 1;
+}
+
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
 
 #define __HAVE_ARCH_PGTABLE_DEPOSIT
@@ -1378,7 +1391,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 +1404,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 +1560,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 +1583,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__ */
 
index b0e6435b2f02195e60303a9c46f0c199220c5225..0eb37505cab11c71f083ed508f02c98a72127e95 100644 (file)
@@ -43,6 +43,7 @@ extern void execve_tail(void);
 #ifndef CONFIG_64BIT
 
 #define TASK_SIZE              (1UL << 31)
+#define TASK_MAX_SIZE          (1UL << 31)
 #define TASK_UNMAPPED_BASE     (1UL << 30)
 
 #else /* CONFIG_64BIT */
@@ -51,6 +52,7 @@ extern void execve_tail(void);
 #define TASK_UNMAPPED_BASE     (test_thread_flag(TIF_31BIT) ? \
                                        (1UL << 30) : (1UL << 41))
 #define TASK_SIZE              TASK_SIZE_OF(current)
+#define TASK_MAX_SIZE          (1UL << 53)
 
 #endif /* CONFIG_64BIT */
 
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 3074475c8ae062dbfa7c285b7217fbf2f2c87241..3a74d8af0d69dd2e3bac77a427a6bfd64723bae9 100644 (file)
@@ -119,12 +119,21 @@ static int __diag_virtio_hypercall(struct kvm_vcpu *vcpu)
         * The layout is as follows:
         * - gpr 2 contains the subchannel id (passed as addr)
         * - gpr 3 contains the virtqueue index (passed as datamatch)
+        * - gpr 4 contains the index on the bus (optionally)
         */
-       ret = kvm_io_bus_write(vcpu->kvm, KVM_VIRTIO_CCW_NOTIFY_BUS,
-                               vcpu->run->s.regs.gprs[2],
-                               8, &vcpu->run->s.regs.gprs[3]);
+       ret = kvm_io_bus_write_cookie(vcpu->kvm, KVM_VIRTIO_CCW_NOTIFY_BUS,
+                                     vcpu->run->s.regs.gprs[2],
+                                     8, &vcpu->run->s.regs.gprs[3],
+                                     vcpu->run->s.regs.gprs[4]);
        srcu_read_unlock(&vcpu->kvm->srcu, idx);
-       /* kvm_io_bus_write returns -EOPNOTSUPP if it found no match. */
+
+       /*
+        * Return cookie in gpr 2, but don't overwrite the register if the
+        * diagnose will be handled by userspace.
+        */
+       if (ret != -EOPNOTSUPP)
+               vcpu->run->s.regs.gprs[2] = ret;
+       /* kvm_io_bus_write_cookie returns -EOPNOTSUPP if it found no match. */
        return ret < 0 ? ret : 0;
 }
 
index ba694d2ba51e36a2933ad722db76b00e09735f37..ac8e6670c551ccc7dc73cebb61c4dbe84b4cbac8 100644 (file)
@@ -28,6 +28,7 @@
 #include <asm/pgtable.h>
 #include <asm/nmi.h>
 #include <asm/switch_to.h>
+#include <asm/facility.h>
 #include <asm/sclp.h>
 #include "kvm-s390.h"
 #include "gaccess.h"
@@ -84,9 +85,15 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
        { NULL }
 };
 
-static unsigned long long *facilities;
+unsigned long *vfacilities;
 static struct gmap_notifier gmap_notifier;
 
+/* test availability of vfacility */
+static inline int test_vfacility(unsigned long nr)
+{
+       return __test_facility(nr, (void *) vfacilities);
+}
+
 /* Section: not file related */
 int kvm_arch_hardware_enable(void *garbage)
 {
@@ -387,7 +394,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
        vcpu->arch.sie_block->ecb   = 6;
        vcpu->arch.sie_block->ecb2  = 8;
        vcpu->arch.sie_block->eca   = 0xC1002001U;
-       vcpu->arch.sie_block->fac   = (int) (long) facilities;
+       vcpu->arch.sie_block->fac   = (int) (long) vfacilities;
        hrtimer_init(&vcpu->arch.ckc_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
        tasklet_init(&vcpu->arch.tasklet, kvm_s390_tasklet,
                     (unsigned long) vcpu);
@@ -1056,6 +1063,10 @@ int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages)
        return 0;
 }
 
+void kvm_arch_memslots_updated(struct kvm *kvm)
+{
+}
+
 /* Section: memory related */
 int kvm_arch_prepare_memory_region(struct kvm *kvm,
                                   struct kvm_memory_slot *memslot,
@@ -1122,20 +1133,20 @@ static int __init kvm_s390_init(void)
         * to hold the maximum amount of facilities. On the other hand, we
         * only set facilities that are known to work in KVM.
         */
-       facilities = (unsigned long long *) get_zeroed_page(GFP_KERNEL|GFP_DMA);
-       if (!facilities) {
+       vfacilities = (unsigned long *) get_zeroed_page(GFP_KERNEL|GFP_DMA);
+       if (!vfacilities) {
                kvm_exit();
                return -ENOMEM;
        }
-       memcpy(facilities, S390_lowcore.stfle_fac_list, 16);
-       facilities[0] &= 0xff82fff3f47c0000ULL;
-       facilities[1] &= 0x001c000000000000ULL;
+       memcpy(vfacilities, S390_lowcore.stfle_fac_list, 16);
+       vfacilities[0] &= 0xff82fff3f47c0000UL;
+       vfacilities[1] &= 0x001c000000000000UL;
        return 0;
 }
 
 static void __exit kvm_s390_exit(void)
 {
-       free_page((unsigned long) facilities);
+       free_page((unsigned long) vfacilities);
        kvm_exit();
 }
 
index 028ca9fd2158f4ab015e40236d70b3acbf53c6e5..dc99f1ca42678768e5e0241cbeaa20de4e0aae87 100644 (file)
@@ -24,6 +24,9 @@
 
 typedef int (*intercept_handler_t)(struct kvm_vcpu *vcpu);
 
+/* declare vfacilities extern */
+extern unsigned long *vfacilities;
+
 /* negativ values are error codes, positive values for internal conditions */
 #define SIE_INTERCEPT_RERUNVCPU                (1<<0)
 #define SIE_INTERCEPT_UCONTROL         (1<<1)
@@ -112,6 +115,13 @@ static inline u64 kvm_s390_get_base_disp_rs(struct kvm_vcpu *vcpu)
        return (base2 ? vcpu->run->s.regs.gprs[base2] : 0) + disp2;
 }
 
+/* Set the condition code in the guest program status word */
+static inline void kvm_s390_set_psw_cc(struct kvm_vcpu *vcpu, unsigned long cc)
+{
+       vcpu->arch.sie_block->gpsw.mask &= ~(3UL << 44);
+       vcpu->arch.sie_block->gpsw.mask |= cc << 44;
+}
+
 int kvm_s390_handle_wait(struct kvm_vcpu *vcpu);
 enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer);
 void kvm_s390_tasklet(unsigned long parm);
index 0da3e6eb6be6cec4d55780b838492e52d093f08d..8f8d8ee9b1fb6e0ae53fa3c707c1ee48b11f968d 100644 (file)
@@ -163,8 +163,7 @@ static int handle_tpi(struct kvm_vcpu *vcpu)
        kfree(inti);
 no_interrupt:
        /* Set condition code and we're done. */
-       vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44);
-       vcpu->arch.sie_block->gpsw.mask |= (cc & 3ul) << 44;
+       kvm_s390_set_psw_cc(vcpu, cc);
        return 0;
 }
 
@@ -219,15 +218,13 @@ static int handle_io_inst(struct kvm_vcpu *vcpu)
                 * Set condition code 3 to stop the guest from issueing channel
                 * I/O instructions.
                 */
-               vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44);
-               vcpu->arch.sie_block->gpsw.mask |= (3 & 3ul) << 44;
+               kvm_s390_set_psw_cc(vcpu, 3);
                return 0;
        }
 }
 
 static int handle_stfl(struct kvm_vcpu *vcpu)
 {
-       unsigned int facility_list;
        int rc;
 
        vcpu->stat.instruction_stfl++;
@@ -235,15 +232,13 @@ static int handle_stfl(struct kvm_vcpu *vcpu)
        if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
                return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
 
-       /* only pass the facility bits, which we can handle */
-       facility_list = S390_lowcore.stfl_fac_list & 0xff82fff3;
-
        rc = copy_to_guest(vcpu, offsetof(struct _lowcore, stfl_fac_list),
-                          &facility_list, sizeof(facility_list));
+                          vfacilities, 4);
        if (rc)
                return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
-       VCPU_EVENT(vcpu, 5, "store facility list value %x", facility_list);
-       trace_kvm_s390_handle_stfl(vcpu, facility_list);
+       VCPU_EVENT(vcpu, 5, "store facility list value %x",
+                  *(unsigned int *) vfacilities);
+       trace_kvm_s390_handle_stfl(vcpu, *(unsigned int *) vfacilities);
        return 0;
 }
 
@@ -386,7 +381,7 @@ static int handle_stsi(struct kvm_vcpu *vcpu)
                return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
 
        if (fc > 3) {
-               vcpu->arch.sie_block->gpsw.mask |= 3ul << 44;     /* cc 3 */
+               kvm_s390_set_psw_cc(vcpu, 3);
                return 0;
        }
 
@@ -396,7 +391,7 @@ static int handle_stsi(struct kvm_vcpu *vcpu)
 
        if (fc == 0) {
                vcpu->run->s.regs.gprs[0] = 3 << 28;
-               vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44);  /* cc 0 */
+               kvm_s390_set_psw_cc(vcpu, 0);
                return 0;
        }
 
@@ -430,12 +425,11 @@ static int handle_stsi(struct kvm_vcpu *vcpu)
        }
        trace_kvm_s390_handle_stsi(vcpu, fc, sel1, sel2, operand2);
        free_page(mem);
-       vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44);
+       kvm_s390_set_psw_cc(vcpu, 0);
        vcpu->run->s.regs.gprs[0] = 0;
        return 0;
 out_no_data:
-       /* condition code 3 */
-       vcpu->arch.sie_block->gpsw.mask |= 3ul << 44;
+       kvm_s390_set_psw_cc(vcpu, 3);
 out_exception:
        free_page(mem);
        return rc;
@@ -493,12 +487,12 @@ static int handle_epsw(struct kvm_vcpu *vcpu)
        kvm_s390_get_regs_rre(vcpu, &reg1, &reg2);
 
        /* This basically extracts the mask half of the psw. */
-       vcpu->run->s.regs.gprs[reg1] &= 0xffffffff00000000;
+       vcpu->run->s.regs.gprs[reg1] &= 0xffffffff00000000UL;
        vcpu->run->s.regs.gprs[reg1] |= vcpu->arch.sie_block->gpsw.mask >> 32;
        if (reg2) {
-               vcpu->run->s.regs.gprs[reg2] &= 0xffffffff00000000;
+               vcpu->run->s.regs.gprs[reg2] &= 0xffffffff00000000UL;
                vcpu->run->s.regs.gprs[reg2] |=
-                       vcpu->arch.sie_block->gpsw.mask & 0x00000000ffffffff;
+                       vcpu->arch.sie_block->gpsw.mask & 0x00000000ffffffffUL;
        }
        return 0;
 }
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..c873467ccb4a603d5a4554becb922621a5c3f55c 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_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;
+       *(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..e2498039467faf59fa3249d98db28dc56ac57321 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);
@@ -335,7 +335,7 @@ int gmap_map_segment(struct gmap *gmap, unsigned long from,
 
        if ((from | to | len) & (PMD_SIZE - 1))
                return -EINVAL;
-       if (len == 0 || from + len > PGDIR_SIZE ||
+       if (len == 0 || from + len > TASK_MAX_SIZE ||
            from + len < from || to + len < to)
                return -EINVAL;
 
@@ -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);
@@ -731,6 +732,11 @@ void gmap_do_ipte_notify(struct mm_struct *mm, unsigned long addr, pte_t *pte)
        spin_unlock(&gmap_notifier_lock);
 }
 
+static inline int page_table_with_pgste(struct page *page)
+{
+       return atomic_read(&page->_mapcount) == 0;
+}
+
 static inline unsigned long *page_table_alloc_pgste(struct mm_struct *mm,
                                                    unsigned long vmaddr)
 {
@@ -750,9 +756,9 @@ static inline unsigned long *page_table_alloc_pgste(struct mm_struct *mm,
        mp->vmaddr = vmaddr & PMD_MASK;
        INIT_LIST_HEAD(&mp->mapper);
        page->index = (unsigned long) mp;
-       atomic_set(&page->_mapcount, 3);
+       atomic_set(&page->_mapcount, 0);
        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;
 }
@@ -821,6 +827,11 @@ EXPORT_SYMBOL(set_guest_storage_key);
 
 #else /* CONFIG_PGSTE */
 
+static inline int page_table_with_pgste(struct page *page)
+{
+       return 0;
+}
+
 static inline unsigned long *page_table_alloc_pgste(struct mm_struct *mm,
                                                    unsigned long vmaddr)
 {
@@ -878,7 +889,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 {
@@ -897,12 +908,12 @@ void page_table_free(struct mm_struct *mm, unsigned long *table)
        struct page *page;
        unsigned int bit, mask;
 
-       if (mm_has_pgste(mm)) {
+       page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
+       if (page_table_with_pgste(page)) {
                gmap_disconnect_pgtable(mm, table);
                return page_table_free_pgste(table);
        }
        /* Free 1K/2K page table fragment of a 4K page */
-       page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
        bit = 1 << ((__pa(table) & ~PAGE_MASK)/(PTRS_PER_PTE*sizeof(pte_t)));
        spin_lock_bh(&mm->context.list_lock);
        if ((atomic_read(&page->_mapcount) & FRAG_MASK) != FRAG_MASK)
@@ -940,14 +951,14 @@ void page_table_free_rcu(struct mmu_gather *tlb, unsigned long *table)
        unsigned int bit, mask;
 
        mm = tlb->mm;
-       if (mm_has_pgste(mm)) {
+       page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
+       if (page_table_with_pgste(page)) {
                gmap_disconnect_pgtable(mm, table);
                table = (unsigned long *) (__pa(table) | FRAG_MASK);
                tlb_remove_table(tlb, table);
                return;
        }
        bit = 1 << ((__pa(table) & ~PAGE_MASK) / (PTRS_PER_PTE*sizeof(pte_t)));
-       page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
        spin_lock_bh(&mm->context.list_lock);
        if ((atomic_read(&page->_mapcount) & FRAG_MASK) != FRAG_MASK)
                list_del(&page->lru);
@@ -1033,36 +1044,120 @@ void tlb_remove_table(struct mmu_gather *tlb, void *table)
 }
 
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
-void thp_split_vma(struct vm_area_struct *vma)
+static inline void thp_split_vma(struct vm_area_struct *vma)
 {
        unsigned long addr;
-       struct page *page;
 
-       for (addr = vma->vm_start; addr < vma->vm_end; addr += PAGE_SIZE) {
-               page = follow_page(vma, addr, FOLL_SPLIT);
-       }
+       for (addr = vma->vm_start; addr < vma->vm_end; addr += PAGE_SIZE)
+               follow_page(vma, addr, FOLL_SPLIT);
 }
 
-void thp_split_mm(struct mm_struct *mm)
+static inline void thp_split_mm(struct mm_struct *mm)
 {
-       struct vm_area_struct *vma = mm->mmap;
+       struct vm_area_struct *vma;
 
-       while (vma != NULL) {
+       for (vma = mm->mmap; vma != NULL; vma = vma->vm_next) {
                thp_split_vma(vma);
                vma->vm_flags &= ~VM_HUGEPAGE;
                vma->vm_flags |= VM_NOHUGEPAGE;
-               vma = vma->vm_next;
        }
+       mm->def_flags |= VM_NOHUGEPAGE;
+}
+#else
+static inline void thp_split_mm(struct mm_struct *mm)
+{
 }
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
+static unsigned long page_table_realloc_pmd(struct mmu_gather *tlb,
+                               struct mm_struct *mm, pud_t *pud,
+                               unsigned long addr, unsigned long end)
+{
+       unsigned long next, *table, *new;
+       struct page *page;
+       pmd_t *pmd;
+
+       pmd = pmd_offset(pud, addr);
+       do {
+               next = pmd_addr_end(addr, end);
+again:
+               if (pmd_none_or_clear_bad(pmd))
+                       continue;
+               table = (unsigned long *) pmd_deref(*pmd);
+               page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
+               if (page_table_with_pgste(page))
+                       continue;
+               /* Allocate new page table with pgstes */
+               new = page_table_alloc_pgste(mm, addr);
+               if (!new) {
+                       mm->context.has_pgste = 0;
+                       continue;
+               }
+               spin_lock(&mm->page_table_lock);
+               if (likely((unsigned long *) pmd_deref(*pmd) == table)) {
+                       /* Nuke pmd entry pointing to the "short" page table */
+                       pmdp_flush_lazy(mm, addr, pmd);
+                       pmd_clear(pmd);
+                       /* Copy ptes from old table to new table */
+                       memcpy(new, table, PAGE_SIZE/2);
+                       clear_table(table, _PAGE_INVALID, PAGE_SIZE/2);
+                       /* Establish new table */
+                       pmd_populate(mm, pmd, (pte_t *) new);
+                       /* Free old table with rcu, there might be a walker! */
+                       page_table_free_rcu(tlb, table);
+                       new = NULL;
+               }
+               spin_unlock(&mm->page_table_lock);
+               if (new) {
+                       page_table_free_pgste(new);
+                       goto again;
+               }
+       } while (pmd++, addr = next, addr != end);
+
+       return addr;
+}
+
+static unsigned long page_table_realloc_pud(struct mmu_gather *tlb,
+                                  struct mm_struct *mm, pgd_t *pgd,
+                                  unsigned long addr, unsigned long end)
+{
+       unsigned long next;
+       pud_t *pud;
+
+       pud = pud_offset(pgd, addr);
+       do {
+               next = pud_addr_end(addr, end);
+               if (pud_none_or_clear_bad(pud))
+                       continue;
+               next = page_table_realloc_pmd(tlb, mm, pud, addr, next);
+       } while (pud++, addr = next, addr != end);
+
+       return addr;
+}
+
+static void page_table_realloc(struct mmu_gather *tlb, struct mm_struct *mm,
+                              unsigned long addr, unsigned long end)
+{
+       unsigned long next;
+       pgd_t *pgd;
+
+       pgd = pgd_offset(mm, addr);
+       do {
+               next = pgd_addr_end(addr, end);
+               if (pgd_none_or_clear_bad(pgd))
+                       continue;
+               next = page_table_realloc_pud(tlb, mm, pgd, addr, next);
+       } while (pgd++, addr = next, addr != end);
+}
+
 /*
  * switch on pgstes for its userspace process (for kvm)
  */
 int s390_enable_sie(void)
 {
        struct task_struct *tsk = current;
-       struct mm_struct *mm, *old_mm;
+       struct mm_struct *mm = tsk->mm;
+       struct mmu_gather tlb;
 
        /* Do we have switched amode? If no, we cannot do sie */
        if (s390_user_mode == HOME_SPACE_MODE)
@@ -1072,57 +1167,16 @@ int s390_enable_sie(void)
        if (mm_has_pgste(tsk->mm))
                return 0;
 
-       /* lets check if we are allowed to replace the mm */
-       task_lock(tsk);
-       if (!tsk->mm || atomic_read(&tsk->mm->mm_users) > 1 ||
-#ifdef CONFIG_AIO
-           !hlist_empty(&tsk->mm->ioctx_list) ||
-#endif
-           tsk->mm != tsk->active_mm) {
-               task_unlock(tsk);
-               return -EINVAL;
-       }
-       task_unlock(tsk);
-
-       /* we copy the mm and let dup_mm create the page tables with_pgstes */
-       tsk->mm->context.alloc_pgste = 1;
-       /* make sure that both mms have a correct rss state */
-       sync_mm_rss(tsk->mm);
-       mm = dup_mm(tsk);
-       tsk->mm->context.alloc_pgste = 0;
-       if (!mm)
-               return -ENOMEM;
-
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+       down_write(&mm->mmap_sem);
        /* split thp mappings and disable thp for future mappings */
        thp_split_mm(mm);
-       mm->def_flags |= VM_NOHUGEPAGE;
-#endif
-
-       /* Now lets check again if something happened */
-       task_lock(tsk);
-       if (!tsk->mm || atomic_read(&tsk->mm->mm_users) > 1 ||
-#ifdef CONFIG_AIO
-           !hlist_empty(&tsk->mm->ioctx_list) ||
-#endif
-           tsk->mm != tsk->active_mm) {
-               mmput(mm);
-               task_unlock(tsk);
-               return -EINVAL;
-       }
-
-       /* ok, we are alone. No ptrace, no threads, etc. */
-       old_mm = tsk->mm;
-       tsk->mm = tsk->active_mm = mm;
-       preempt_disable();
-       update_mm(mm, tsk);
-       atomic_inc(&mm->context.attach_count);
-       atomic_dec(&old_mm->context.attach_count);
-       cpumask_set_cpu(smp_processor_id(), mm_cpumask(mm));
-       preempt_enable();
-       task_unlock(tsk);
-       mmput(old_mm);
-       return 0;
+       /* Reallocate the page tables with pgstes */
+       mm->context.has_pgste = 1;
+       tlb_gather_mmu(&tlb, mm, 0);
+       page_table_realloc(&tlb, mm, 0, TASK_SIZE);
+       tlb_finish_mmu(&tlb, 0, -1);
+       up_write(&mm->mmap_sem);
+       return mm->context.has_pgste ? 0 : -ENOMEM;
 }
 EXPORT_SYMBOL_GPL(s390_enable_sie);
 
@@ -1198,9 +1252,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 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 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 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..23562cbe3e8e8d68d55376100e8300fe55d66534 100644 (file)
@@ -612,7 +612,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 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 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 b32ebf92b0ce96b5798bdf2a48043986be6ba6ea..52432ab5bd77ac89d8d87b3167687a8bff80a040 100644 (file)
@@ -81,7 +81,6 @@ config X86
        select HAVE_USER_RETURN_NOTIFIER
        select ARCH_BINFMT_ELF_RANDOMIZE_PIE
        select HAVE_ARCH_JUMP_LABEL
-       select HAVE_TEXT_POKE_SMP
        select HAVE_GENERIC_HARDIRQS
        select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
        select SPARSE_IRQ
@@ -1344,8 +1343,12 @@ config ARCH_SELECT_MEMORY_MODEL
        depends on ARCH_SPARSEMEM_ENABLE
 
 config ARCH_MEMORY_PROBE
-       def_bool y
+       bool "Enable sysfs memory/probe interface"
        depends on X86_64 && MEMORY_HOTPLUG
+       help
+         This option enables a sysfs memory/probe interface for testing.
+         See Documentation/memory-hotplug.txt for more information.
+         If you are unsure how to answer this question, answer N.
 
 config ARCH_PROC_KCORE_TEXT
        def_bool y
@@ -2332,10 +2335,6 @@ config HAVE_ATOMIC_IOMAP
        def_bool y
        depends on X86_32
 
-config HAVE_TEXT_POKE_SMP
-       bool
-       select STOP_MACHINE if SMP
-
 config X86_DEV_DMA_OPS
        bool
        depends on X86_64 || STA2X11
index d606463aa6d63bfdab5641e6bd7e6b68545e32d9..b7388a425f0994ba87a30a27fe8ba57d7e3e5457 100644 (file)
@@ -225,7 +225,7 @@ static void low_free(unsigned long size, unsigned long addr)
        unsigned long nr_pages;
 
        nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
-       efi_call_phys2(sys_table->boottime->free_pages, addr, size);
+       efi_call_phys2(sys_table->boottime->free_pages, addr, nr_pages);
 }
 
 static void find_bits(unsigned long mask, u8 *pos, u8 *size)
index 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 474dc1b59f726b92de0a6c9fe3cfcc76ae5e005e..4299eb05023cf812ee0f897a1a6189660167dc4e 100644 (file)
@@ -452,7 +452,7 @@ ia32_badsys:
 
        CFI_ENDPROC
        
-       .macro PTREGSCALL label, func, arg
+       .macro PTREGSCALL label, func
        ALIGN
 GLOBAL(\label)
        leaq \func(%rip),%rax
index 2dfac58f3b11049e21b9ed752546f873b207adb0..b1977bad5435e5342af7e548700f08c1a04ff580 100644 (file)
@@ -86,6 +86,7 @@ extern int acpi_pci_disabled;
 extern int acpi_skip_timer_override;
 extern int acpi_use_timer_override;
 extern int acpi_fix_pin2_polarity;
+extern int acpi_disable_cmcff;
 
 extern u8 acpi_sci_flags;
 extern int acpi_sci_override_gsi;
@@ -168,6 +169,7 @@ static inline void arch_acpi_set_pdc_bits(u32 *buf)
 
 #define acpi_lapic 0
 #define acpi_ioapic 0
+#define acpi_disable_cmcff 0
 static inline void acpi_noirq_set(void) { }
 static inline void acpi_disable_pci(void) { }
 static inline void disable_acpi(void) { }
index 58ed6d96a6acbd99169bbc8e964b6ba998d8774f..0a3f9c9f98d5ccf446980cfcf71b7055bb79ade8 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/stddef.h>
 #include <linux/stringify.h>
 #include <asm/asm.h>
+#include <asm/ptrace.h>
 
 /*
  * Alternative inline assembly for SMP.
@@ -220,20 +221,11 @@ extern void *text_poke_early(void *addr, const void *opcode, size_t len);
  * no thread can be preempted in the instructions being modified (no iret to an
  * invalid instruction possible) or if the instructions are changed from a
  * consistent state to another consistent state atomically.
- * More care must be taken when modifying code in the SMP case because of
- * Intel's errata. text_poke_smp() takes care that errata, but still
- * doesn't support NMI/MCE handler code modifying.
  * On the local CPU you need to be protected again NMI or MCE handlers seeing an
  * inconsistent instruction while you patch.
  */
-struct text_poke_param {
-       void *addr;
-       const void *opcode;
-       size_t len;
-};
-
 extern void *text_poke(void *addr, const void *opcode, size_t len);
-extern void *text_poke_smp(void *addr, const void *opcode, size_t len);
-extern void text_poke_smp_batch(struct text_poke_param *params, int n);
+extern int poke_int3_handler(struct pt_regs *regs);
+extern void *text_poke_bp(void *addr, const void *opcode, size_t len, void *handler);
 
 #endif /* _ASM_X86_ALTERNATIVE_H */
index 6dfd0195bb5529ce8a86fa379726f43b9f513ab4..41639ce8fd634a4e8436a062006b763702749fc1 100644 (file)
 #include <linux/compiler.h>
 #include <asm/alternative.h>
 
+#if BITS_PER_LONG == 32
+# define _BITOPS_LONG_SHIFT 5
+#elif BITS_PER_LONG == 64
+# define _BITOPS_LONG_SHIFT 6
+#else
+# error "Unexpected BITS_PER_LONG"
+#endif
+
 #define BIT_64(n)                      (U64_C(1) << (n))
 
 /*
@@ -59,7 +67,7 @@
  * restricted to acting on a single-word quantity.
  */
 static __always_inline void
-set_bit(unsigned int nr, volatile unsigned long *addr)
+set_bit(long nr, volatile unsigned long *addr)
 {
        if (IS_IMMEDIATE(nr)) {
                asm volatile(LOCK_PREFIX "orb %1,%0"
@@ -81,7 +89,7 @@ set_bit(unsigned int nr, volatile unsigned long *addr)
  * If it's called on the same region of memory simultaneously, the effect
  * may be that only one operation succeeds.
  */
-static inline void __set_bit(int nr, volatile unsigned long *addr)
+static inline void __set_bit(long nr, volatile unsigned long *addr)
 {
        asm volatile("bts %1,%0" : ADDR : "Ir" (nr) : "memory");
 }
@@ -97,7 +105,7 @@ static inline void __set_bit(int nr, volatile unsigned long *addr)
  * in order to ensure changes are visible on other processors.
  */
 static __always_inline void
-clear_bit(int nr, volatile unsigned long *addr)
+clear_bit(long nr, volatile unsigned long *addr)
 {
        if (IS_IMMEDIATE(nr)) {
                asm volatile(LOCK_PREFIX "andb %1,%0"
@@ -118,13 +126,13 @@ clear_bit(int nr, volatile unsigned long *addr)
  * clear_bit() is atomic and implies release semantics before the memory
  * operation. It can be used for an unlock.
  */
-static inline void clear_bit_unlock(unsigned nr, volatile unsigned long *addr)
+static inline void clear_bit_unlock(long nr, volatile unsigned long *addr)
 {
        barrier();
        clear_bit(nr, addr);
 }
 
-static inline void __clear_bit(int nr, volatile unsigned long *addr)
+static inline void __clear_bit(long nr, volatile unsigned long *addr)
 {
        asm volatile("btr %1,%0" : ADDR : "Ir" (nr));
 }
@@ -141,7 +149,7 @@ static inline void __clear_bit(int nr, volatile unsigned long *addr)
  * No memory barrier is required here, because x86 cannot reorder stores past
  * older loads. Same principle as spin_unlock.
  */
-static inline void __clear_bit_unlock(unsigned nr, volatile unsigned long *addr)
+static inline void __clear_bit_unlock(long nr, volatile unsigned long *addr)
 {
        barrier();
        __clear_bit(nr, addr);
@@ -159,7 +167,7 @@ static inline void __clear_bit_unlock(unsigned nr, volatile unsigned long *addr)
  * If it's called on the same region of memory simultaneously, the effect
  * may be that only one operation succeeds.
  */
-static inline void __change_bit(int nr, volatile unsigned long *addr)
+static inline void __change_bit(long nr, volatile unsigned long *addr)
 {
        asm volatile("btc %1,%0" : ADDR : "Ir" (nr));
 }
@@ -173,7 +181,7 @@ static inline void __change_bit(int nr, volatile unsigned long *addr)
  * Note that @nr may be almost arbitrarily large; this function is not
  * restricted to acting on a single-word quantity.
  */
-static inline void change_bit(int nr, volatile unsigned long *addr)
+static inline void change_bit(long nr, volatile unsigned long *addr)
 {
        if (IS_IMMEDIATE(nr)) {
                asm volatile(LOCK_PREFIX "xorb %1,%0"
@@ -194,7 +202,7 @@ static inline void change_bit(int nr, volatile unsigned long *addr)
  * This operation is atomic and cannot be reordered.
  * It also implies a memory barrier.
  */
-static inline int test_and_set_bit(int nr, volatile unsigned long *addr)
+static inline int test_and_set_bit(long nr, volatile unsigned long *addr)
 {
        int oldbit;
 
@@ -212,7 +220,7 @@ static inline int test_and_set_bit(int nr, volatile unsigned long *addr)
  * This is the same as test_and_set_bit on x86.
  */
 static __always_inline int
-test_and_set_bit_lock(int nr, volatile unsigned long *addr)
+test_and_set_bit_lock(long nr, volatile unsigned long *addr)
 {
        return test_and_set_bit(nr, addr);
 }
@@ -226,7 +234,7 @@ test_and_set_bit_lock(int nr, volatile unsigned long *addr)
  * If two examples of this operation race, one can appear to succeed
  * but actually fail.  You must protect multiple accesses with a lock.
  */
-static inline int __test_and_set_bit(int nr, volatile unsigned long *addr)
+static inline int __test_and_set_bit(long nr, volatile unsigned long *addr)
 {
        int oldbit;
 
@@ -245,7 +253,7 @@ static inline int __test_and_set_bit(int nr, volatile unsigned long *addr)
  * This operation is atomic and cannot be reordered.
  * It also implies a memory barrier.
  */
-static inline int test_and_clear_bit(int nr, volatile unsigned long *addr)
+static inline int test_and_clear_bit(long nr, volatile unsigned long *addr)
 {
        int oldbit;
 
@@ -272,7 +280,7 @@ static inline int test_and_clear_bit(int nr, volatile unsigned long *addr)
  * accessed from a hypervisor on the same CPU if running in a VM: don't change
  * this without also updating arch/x86/kernel/kvm.c
  */
-static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr)
+static inline int __test_and_clear_bit(long nr, volatile unsigned long *addr)
 {
        int oldbit;
 
@@ -284,7 +292,7 @@ static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr)
 }
 
 /* WARNING: non atomic and it can be reordered! */
-static inline int __test_and_change_bit(int nr, volatile unsigned long *addr)
+static inline int __test_and_change_bit(long nr, volatile unsigned long *addr)
 {
        int oldbit;
 
@@ -304,7 +312,7 @@ static inline int __test_and_change_bit(int nr, volatile unsigned long *addr)
  * This operation is atomic and cannot be reordered.
  * It also implies a memory barrier.
  */
-static inline int test_and_change_bit(int nr, volatile unsigned long *addr)
+static inline int test_and_change_bit(long nr, volatile unsigned long *addr)
 {
        int oldbit;
 
@@ -315,13 +323,13 @@ static inline int test_and_change_bit(int nr, volatile unsigned long *addr)
        return oldbit;
 }
 
-static __always_inline int constant_test_bit(unsigned int nr, const volatile unsigned long *addr)
+static __always_inline int constant_test_bit(long nr, const volatile unsigned long *addr)
 {
-       return ((1UL << (nr % BITS_PER_LONG)) &
-               (addr[nr / BITS_PER_LONG])) != 0;
+       return ((1UL << (nr & (BITS_PER_LONG-1))) &
+               (addr[nr >> _BITOPS_LONG_SHIFT])) != 0;
 }
 
-static inline int variable_test_bit(int nr, volatile const unsigned long *addr)
+static inline int variable_test_bit(long nr, volatile const unsigned long *addr)
 {
        int oldbit;
 
index 47538a61c91bfddc1eff8a6712e4f89a5b0187b4..d3f5c63078d812e2f6220cfa5ad322aae920827c 100644 (file)
@@ -366,9 +366,10 @@ extern bool __static_cpu_has_safe(u16 bit);
  */
 static __always_inline __pure bool __static_cpu_has(u16 bit)
 {
-#if __GNUC__ > 4 || __GNUC_MINOR__ >= 5
+#ifdef CC_HAVE_ASM_GOTO
 
 #ifdef CONFIG_X86_DEBUG_STATIC_CPU_HAS
+
                /*
                 * Catch too early usage of this before alternatives
                 * have run.
@@ -384,6 +385,7 @@ static __always_inline __pure bool __static_cpu_has(u16 bit)
                         ".previous\n"
                         /* skipping size check since replacement size = 0 */
                         : : "i" (X86_FEATURE_ALWAYS) : : t_warn);
+
 #endif
 
                asm goto("1: jmp %l[t_no]\n"
@@ -406,7 +408,9 @@ static __always_inline __pure bool __static_cpu_has(u16 bit)
                warn_pre_alternatives();
                return false;
 #endif
-#else /* GCC_VERSION >= 40500 */
+
+#else /* CC_HAVE_ASM_GOTO */
+
                u8 flag;
                /* Open-coded due to __stringify() in ALTERNATIVE() */
                asm volatile("1: movb $0,%0\n"
@@ -427,7 +431,8 @@ static __always_inline __pure bool __static_cpu_has(u16 bit)
                             ".previous\n"
                             : "=qm" (flag) : "i" (bit));
                return flag;
-#endif
+
+#endif /* CC_HAVE_ASM_GOTO */
 }
 
 #define static_cpu_has(bit)                                    \
@@ -441,7 +446,7 @@ static __always_inline __pure bool __static_cpu_has(u16 bit)
 
 static __always_inline __pure bool _static_cpu_has_safe(u16 bit)
 {
-#if __GNUC__ > 4 || __GNUC_MINOR__ >= 5
+#ifdef CC_HAVE_ASM_GOTO
 /*
  * We need to spell the jumps to the compiler because, depending on the offset,
  * the replacement jump can be bigger than the original jump, and this we cannot
@@ -475,7 +480,7 @@ static __always_inline __pure bool _static_cpu_has_safe(u16 bit)
                return false;
        t_dynamic:
                return __static_cpu_has_safe(bit);
-#else /* GCC_VERSION >= 40500 */
+#else
                u8 flag;
                /* Open-coded due to __stringify() in ALTERNATIVE() */
                asm volatile("1: movb $2,%0\n"
@@ -511,7 +516,7 @@ static __always_inline __pure bool _static_cpu_has_safe(u16 bit)
                             : "=qm" (flag)
                             : "i" (bit), "i" (X86_FEATURE_ALWAYS));
                return (flag == 2 ? __static_cpu_has_safe(bit) : flag);
-#endif
+#endif /* CC_HAVE_ASM_GOTO */
 }
 
 #define static_cpu_has_safe(bit)                               \
index f87f7fcefa0acdc4856aa576078a34c2d4002e1e..f5df0a84e51cbacd4cb4d056ddfa064a2be250db 100644 (file)
@@ -323,6 +323,7 @@ struct kvm_pmu {
        u64 global_ovf_ctrl;
        u64 counter_bitmask[2];
        u64 global_ctrl_mask;
+       u64 reserved_bits;
        u8 version;
        struct kvm_pmc gp_counters[INTEL_PMC_MAX_GENERIC];
        struct kvm_pmc fixed_counters[INTEL_PMC_MAX_FIXED];
@@ -802,8 +803,8 @@ extern u32  kvm_min_guest_tsc_khz;
 extern u32  kvm_max_guest_tsc_khz;
 
 enum emulation_result {
-       EMULATE_DONE,       /* no further processing */
-       EMULATE_DO_MMIO,      /* kvm_run filled with mmio request */
+       EMULATE_DONE,         /* no further processing */
+       EMULATE_USER_EXIT,    /* kvm_run ready for userspace exit */
        EMULATE_FAIL,         /* can't emulate this instruction */
 };
 
index 29e3093bbd2132d89e8b22d0150a3088d6e4b1da..163d7a4451f034e579b7d7d296a3a92a70fd4237 100644 (file)
@@ -188,6 +188,9 @@ extern void register_mce_write_callback(ssize_t (*)(struct file *filp,
                                    const char __user *ubuf,
                                    size_t usize, loff_t *off));
 
+/* Disable CMCI/polling for MCA bank claimed by firmware */
+extern void mce_disable_bank(int bank);
+
 /*
  * Exception handler
  */
index 2c543fff241bb85cb3b07c6cd1c19033380ffd3c..e7e6751648edf775ad54a42a5c05b3e6d3c1cff5 100644 (file)
  *
  * Atomically decrements @v and calls <fail_fn> if the result is negative.
  */
+#ifdef CC_HAVE_ASM_GOTO
+static inline void __mutex_fastpath_lock(atomic_t *v,
+                                        void (*fail_fn)(atomic_t *))
+{
+       asm volatile goto(LOCK_PREFIX "   decl %0\n"
+                         "   jns %l[exit]\n"
+                         : : "m" (v->counter)
+                         : "memory", "cc"
+                         : exit);
+       fail_fn(v);
+exit:
+       return;
+}
+#else
 #define __mutex_fastpath_lock(v, fail_fn)                      \
 do {                                                           \
        unsigned long dummy;                                    \
@@ -32,6 +46,7 @@ do {                                                          \
                     : "rax", "rsi", "rdx", "rcx",              \
                       "r8", "r9", "r10", "r11", "memory");     \
 } while (0)
+#endif
 
 /**
  *  __mutex_fastpath_lock_retval - try to take the lock by moving the count
@@ -56,6 +71,20 @@ static inline int __mutex_fastpath_lock_retval(atomic_t *count)
  *
  * Atomically increments @v and calls <fail_fn> if the result is nonpositive.
  */
+#ifdef CC_HAVE_ASM_GOTO
+static inline void __mutex_fastpath_unlock(atomic_t *v,
+                                          void (*fail_fn)(atomic_t *))
+{
+       asm volatile goto(LOCK_PREFIX "   incl %0\n"
+                         "   jg %l[exit]\n"
+                         : : "m" (v->counter)
+                         : "memory", "cc"
+                         : exit);
+       fail_fn(v);
+exit:
+       return;
+}
+#else
 #define __mutex_fastpath_unlock(v, fail_fn)                    \
 do {                                                           \
        unsigned long dummy;                                    \
@@ -72,6 +101,7 @@ do {                                                         \
                     : "rax", "rsi", "rdx", "rcx",              \
                       "r8", "r9", "r10", "r11", "memory");     \
 } while (0)
+#endif
 
 #define __mutex_slowpath_needs_to_unlock()     1
 
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 109a9dd5d454f197414e2449617cf9cb73ab1220..be8269b00e2a1f720fe69755645948cf771e769e 100644 (file)
@@ -93,7 +93,6 @@ unsigned __pvclock_read_cycles(const struct pvclock_vcpu_time_info *src,
 
 struct pvclock_vsyscall_time_info {
        struct pvclock_vcpu_time_info pvti;
-       u32 migrate_count;
 } __attribute__((__aligned__(SMP_CACHE_BYTES)));
 
 #define PVTI_SIZE sizeof(struct pvclock_vsyscall_time_info)
index 9d09b4073b60f137e970be710ebc171a4b001125..05af3b31d522083498dad85efea6b3b0848f2551 100644 (file)
@@ -26,9 +26,9 @@
  * Note that @nr may be almost arbitrarily large; this function is not
  * restricted to acting on a single-word quantity.
  */
-static inline void sync_set_bit(int nr, volatile unsigned long *addr)
+static inline void sync_set_bit(long nr, volatile unsigned long *addr)
 {
-       asm volatile("lock; btsl %1,%0"
+       asm volatile("lock; bts %1,%0"
                     : "+m" (ADDR)
                     : "Ir" (nr)
                     : "memory");
@@ -44,9 +44,9 @@ static inline void sync_set_bit(int nr, volatile unsigned long *addr)
  * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit()
  * in order to ensure changes are visible on other processors.
  */
-static inline void sync_clear_bit(int nr, volatile unsigned long *addr)
+static inline void sync_clear_bit(long nr, volatile unsigned long *addr)
 {
-       asm volatile("lock; btrl %1,%0"
+       asm volatile("lock; btr %1,%0"
                     : "+m" (ADDR)
                     : "Ir" (nr)
                     : "memory");
@@ -61,9 +61,9 @@ static inline void sync_clear_bit(int nr, volatile unsigned long *addr)
  * Note that @nr may be almost arbitrarily large; this function is not
  * restricted to acting on a single-word quantity.
  */
-static inline void sync_change_bit(int nr, volatile unsigned long *addr)
+static inline void sync_change_bit(long nr, volatile unsigned long *addr)
 {
-       asm volatile("lock; btcl %1,%0"
+       asm volatile("lock; btc %1,%0"
                     : "+m" (ADDR)
                     : "Ir" (nr)
                     : "memory");
@@ -77,11 +77,11 @@ static inline void sync_change_bit(int nr, volatile unsigned long *addr)
  * This operation is atomic and cannot be reordered.
  * It also implies a memory barrier.
  */
-static inline int sync_test_and_set_bit(int nr, volatile unsigned long *addr)
+static inline int sync_test_and_set_bit(long nr, volatile unsigned long *addr)
 {
        int oldbit;
 
-       asm volatile("lock; btsl %2,%1\n\tsbbl %0,%0"
+       asm volatile("lock; bts %2,%1\n\tsbbl %0,%0"
                     : "=r" (oldbit), "+m" (ADDR)
                     : "Ir" (nr) : "memory");
        return oldbit;
@@ -95,11 +95,11 @@ static inline int sync_test_and_set_bit(int nr, volatile unsigned long *addr)
  * This operation is atomic and cannot be reordered.
  * It also implies a memory barrier.
  */
-static inline int sync_test_and_clear_bit(int nr, volatile unsigned long *addr)
+static inline int sync_test_and_clear_bit(long nr, volatile unsigned long *addr)
 {
        int oldbit;
 
-       asm volatile("lock; btrl %2,%1\n\tsbbl %0,%0"
+       asm volatile("lock; btr %2,%1\n\tsbbl %0,%0"
                     : "=r" (oldbit), "+m" (ADDR)
                     : "Ir" (nr) : "memory");
        return oldbit;
@@ -113,11 +113,11 @@ static inline int sync_test_and_clear_bit(int nr, volatile unsigned long *addr)
  * This operation is atomic and cannot be reordered.
  * It also implies a memory barrier.
  */
-static inline int sync_test_and_change_bit(int nr, volatile unsigned long *addr)
+static inline int sync_test_and_change_bit(long nr, volatile unsigned long *addr)
 {
        int oldbit;
 
-       asm volatile("lock; btcl %2,%1\n\tsbbl %0,%0"
+       asm volatile("lock; btc %2,%1\n\tsbbl %0,%0"
                     : "=r" (oldbit), "+m" (ADDR)
                     : "Ir" (nr) : "memory");
        return oldbit;
index c91e8b9d588b14d0f86b4ea7a82b5d07c8387c2c..235be70d5bb4d0e936fba155a785b82bb639ee1b 100644 (file)
@@ -49,6 +49,7 @@ extern void tsc_init(void);
 extern void mark_tsc_unstable(char *reason);
 extern int unsynchronized_tsc(void);
 extern int check_tsc_unstable(void);
+extern int check_tsc_disabled(void);
 extern unsigned long native_calibrate_tsc(void);
 
 extern int tsc_clocksource_reliable;
index 2627a81253eeaf03336f36ed4ea13dc49baa7183..e482d0609acd2665c4305f14d8d65e6cf92ec61a 100644 (file)
@@ -67,6 +67,7 @@ EXPORT_SYMBOL(acpi_pci_disabled);
 int acpi_lapic;
 int acpi_ioapic;
 int acpi_strict;
+int acpi_disable_cmcff;
 
 u8 acpi_sci_flags __initdata;
 int acpi_sci_override_gsi __initdata;
@@ -141,16 +142,8 @@ static u32 irq_to_gsi(int irq)
 }
 
 /*
- * Temporarily use the virtual area starting from FIX_IO_APIC_BASE_END,
- * to map the target physical address. The problem is that set_fixmap()
- * provides a single page, and it is possible that the page is not
- * sufficient.
- * By using this area, we can map up to MAX_IO_APICS pages temporarily,
- * i.e. until the next __va_range() call.
- *
- * Important Safety Note:  The fixed I/O APIC page numbers are *subtracted*
- * from the fixed base.  That's why we start at FIX_IO_APIC_BASE_END and
- * count idx down while incrementing the phys address.
+ * This is just a simple wrapper around early_ioremap(),
+ * with sanity checks for phys == 0 and size == 0.
  */
 char *__init __acpi_map_table(unsigned long phys, unsigned long size)
 {
@@ -160,6 +153,7 @@ char *__init __acpi_map_table(unsigned long phys, unsigned long size)
 
        return early_ioremap(phys, size);
 }
+
 void __init __acpi_unmap_table(char *map, unsigned long size)
 {
        if (!map || !size)
@@ -199,7 +193,7 @@ static void acpi_register_lapic(int id, u8 enabled)
 {
        unsigned int ver = 0;
 
-       if (id >= (MAX_LOCAL_APIC-1)) {
+       if (id >= MAX_LOCAL_APIC) {
                printk(KERN_INFO PREFIX "skipped apicid that is too big\n");
                return;
        }
@@ -1626,6 +1620,10 @@ static int __init parse_acpi(char *arg)
        /* "acpi=copy_dsdt" copys DSDT */
        else if (strcmp(arg, "copy_dsdt") == 0) {
                acpi_gbl_copy_dsdt_locally = 1;
+       }
+       /* "acpi=nocmcff" disables FF mode for corrected errors */
+       else if (strcmp(arg, "nocmcff") == 0) {
+               acpi_disable_cmcff = 1;
        } else {
                /* Core will printk when we return error. */
                return -EINVAL;
index c15cf9a25e279fc9934549a2c4a7d6faf26766fd..15e8563e5c244e0712c9696a3367067044a300b3 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/memory.h>
 #include <linux/stop_machine.h>
 #include <linux/slab.h>
+#include <linux/kdebug.h>
 #include <asm/alternative.h>
 #include <asm/sections.h>
 #include <asm/pgtable.h>
@@ -596,97 +597,93 @@ void *__kprobes text_poke(void *addr, const void *opcode, size_t len)
        return addr;
 }
 
-/*
- * Cross-modifying kernel text with stop_machine().
- * This code originally comes from immediate value.
- */
-static atomic_t stop_machine_first;
-static int wrote_text;
+static void do_sync_core(void *info)
+{
+       sync_core();
+}
 
-struct text_poke_params {
-       struct text_poke_param *params;
-       int nparams;
-};
+static bool bp_patching_in_progress;
+static void *bp_int3_handler, *bp_int3_addr;
 
-static int __kprobes stop_machine_text_poke(void *data)
+int poke_int3_handler(struct pt_regs *regs)
 {
-       struct text_poke_params *tpp = data;
-       struct text_poke_param *p;
-       int i;
+       /* bp_patching_in_progress */
+       smp_rmb();
 
-       if (atomic_xchg(&stop_machine_first, 0)) {
-               for (i = 0; i < tpp->nparams; i++) {
-                       p = &tpp->params[i];
-                       text_poke(p->addr, p->opcode, p->len);
-               }
-               smp_wmb();      /* Make sure other cpus see that this has run */
-               wrote_text = 1;
-       } else {
-               while (!wrote_text)
-                       cpu_relax();
-               smp_mb();       /* Load wrote_text before following execution */
-       }
+       if (likely(!bp_patching_in_progress))
+               return 0;
 
-       for (i = 0; i < tpp->nparams; i++) {
-               p = &tpp->params[i];
-               flush_icache_range((unsigned long)p->addr,
-                                  (unsigned long)p->addr + p->len);
-       }
-       /*
-        * Intel Archiecture Software Developer's Manual section 7.1.3 specifies
-        * that a core serializing instruction such as "cpuid" should be
-        * executed on _each_ core before the new instruction is made visible.
-        */
-       sync_core();
-       return 0;
-}
+       if (user_mode_vm(regs) || regs->ip != (unsigned long)bp_int3_addr)
+               return 0;
+
+       /* set up the specified breakpoint handler */
+       regs->ip = (unsigned long) bp_int3_handler;
+
+       return 1;
 
-/**
- * text_poke_smp - Update instructions on a live kernel on SMP
- * @addr: address to modify
- * @opcode: source of the copy
- * @len: length to copy
- *
- * Modify multi-byte instruction by using stop_machine() on SMP. This allows
- * user to poke/set multi-byte text on SMP. Only non-NMI/MCE code modifying
- * should be allowed, since stop_machine() does _not_ protect code against
- * NMI and MCE.
- *
- * Note: Must be called under get_online_cpus() and text_mutex.
- */
-void *__kprobes text_poke_smp(void *addr, const void *opcode, size_t len)
-{
-       struct text_poke_params tpp;
-       struct text_poke_param p;
-
-       p.addr = addr;
-       p.opcode = opcode;
-       p.len = len;
-       tpp.params = &p;
-       tpp.nparams = 1;
-       atomic_set(&stop_machine_first, 1);
-       wrote_text = 0;
-       /* Use __stop_machine() because the caller already got online_cpus. */
-       __stop_machine(stop_machine_text_poke, (void *)&tpp, cpu_online_mask);
-       return addr;
 }
 
 /**
- * text_poke_smp_batch - Update instructions on a live kernel on SMP
- * @params: an array of text_poke parameters
- * @n: the number of elements in params.
+ * text_poke_bp() -- update instructions on live kernel on SMP
+ * @addr:      address to patch
+ * @opcode:    opcode of new instruction
+ * @len:       length to copy
+ * @handler:   address to jump to when the temporary breakpoint is hit
  *
- * Modify multi-byte instruction by using stop_machine() on SMP. Since the
- * stop_machine() is heavy task, it is better to aggregate text_poke requests
- * and do it once if possible.
+ * Modify multi-byte instruction by using int3 breakpoint on SMP.
+ * We completely avoid stop_machine() here, and achieve the
+ * synchronization using int3 breakpoint.
  *
- * Note: Must be called under get_online_cpus() and text_mutex.
+ * The way it is done:
+ *     - add a int3 trap to the address that will be patched
+ *     - sync cores
+ *     - update all but the first byte of the patched range
+ *     - sync cores
+ *     - replace the first byte (int3) by the first byte of
+ *       replacing opcode
+ *     - sync cores
+ *
+ * Note: must be called under text_mutex.
  */
-void __kprobes text_poke_smp_batch(struct text_poke_param *params, int n)
+void *text_poke_bp(void *addr, const void *opcode, size_t len, void *handler)
 {
-       struct text_poke_params tpp = {.params = params, .nparams = n};
+       unsigned char int3 = 0xcc;
+
+       bp_int3_handler = handler;
+       bp_int3_addr = (u8 *)addr + sizeof(int3);
+       bp_patching_in_progress = true;
+       /*
+        * Corresponding read barrier in int3 notifier for
+        * making sure the in_progress flags is correctly ordered wrt.
+        * patching
+        */
+       smp_wmb();
+
+       text_poke(addr, &int3, sizeof(int3));
 
-       atomic_set(&stop_machine_first, 1);
-       wrote_text = 0;
-       __stop_machine(stop_machine_text_poke, (void *)&tpp, cpu_online_mask);
+       on_each_cpu(do_sync_core, NULL, 1);
+
+       if (len - sizeof(int3) > 0) {
+               /* patch all but the first byte */
+               text_poke((char *)addr + sizeof(int3),
+                         (const char *) opcode + sizeof(int3),
+                         len - sizeof(int3));
+               /*
+                * According to Intel, this core syncing is very likely
+                * not necessary and we'd be safe even without it. But
+                * better safe than sorry (plus there's not only Intel).
+                */
+               on_each_cpu(do_sync_core, NULL, 1);
+       }
+
+       /* patch the first byte */
+       text_poke(addr, opcode, sizeof(int3));
+
+       on_each_cpu(do_sync_core, NULL, 1);
+
+       bp_patching_in_progress = false;
+       smp_wmb();
+
+       return addr;
 }
+
index eca89c53a7f50598c94ddb6ebab399649b7e747a..d9dd5a6e0ddaac229155f7b2bba6b4d1ee03d162 100644 (file)
@@ -1622,11 +1622,8 @@ void __init enable_IR_x2apic(void)
                goto skip_x2apic;
 
        if (ret < 0) {
-               /* IR is required if there is APIC ID > 255 even when running
-                * under KVM
-                */
-               if (max_physical_apicid > 255 ||
-                   !hypervisor_x2apic_available()) {
+               /* IR is required if there is APIC ID > 255 */
+               if (max_physical_apicid > 255) {
                        if (x2apic_preenabled)
                                disable_x2apic();
                        goto skip_x2apic;
index 5b7d4fa5d3b726da00a0b4102ce9aa22681a98ac..09edd0b65fefbb1eda927e3af5ac84a8e4ab40cd 100644 (file)
@@ -25,15 +25,18 @@ int mce_severity(struct mce *a, int tolerant, char **msg);
 struct dentry *mce_get_debugfs_dir(void);
 
 extern struct mce_bank *mce_banks;
+extern mce_banks_t mce_banks_ce_disabled;
 
 #ifdef CONFIG_X86_MCE_INTEL
 unsigned long mce_intel_adjust_timer(unsigned long interval);
 void mce_intel_cmci_poll(void);
 void mce_intel_hcpu_update(unsigned long cpu);
+void cmci_disable_bank(int bank);
 #else
 # define mce_intel_adjust_timer mce_adjust_timer_default
 static inline void mce_intel_cmci_poll(void) { }
 static inline void mce_intel_hcpu_update(unsigned long cpu) { }
+static inline void cmci_disable_bank(int bank) { }
 #endif
 
 void mce_timer_kick(unsigned long interval);
index 87a65c939bcdb27c61c636804646c941b2ba892a..b3218cdee95f43a14ce2681e8a339e2cca28bcaa 100644 (file)
@@ -97,6 +97,15 @@ DEFINE_PER_CPU(mce_banks_t, mce_poll_banks) = {
        [0 ... BITS_TO_LONGS(MAX_NR_BANKS)-1] = ~0UL
 };
 
+/*
+ * MCA banks controlled through firmware first for corrected errors.
+ * This is a global list of banks for which we won't enable CMCI and we
+ * won't poll. Firmware controls these banks and is responsible for
+ * reporting corrected errors through GHES. Uncorrected/recoverable
+ * errors are still notified through a machine check.
+ */
+mce_banks_t mce_banks_ce_disabled;
+
 static DEFINE_PER_CPU(struct work_struct, mce_work);
 
 static void (*quirk_no_way_out)(int bank, struct mce *m, struct pt_regs *regs);
@@ -1935,6 +1944,25 @@ static struct miscdevice mce_chrdev_device = {
        &mce_chrdev_ops,
 };
 
+static void __mce_disable_bank(void *arg)
+{
+       int bank = *((int *)arg);
+       __clear_bit(bank, __get_cpu_var(mce_poll_banks));
+       cmci_disable_bank(bank);
+}
+
+void mce_disable_bank(int bank)
+{
+       if (bank >= mca_cfg.banks) {
+               pr_warn(FW_BUG
+                       "Ignoring request to disable invalid MCA bank %d.\n",
+                       bank);
+               return;
+       }
+       set_bit(bank, mce_banks_ce_disabled);
+       on_each_cpu(__mce_disable_bank, &bank, 1);
+}
+
 /*
  * mce=off Disables machine check
  * mce=no_cmci Disables CMCI
index d56405309dc16a3a5deb9798ff2b0656f1afc0e1..4cfe0458ca665a5311cc57512f121878e616ea9f 100644 (file)
@@ -203,6 +203,10 @@ static void cmci_discover(int banks)
                if (test_bit(i, owned))
                        continue;
 
+               /* Skip banks in firmware first mode */
+               if (test_bit(i, mce_banks_ce_disabled))
+                       continue;
+
                rdmsrl(MSR_IA32_MCx_CTL2(i), val);
 
                /* Already owned by someone else? */
@@ -271,6 +275,19 @@ void cmci_recheck(void)
        local_irq_restore(flags);
 }
 
+/* Caller must hold the lock on cmci_discover_lock */
+static void __cmci_disable_bank(int bank)
+{
+       u64 val;
+
+       if (!test_bit(bank, __get_cpu_var(mce_banks_owned)))
+               return;
+       rdmsrl(MSR_IA32_MCx_CTL2(bank), val);
+       val &= ~MCI_CTL2_CMCI_EN;
+       wrmsrl(MSR_IA32_MCx_CTL2(bank), val);
+       __clear_bit(bank, __get_cpu_var(mce_banks_owned));
+}
+
 /*
  * Disable CMCI on this CPU for all banks it owns when it goes down.
  * This allows other CPUs to claim the banks on rediscovery.
@@ -280,20 +297,12 @@ void cmci_clear(void)
        unsigned long flags;
        int i;
        int banks;
-       u64 val;
 
        if (!cmci_supported(&banks))
                return;
        raw_spin_lock_irqsave(&cmci_discover_lock, flags);
-       for (i = 0; i < banks; i++) {
-               if (!test_bit(i, __get_cpu_var(mce_banks_owned)))
-                       continue;
-               /* Disable CMCI */
-               rdmsrl(MSR_IA32_MCx_CTL2(i), val);
-               val &= ~MCI_CTL2_CMCI_EN;
-               wrmsrl(MSR_IA32_MCx_CTL2(i), val);
-               __clear_bit(i, __get_cpu_var(mce_banks_owned));
-       }
+       for (i = 0; i < banks; i++)
+               __cmci_disable_bank(i);
        raw_spin_unlock_irqrestore(&cmci_discover_lock, flags);
 }
 
@@ -327,6 +336,19 @@ void cmci_reenable(void)
                cmci_discover(banks);
 }
 
+void cmci_disable_bank(int bank)
+{
+       int banks;
+       unsigned long flags;
+
+       if (!cmci_supported(&banks))
+               return;
+
+       raw_spin_lock_irqsave(&cmci_discover_lock, flags);
+       __cmci_disable_bank(bank);
+       raw_spin_unlock_irqrestore(&cmci_discover_lock, flags);
+}
+
 static void intel_init_cmci(void)
 {
        int banks;
index a7c7305030cc6c9600a601c1dd51f19560ac3830..8355c84b9729df767945c5f4c8a5f7c5db15fab8 100644 (file)
@@ -1884,6 +1884,7 @@ static struct pmu pmu = {
 void arch_perf_update_userpage(struct perf_event_mmap_page *userpg, u64 now)
 {
        userpg->cap_usr_time = 0;
+       userpg->cap_usr_time_zero = 0;
        userpg->cap_usr_rdpmc = x86_pmu.attr_rdpmc;
        userpg->pmc_width = x86_pmu.cntval_bits;
 
@@ -1897,6 +1898,11 @@ void arch_perf_update_userpage(struct perf_event_mmap_page *userpg, u64 now)
        userpg->time_mult = this_cpu_read(cyc2ns);
        userpg->time_shift = CYC2NS_SCALE_FACTOR;
        userpg->time_offset = this_cpu_read(cyc2ns_offset) - now;
+
+       if (sched_clock_stable && !check_tsc_disabled()) {
+               userpg->cap_usr_time_zero = 1;
+               userpg->time_zero = this_cpu_read(cyc2ns_offset);
+       }
 }
 
 /*
index 69eb2fa254942e23537266c4e8a4d0a77c7ee04f..376dc7873447c80e27b8b765e6ff41a8f737da8a 100644 (file)
@@ -52,8 +52,7 @@ void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
-void __init early_init_dt_setup_initrd_arch(unsigned long start,
-                                           unsigned long end)
+void __init early_init_dt_setup_initrd_arch(u64 start, u64 end)
 {
        initrd_start = (unsigned long)__va(start);
        initrd_end = (unsigned long)__va(end);
index 94ab6b90dd3fabdaf2856a5d7fc2abfd4ed2af88..63bdb29b25497edfb0a97ec7cfb9aa5b746d200a 100644 (file)
@@ -196,15 +196,23 @@ static void __init ati_bugs_contd(int num, int slot, int func)
 static void __init intel_remapping_check(int num, int slot, int func)
 {
        u8 revision;
+       u16 device;
 
+       device = read_pci_config_16(num, slot, func, PCI_DEVICE_ID);
        revision = read_pci_config_byte(num, slot, func, PCI_REVISION_ID);
 
        /*
-        * Revision 0x13 of this chipset supports irq remapping
-        * but has an erratum that breaks its behavior, flag it as such
+        * Revision 13 of all triggering devices id in this quirk have
+        * a problem draining interrupts when irq remapping is enabled,
+        * and should be flagged as broken.  Additionally revisions 0x12
+        * and 0x22 of device id 0x3405 has this problem.
         */
        if (revision == 0x13)
                set_irq_remapping_broken();
+       else if ((device == 0x3405) &&
+           ((revision == 0x12) ||
+            (revision == 0x22)))
+               set_irq_remapping_broken();
 
 }
 
@@ -239,6 +247,8 @@ static struct chipset early_qrk[] __initdata = {
          PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, ati_bugs_contd },
        { PCI_VENDOR_ID_INTEL, 0x3403, PCI_CLASS_BRIDGE_HOST,
          PCI_BASE_CLASS_BRIDGE, 0, intel_remapping_check },
+       { PCI_VENDOR_ID_INTEL, 0x3405, PCI_CLASS_BRIDGE_HOST,
+         PCI_BASE_CLASS_BRIDGE, 0, intel_remapping_check },
        { PCI_VENDOR_ID_INTEL, 0x3406, PCI_CLASS_BRIDGE_HOST,
          PCI_BASE_CLASS_BRIDGE, 0, intel_remapping_check },
        {}
index 5dd87a89f011d89d5098fc582e794c5250fce3dd..81ba27679f18ec6100bd167c3739608631a7c475 100644 (file)
@@ -409,6 +409,7 @@ enable_paging:
 /*
  * Check if it is 486
  */
+       movb $4,X86                     # at least 486
        cmpl $-1,X86_CPUID
        je is486
 
@@ -436,7 +437,6 @@ enable_paging:
        movl %edx,X86_CAPABILITY
 
 is486:
-       movb $4,X86
        movl $0x50022,%ecx      # set AM, WP, NE and MP
        movl %cr0,%eax
        andl $0x80000011,%eax   # Save PG,PE,ET
index 202d24f0f7e70546a2020212b97fb450e41cc9c5..5d576ab344030832617450ac2330d63f135596a4 100644 (file)
@@ -116,7 +116,7 @@ static void mxcsr_feature_mask_init(void)
 
        if (cpu_has_fxsr) {
                memset(&fx_scratch, 0, sizeof(struct i387_fxsave_struct));
-               asm volatile("fxsave %0" : : "m" (fx_scratch));
+               asm volatile("fxsave %0" : "+m" (fx_scratch));
                mask = fx_scratch.mxcsr_mask;
                if (mask == 0)
                        mask = 0x0000ffbf;
index 2889b3d438823ea58d6796355e08fb081c1896f7..460f5d9ceebb65c5337a6d3b57edbad7925b8c1a 100644 (file)
@@ -37,7 +37,19 @@ static void __jump_label_transform(struct jump_entry *entry,
        } else
                memcpy(&code, ideal_nops[NOP_ATOMIC5], JUMP_LABEL_NOP_SIZE);
 
-       (*poker)((void *)entry->code, &code, JUMP_LABEL_NOP_SIZE);
+       /*
+        * Make text_poke_bp() a default fallback poker.
+        *
+        * At the time the change is being done, just ignore whether we
+        * are doing nop -> jump or jump -> nop transition, and assume
+        * always nop being the 'currently valid' instruction
+        *
+        */
+       if (poker)
+               (*poker)((void *)entry->code, &code, JUMP_LABEL_NOP_SIZE);
+       else
+               text_poke_bp((void *)entry->code, &code, JUMP_LABEL_NOP_SIZE,
+                            (void *)entry->code + JUMP_LABEL_NOP_SIZE);
 }
 
 void arch_jump_label_transform(struct jump_entry *entry,
@@ -45,7 +57,7 @@ void arch_jump_label_transform(struct jump_entry *entry,
 {
        get_online_cpus();
        mutex_lock(&text_mutex);
-       __jump_label_transform(entry, type, text_poke_smp);
+       __jump_label_transform(entry, type, NULL);
        mutex_unlock(&text_mutex);
        put_online_cpus();
 }
index 2e9d4b5af036abf5a86868cb706e479df3911d23..c6ee63f927ab721dd542b016bcfb22d65a55f114 100644 (file)
@@ -82,14 +82,9 @@ extern void synthesize_reljump(void *from, void *to);
 extern void synthesize_relcall(void *from, void *to);
 
 #ifdef CONFIG_OPTPROBES
-extern int arch_init_optprobes(void);
 extern int setup_detour_execution(struct kprobe *p, struct pt_regs *regs, int reenter);
 extern unsigned long __recover_optprobed_insn(kprobe_opcode_t *buf, unsigned long addr);
 #else  /* !CONFIG_OPTPROBES */
-static inline int arch_init_optprobes(void)
-{
-       return 0;
-}
 static inline int setup_detour_execution(struct kprobe *p, struct pt_regs *regs, int reenter)
 {
        return 0;
index 211bce445522d541cc1bcc05e44e401b376f8093..cd49b2c96d32f9ede4bc47fa2c67f04803a78db7 100644 (file)
@@ -1068,7 +1068,7 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
 
 int __init arch_init_kprobes(void)
 {
-       return arch_init_optprobes();
+       return 0;
 }
 
 int __kprobes arch_trampoline_kprobe(struct kprobe *p)
index 76dc6f09572466426268955fbb11fdc845dca040..d71e994393760bca98efb30663f6bb5082b213c8 100644 (file)
@@ -371,31 +371,6 @@ int __kprobes arch_prepare_optimized_kprobe(struct optimized_kprobe *op)
        return 0;
 }
 
-#define MAX_OPTIMIZE_PROBES 256
-static struct text_poke_param *jump_poke_params;
-static struct jump_poke_buffer {
-       u8 buf[RELATIVEJUMP_SIZE];
-} *jump_poke_bufs;
-
-static void __kprobes setup_optimize_kprobe(struct text_poke_param *tprm,
-                                           u8 *insn_buf,
-                                           struct optimized_kprobe *op)
-{
-       s32 rel = (s32)((long)op->optinsn.insn -
-                       ((long)op->kp.addr + RELATIVEJUMP_SIZE));
-
-       /* Backup instructions which will be replaced by jump address */
-       memcpy(op->optinsn.copied_insn, op->kp.addr + INT3_SIZE,
-              RELATIVE_ADDR_SIZE);
-
-       insn_buf[0] = RELATIVEJUMP_OPCODE;
-       *(s32 *)(&insn_buf[1]) = rel;
-
-       tprm->addr = op->kp.addr;
-       tprm->opcode = insn_buf;
-       tprm->len = RELATIVEJUMP_SIZE;
-}
-
 /*
  * Replace breakpoints (int3) with relative jumps.
  * Caller must call with locking kprobe_mutex and text_mutex.
@@ -403,37 +378,38 @@ static void __kprobes setup_optimize_kprobe(struct text_poke_param *tprm,
 void __kprobes arch_optimize_kprobes(struct list_head *oplist)
 {
        struct optimized_kprobe *op, *tmp;
-       int c = 0;
+       u8 insn_buf[RELATIVEJUMP_SIZE];
 
        list_for_each_entry_safe(op, tmp, oplist, list) {
+               s32 rel = (s32)((long)op->optinsn.insn -
+                       ((long)op->kp.addr + RELATIVEJUMP_SIZE));
+
                WARN_ON(kprobe_disabled(&op->kp));
-               /* Setup param */
-               setup_optimize_kprobe(&jump_poke_params[c],
-                                     jump_poke_bufs[c].buf, op);
+
+               /* Backup instructions which will be replaced by jump address */
+               memcpy(op->optinsn.copied_insn, op->kp.addr + INT3_SIZE,
+                      RELATIVE_ADDR_SIZE);
+
+               insn_buf[0] = RELATIVEJUMP_OPCODE;
+               *(s32 *)(&insn_buf[1]) = rel;
+
+               text_poke_bp(op->kp.addr, insn_buf, RELATIVEJUMP_SIZE,
+                            op->optinsn.insn);
+
                list_del_init(&op->list);
-               if (++c >= MAX_OPTIMIZE_PROBES)
-                       break;
        }
-
-       /*
-        * text_poke_smp doesn't support NMI/MCE code modifying.
-        * However, since kprobes itself also doesn't support NMI/MCE
-        * code probing, it's not a problem.
-        */
-       text_poke_smp_batch(jump_poke_params, c);
 }
 
-static void __kprobes setup_unoptimize_kprobe(struct text_poke_param *tprm,
-                                             u8 *insn_buf,
-                                             struct optimized_kprobe *op)
+/* Replace a relative jump with a breakpoint (int3).  */
+void __kprobes arch_unoptimize_kprobe(struct optimized_kprobe *op)
 {
+       u8 insn_buf[RELATIVEJUMP_SIZE];
+
        /* Set int3 to first byte for kprobes */
        insn_buf[0] = BREAKPOINT_INSTRUCTION;
        memcpy(insn_buf + 1, op->optinsn.copied_insn, RELATIVE_ADDR_SIZE);
-
-       tprm->addr = op->kp.addr;
-       tprm->opcode = insn_buf;
-       tprm->len = RELATIVEJUMP_SIZE;
+       text_poke_bp(op->kp.addr, insn_buf, RELATIVEJUMP_SIZE,
+                    op->optinsn.insn);
 }
 
 /*
@@ -444,34 +420,11 @@ extern void arch_unoptimize_kprobes(struct list_head *oplist,
                                    struct list_head *done_list)
 {
        struct optimized_kprobe *op, *tmp;
-       int c = 0;
 
        list_for_each_entry_safe(op, tmp, oplist, list) {
-               /* Setup param */
-               setup_unoptimize_kprobe(&jump_poke_params[c],
-                                       jump_poke_bufs[c].buf, op);
+               arch_unoptimize_kprobe(op);
                list_move(&op->list, done_list);
-               if (++c >= MAX_OPTIMIZE_PROBES)
-                       break;
        }
-
-       /*
-        * text_poke_smp doesn't support NMI/MCE code modifying.
-        * However, since kprobes itself also doesn't support NMI/MCE
-        * code probing, it's not a problem.
-        */
-       text_poke_smp_batch(jump_poke_params, c);
-}
-
-/* Replace a relative jump with a breakpoint (int3).  */
-void __kprobes arch_unoptimize_kprobe(struct optimized_kprobe *op)
-{
-       u8 buf[RELATIVEJUMP_SIZE];
-
-       /* Set int3 to first byte for kprobes */
-       buf[0] = BREAKPOINT_INSTRUCTION;
-       memcpy(buf + 1, op->optinsn.copied_insn, RELATIVE_ADDR_SIZE);
-       text_poke_smp(op->kp.addr, buf, RELATIVEJUMP_SIZE);
 }
 
 int  __kprobes
@@ -491,22 +444,3 @@ setup_detour_execution(struct kprobe *p, struct pt_regs *regs, int reenter)
        }
        return 0;
 }
-
-int __kprobes arch_init_optprobes(void)
-{
-       /* Allocate code buffer and parameter array */
-       jump_poke_bufs = kmalloc(sizeof(struct jump_poke_buffer) *
-                                MAX_OPTIMIZE_PROBES, GFP_KERNEL);
-       if (!jump_poke_bufs)
-               return -ENOMEM;
-
-       jump_poke_params = kmalloc(sizeof(struct text_poke_param) *
-                                  MAX_OPTIMIZE_PROBES, GFP_KERNEL);
-       if (!jump_poke_params) {
-               kfree(jump_poke_bufs);
-               jump_poke_bufs = NULL;
-               return -ENOMEM;
-       }
-
-       return 0;
-}
index 2cb9470ea85bac67b42c1fb6decdd26c35230041..a16bae3f83b37ab189dbe2a443f1461a075a6ae7 100644 (file)
@@ -128,46 +128,7 @@ void pvclock_read_wallclock(struct pvclock_wall_clock *wall_clock,
        set_normalized_timespec(ts, now.tv_sec, now.tv_nsec);
 }
 
-static struct pvclock_vsyscall_time_info *pvclock_vdso_info;
-
-static struct pvclock_vsyscall_time_info *
-pvclock_get_vsyscall_user_time_info(int cpu)
-{
-       if (!pvclock_vdso_info) {
-               BUG();
-               return NULL;
-       }
-
-       return &pvclock_vdso_info[cpu];
-}
-
-struct pvclock_vcpu_time_info *pvclock_get_vsyscall_time_info(int cpu)
-{
-       return &pvclock_get_vsyscall_user_time_info(cpu)->pvti;
-}
-
 #ifdef CONFIG_X86_64
-static int pvclock_task_migrate(struct notifier_block *nb, unsigned long l,
-                               void *v)
-{
-       struct task_migration_notifier *mn = v;
-       struct pvclock_vsyscall_time_info *pvti;
-
-       pvti = pvclock_get_vsyscall_user_time_info(mn->from_cpu);
-
-       /* this is NULL when pvclock vsyscall is not initialized */
-       if (unlikely(pvti == NULL))
-               return NOTIFY_DONE;
-
-       pvti->migrate_count++;
-
-       return NOTIFY_DONE;
-}
-
-static struct notifier_block pvclock_migrate = {
-       .notifier_call = pvclock_task_migrate,
-};
-
 /*
  * Initialize the generic pvclock vsyscall state.  This will allocate
  * a/some page(s) for the per-vcpu pvclock information, set up a
@@ -181,17 +142,12 @@ int __init pvclock_init_vsyscall(struct pvclock_vsyscall_time_info *i,
 
        WARN_ON (size != PVCLOCK_VSYSCALL_NR_PAGES*PAGE_SIZE);
 
-       pvclock_vdso_info = i;
-
        for (idx = 0; idx <= (PVCLOCK_FIXMAP_END-PVCLOCK_FIXMAP_BEGIN); idx++) {
                __set_fixmap(PVCLOCK_FIXMAP_BEGIN + idx,
                             __pa(i) + (idx*PAGE_SIZE),
                             PAGE_KERNEL_VVAR);
        }
 
-
-       register_task_migration_notifier(&pvclock_migrate);
-
        return 0;
 }
 #endif
index 1b23a1c9274696f108dcf2ad2482445523930de0..8c8093b146ca7cc565c48cb7ba66ca89deb06f9a 100644 (file)
@@ -58,6 +58,7 @@
 #include <asm/mce.h>
 #include <asm/fixmap.h>
 #include <asm/mach_traps.h>
+#include <asm/alternative.h>
 
 #ifdef CONFIG_X86_64
 #include <asm/x86_init.h>
@@ -327,6 +328,9 @@ dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_co
            ftrace_int3_handler(regs))
                return;
 #endif
+       if (poke_int3_handler(regs))
+               return;
+
        prev_state = exception_enter();
 #ifdef CONFIG_KGDB_LOW_LEVEL_TRAP
        if (kgdb_ll_trap(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP,
index 6ff49247edf8f1e67bbd24dd15e34685bcafb010..930e5d48f560d017afd88f2af1bbf2d368dd1209 100644 (file)
@@ -89,6 +89,12 @@ int check_tsc_unstable(void)
 }
 EXPORT_SYMBOL_GPL(check_tsc_unstable);
 
+int check_tsc_disabled(void)
+{
+       return tsc_disabled;
+}
+EXPORT_SYMBOL_GPL(check_tsc_disabled);
+
 #ifdef CONFIG_X86_TSC
 int __init notsc_setup(char *str)
 {
index afc11245827cf2f39b56d14d50dacd6ea9aeb374..c98f05442325e10284f03c5c8213a7c43d1cc7d1 100644 (file)
@@ -79,16 +79,6 @@ static inline void apic_set_reg(struct kvm_lapic *apic, int reg_off, u32 val)
        *((u32 *) (apic->regs + reg_off)) = val;
 }
 
-static inline int apic_test_and_set_vector(int vec, void *bitmap)
-{
-       return test_and_set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
-}
-
-static inline int apic_test_and_clear_vector(int vec, void *bitmap)
-{
-       return test_and_clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
-}
-
 static inline int apic_test_vector(int vec, void *bitmap)
 {
        return test_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
@@ -331,10 +321,10 @@ void kvm_apic_update_irr(struct kvm_vcpu *vcpu, u32 *pir)
 }
 EXPORT_SYMBOL_GPL(kvm_apic_update_irr);
 
-static inline int apic_test_and_set_irr(int vec, struct kvm_lapic *apic)
+static inline void apic_set_irr(int vec, struct kvm_lapic *apic)
 {
        apic->irr_pending = true;
-       return apic_test_and_set_vector(vec, apic->regs + APIC_IRR);
+       apic_set_vector(vec, apic->regs + APIC_IRR);
 }
 
 static inline int apic_search_irr(struct kvm_lapic *apic)
@@ -681,28 +671,21 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
                if (unlikely(!apic_enabled(apic)))
                        break;
 
+               result = 1;
+
                if (dest_map)
                        __set_bit(vcpu->vcpu_id, dest_map);
 
-               if (kvm_x86_ops->deliver_posted_interrupt) {
-                       result = 1;
+               if (kvm_x86_ops->deliver_posted_interrupt)
                        kvm_x86_ops->deliver_posted_interrupt(vcpu, vector);
-               } else {
-                       result = !apic_test_and_set_irr(vector, apic);
-
-                       if (!result) {
-                               if (trig_mode)
-                                       apic_debug("level trig mode repeatedly "
-                                               "for vector %d", vector);
-                               goto out;
-                       }
+               else {
+                       apic_set_irr(vector, apic);
 
                        kvm_make_request(KVM_REQ_EVENT, vcpu);
                        kvm_vcpu_kick(vcpu);
                }
-out:
                trace_kvm_apic_accept_irq(vcpu->vcpu_id, delivery_mode,
-                               trig_mode, vector, !result);
+                                         trig_mode, vector, false);
                break;
 
        case APIC_DM_REMRD:
index 9e9285ae9b946ac1fbcb3b1dfd02159107c0f221..2c1bb95bb93cfd76ae9d2acff6abe6197110c9c2 100644 (file)
@@ -4182,7 +4182,7 @@ int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t cr2, u32 error_code,
        switch (er) {
        case EMULATE_DONE:
                return 1;
-       case EMULATE_DO_MMIO:
+       case EMULATE_USER_EXIT:
                ++vcpu->stat.mmio_exits;
                /* fall through */
        case EMULATE_FAIL:
@@ -4390,11 +4390,8 @@ void kvm_mmu_invalidate_mmio_sptes(struct kvm *kvm)
        /*
         * The very rare case: if the generation-number is round,
         * zap all shadow pages.
-        *
-        * The max value is MMIO_MAX_GEN - 1 since it is not called
-        * when mark memslot invalid.
         */
-       if (unlikely(kvm_current_mmio_generation(kvm) >= (MMIO_MAX_GEN - 1))) {
+       if (unlikely(kvm_current_mmio_generation(kvm) >= MMIO_MAX_GEN)) {
                printk_ratelimited(KERN_INFO "kvm: zapping shadow pages for mmio generation wraparound\n");
                kvm_mmu_invalidate_zap_all_pages(kvm);
        }
index c53e797e7369ad4a1086899ee65eb1e71d048d84..5c4f63151b4d90a405808bda13daa911c5b2a131 100644 (file)
@@ -160,7 +160,7 @@ static void stop_counter(struct kvm_pmc *pmc)
 
 static void reprogram_counter(struct kvm_pmc *pmc, u32 type,
                unsigned config, bool exclude_user, bool exclude_kernel,
-               bool intr)
+               bool intr, bool in_tx, bool in_tx_cp)
 {
        struct perf_event *event;
        struct perf_event_attr attr = {
@@ -173,6 +173,10 @@ static void reprogram_counter(struct kvm_pmc *pmc, u32 type,
                .exclude_kernel = exclude_kernel,
                .config = config,
        };
+       if (in_tx)
+               attr.config |= HSW_IN_TX;
+       if (in_tx_cp)
+               attr.config |= HSW_IN_TX_CHECKPOINTED;
 
        attr.sample_period = (-pmc->counter) & pmc_bitmask(pmc);
 
@@ -226,7 +230,9 @@ static void reprogram_gp_counter(struct kvm_pmc *pmc, u64 eventsel)
 
        if (!(eventsel & (ARCH_PERFMON_EVENTSEL_EDGE |
                                ARCH_PERFMON_EVENTSEL_INV |
-                               ARCH_PERFMON_EVENTSEL_CMASK))) {
+                               ARCH_PERFMON_EVENTSEL_CMASK |
+                               HSW_IN_TX |
+                               HSW_IN_TX_CHECKPOINTED))) {
                config = find_arch_event(&pmc->vcpu->arch.pmu, event_select,
                                unit_mask);
                if (config != PERF_COUNT_HW_MAX)
@@ -239,7 +245,9 @@ static void reprogram_gp_counter(struct kvm_pmc *pmc, u64 eventsel)
        reprogram_counter(pmc, type, config,
                        !(eventsel & ARCH_PERFMON_EVENTSEL_USR),
                        !(eventsel & ARCH_PERFMON_EVENTSEL_OS),
-                       eventsel & ARCH_PERFMON_EVENTSEL_INT);
+                       eventsel & ARCH_PERFMON_EVENTSEL_INT,
+                       (eventsel & HSW_IN_TX),
+                       (eventsel & HSW_IN_TX_CHECKPOINTED));
 }
 
 static void reprogram_fixed_counter(struct kvm_pmc *pmc, u8 en_pmi, int idx)
@@ -256,7 +264,7 @@ static void reprogram_fixed_counter(struct kvm_pmc *pmc, u8 en_pmi, int idx)
                        arch_events[fixed_pmc_events[idx]].event_type,
                        !(en & 0x2), /* exclude user */
                        !(en & 0x1), /* exclude kernel */
-                       pmi);
+                       pmi, false, false);
 }
 
 static inline u8 fixed_en_pmi(u64 ctrl, int idx)
@@ -408,7 +416,7 @@ int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                } else if ((pmc = get_gp_pmc(pmu, index, MSR_P6_EVNTSEL0))) {
                        if (data == pmc->eventsel)
                                return 0;
-                       if (!(data & 0xffffffff00200000ull)) {
+                       if (!(data & pmu->reserved_bits)) {
                                reprogram_gp_counter(pmc, data);
                                return 0;
                        }
@@ -450,6 +458,7 @@ void kvm_pmu_cpuid_update(struct kvm_vcpu *vcpu)
        pmu->counter_bitmask[KVM_PMC_GP] = 0;
        pmu->counter_bitmask[KVM_PMC_FIXED] = 0;
        pmu->version = 0;
+       pmu->reserved_bits = 0xffffffff00200000ull;
 
        entry = kvm_find_cpuid_entry(vcpu, 0xa, 0);
        if (!entry)
@@ -478,6 +487,12 @@ void kvm_pmu_cpuid_update(struct kvm_vcpu *vcpu)
        pmu->global_ctrl = ((1 << pmu->nr_arch_gp_counters) - 1) |
                (((1ull << pmu->nr_arch_fixed_counters) - 1) << INTEL_PMC_IDX_FIXED);
        pmu->global_ctrl_mask = ~pmu->global_ctrl;
+
+       entry = kvm_find_cpuid_entry(vcpu, 7, 0);
+       if (entry &&
+           (boot_cpu_has(X86_FEATURE_HLE) || boot_cpu_has(X86_FEATURE_RTM)) &&
+           (entry->ebx & (X86_FEATURE_HLE|X86_FEATURE_RTM)))
+               pmu->reserved_bits ^= HSW_IN_TX|HSW_IN_TX_CHECKPOINTED;
 }
 
 void kvm_pmu_init(struct kvm_vcpu *vcpu)
index 064d0be67ecc23734aa465541138d9b5be295277..45fd70cef88ea73834323d5c76d46e7a59bc7582 100644 (file)
@@ -373,6 +373,7 @@ struct nested_vmx {
         * we must keep them pinned while L2 runs.
         */
        struct page *apic_access_page;
+       u64 msr_ia32_feature_control;
 };
 
 #define POSTED_INTR_ON  0
@@ -2282,8 +2283,11 @@ static int vmx_get_vmx_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
 
        switch (msr_index) {
        case MSR_IA32_FEATURE_CONTROL:
-               *pdata = 0;
-               break;
+               if (nested_vmx_allowed(vcpu)) {
+                       *pdata = to_vmx(vcpu)->nested.msr_ia32_feature_control;
+                       break;
+               }
+               return 0;
        case MSR_IA32_VMX_BASIC:
                /*
                 * This MSR reports some information about VMX support. We
@@ -2356,14 +2360,24 @@ static int vmx_get_vmx_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
        return 1;
 }
 
-static int vmx_set_vmx_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
+static int vmx_set_vmx_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 {
+       u32 msr_index = msr_info->index;
+       u64 data = msr_info->data;
+       bool host_initialized = msr_info->host_initiated;
+
        if (!nested_vmx_allowed(vcpu))
                return 0;
 
-       if (msr_index == MSR_IA32_FEATURE_CONTROL)
-               /* TODO: the right thing. */
+       if (msr_index == MSR_IA32_FEATURE_CONTROL) {
+               if (!host_initialized &&
+                               to_vmx(vcpu)->nested.msr_ia32_feature_control
+                               & FEATURE_CONTROL_LOCKED)
+                       return 0;
+               to_vmx(vcpu)->nested.msr_ia32_feature_control = data;
                return 1;
+       }
+
        /*
         * No need to treat VMX capability MSRs specially: If we don't handle
         * them, handle_wrmsr will #GP(0), which is correct (they are readonly)
@@ -2494,7 +2508,7 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                        return 1;
                /* Otherwise falls through */
        default:
-               if (vmx_set_vmx_msr(vcpu, msr_index, data))
+               if (vmx_set_vmx_msr(vcpu, msr_info))
                        break;
                msr = find_msr_entry(vmx, msr_index);
                if (msr) {
@@ -5438,7 +5452,7 @@ static int handle_invalid_guest_state(struct kvm_vcpu *vcpu)
 
                err = emulate_instruction(vcpu, EMULTYPE_NO_REEXECUTE);
 
-               if (err == EMULATE_DO_MMIO) {
+               if (err == EMULATE_USER_EXIT) {
                        ret = 0;
                        goto out;
                }
@@ -5567,8 +5581,47 @@ static void nested_free_all_saved_vmcss(struct vcpu_vmx *vmx)
                free_loaded_vmcs(&vmx->vmcs01);
 }
 
+/*
+ * The following 3 functions, nested_vmx_succeed()/failValid()/failInvalid(),
+ * set the success or error code of an emulated VMX instruction, as specified
+ * by Vol 2B, VMX Instruction Reference, "Conventions".
+ */
+static void nested_vmx_succeed(struct kvm_vcpu *vcpu)
+{
+       vmx_set_rflags(vcpu, vmx_get_rflags(vcpu)
+                       & ~(X86_EFLAGS_CF | X86_EFLAGS_PF | X86_EFLAGS_AF |
+                           X86_EFLAGS_ZF | X86_EFLAGS_SF | X86_EFLAGS_OF));
+}
+
+static void nested_vmx_failInvalid(struct kvm_vcpu *vcpu)
+{
+       vmx_set_rflags(vcpu, (vmx_get_rflags(vcpu)
+                       & ~(X86_EFLAGS_PF | X86_EFLAGS_AF | X86_EFLAGS_ZF |
+                           X86_EFLAGS_SF | X86_EFLAGS_OF))
+                       | X86_EFLAGS_CF);
+}
+
 static void nested_vmx_failValid(struct kvm_vcpu *vcpu,
-                                u32 vm_instruction_error);
+                                       u32 vm_instruction_error)
+{
+       if (to_vmx(vcpu)->nested.current_vmptr == -1ull) {
+               /*
+                * failValid writes the error number to the current VMCS, which
+                * can't be done there isn't a current VMCS.
+                */
+               nested_vmx_failInvalid(vcpu);
+               return;
+       }
+       vmx_set_rflags(vcpu, (vmx_get_rflags(vcpu)
+                       & ~(X86_EFLAGS_CF | X86_EFLAGS_PF | X86_EFLAGS_AF |
+                           X86_EFLAGS_SF | X86_EFLAGS_OF))
+                       | X86_EFLAGS_ZF);
+       get_vmcs12(vcpu)->vm_instruction_error = vm_instruction_error;
+       /*
+        * We don't need to force a shadow sync because
+        * VM_INSTRUCTION_ERROR is not shadowed
+        */
+}
 
 /*
  * Emulate the VMXON instruction.
@@ -5583,6 +5636,8 @@ static int handle_vmon(struct kvm_vcpu *vcpu)
        struct kvm_segment cs;
        struct vcpu_vmx *vmx = to_vmx(vcpu);
        struct vmcs *shadow_vmcs;
+       const u64 VMXON_NEEDED_FEATURES = FEATURE_CONTROL_LOCKED
+               | FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX;
 
        /* The Intel VMX Instruction Reference lists a bunch of bits that
         * are prerequisite to running VMXON, most notably cr4.VMXE must be
@@ -5611,6 +5666,13 @@ static int handle_vmon(struct kvm_vcpu *vcpu)
                skip_emulated_instruction(vcpu);
                return 1;
        }
+
+       if ((vmx->nested.msr_ia32_feature_control & VMXON_NEEDED_FEATURES)
+                       != VMXON_NEEDED_FEATURES) {
+               kvm_inject_gp(vcpu, 0);
+               return 1;
+       }
+
        if (enable_shadow_vmcs) {
                shadow_vmcs = alloc_vmcs();
                if (!shadow_vmcs)
@@ -5628,6 +5690,7 @@ static int handle_vmon(struct kvm_vcpu *vcpu)
        vmx->nested.vmxon = true;
 
        skip_emulated_instruction(vcpu);
+       nested_vmx_succeed(vcpu);
        return 1;
 }
 
@@ -5712,6 +5775,7 @@ static int handle_vmoff(struct kvm_vcpu *vcpu)
                return 1;
        free_nested(to_vmx(vcpu));
        skip_emulated_instruction(vcpu);
+       nested_vmx_succeed(vcpu);
        return 1;
 }
 
@@ -5768,48 +5832,6 @@ static int get_vmx_mem_address(struct kvm_vcpu *vcpu,
        return 0;
 }
 
-/*
- * The following 3 functions, nested_vmx_succeed()/failValid()/failInvalid(),
- * set the success or error code of an emulated VMX instruction, as specified
- * by Vol 2B, VMX Instruction Reference, "Conventions".
- */
-static void nested_vmx_succeed(struct kvm_vcpu *vcpu)
-{
-       vmx_set_rflags(vcpu, vmx_get_rflags(vcpu)
-                       & ~(X86_EFLAGS_CF | X86_EFLAGS_PF | X86_EFLAGS_AF |
-                           X86_EFLAGS_ZF | X86_EFLAGS_SF | X86_EFLAGS_OF));
-}
-
-static void nested_vmx_failInvalid(struct kvm_vcpu *vcpu)
-{
-       vmx_set_rflags(vcpu, (vmx_get_rflags(vcpu)
-                       & ~(X86_EFLAGS_PF | X86_EFLAGS_AF | X86_EFLAGS_ZF |
-                           X86_EFLAGS_SF | X86_EFLAGS_OF))
-                       | X86_EFLAGS_CF);
-}
-
-static void nested_vmx_failValid(struct kvm_vcpu *vcpu,
-                                       u32 vm_instruction_error)
-{
-       if (to_vmx(vcpu)->nested.current_vmptr == -1ull) {
-               /*
-                * failValid writes the error number to the current VMCS, which
-                * can't be done there isn't a current VMCS.
-                */
-               nested_vmx_failInvalid(vcpu);
-               return;
-       }
-       vmx_set_rflags(vcpu, (vmx_get_rflags(vcpu)
-                       & ~(X86_EFLAGS_CF | X86_EFLAGS_PF | X86_EFLAGS_AF |
-                           X86_EFLAGS_SF | X86_EFLAGS_OF))
-                       | X86_EFLAGS_ZF);
-       get_vmcs12(vcpu)->vm_instruction_error = vm_instruction_error;
-       /*
-        * We don't need to force a shadow sync because
-        * VM_INSTRUCTION_ERROR is not shadowed
-        */
-}
-
 /* Emulate the VMCLEAR instruction */
 static int handle_vmclear(struct kvm_vcpu *vcpu)
 {
@@ -5972,8 +5994,8 @@ static void copy_shadow_to_vmcs12(struct vcpu_vmx *vmx)
        unsigned long field;
        u64 field_value;
        struct vmcs *shadow_vmcs = vmx->nested.current_shadow_vmcs;
-       unsigned long *fields = (unsigned long *)shadow_read_write_fields;
-       int num_fields = max_shadow_read_write_fields;
+       const unsigned long *fields = shadow_read_write_fields;
+       const int num_fields = max_shadow_read_write_fields;
 
        vmcs_load(shadow_vmcs);
 
@@ -6002,12 +6024,11 @@ static void copy_shadow_to_vmcs12(struct vcpu_vmx *vmx)
 
 static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx)
 {
-       unsigned long *fields[] = {
-               (unsigned long *)shadow_read_write_fields,
-               (unsigned long *)shadow_read_only_fields
+       const unsigned long *fields[] = {
+               shadow_read_write_fields,
+               shadow_read_only_fields
        };
-       int num_lists =  ARRAY_SIZE(fields);
-       int max_fields[] = {
+       const int max_fields[] = {
                max_shadow_read_write_fields,
                max_shadow_read_only_fields
        };
@@ -6018,7 +6039,7 @@ static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx)
 
        vmcs_load(shadow_vmcs);
 
-       for (q = 0; q < num_lists; q++) {
+       for (q = 0; q < ARRAY_SIZE(fields); q++) {
                for (i = 0; i < max_fields[q]; i++) {
                        field = fields[q][i];
                        vmcs12_read_any(&vmx->vcpu, field, &field_value);
@@ -7948,6 +7969,8 @@ static void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
 static void load_vmcs12_host_state(struct kvm_vcpu *vcpu,
                                   struct vmcs12 *vmcs12)
 {
+       struct kvm_segment seg;
+
        if (vmcs12->vm_exit_controls & VM_EXIT_LOAD_IA32_EFER)
                vcpu->arch.efer = vmcs12->host_ia32_efer;
        else if (vmcs12->vm_exit_controls & VM_EXIT_HOST_ADDR_SPACE_SIZE)
@@ -8001,16 +8024,6 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu,
        vmcs_writel(GUEST_SYSENTER_EIP, vmcs12->host_ia32_sysenter_eip);
        vmcs_writel(GUEST_IDTR_BASE, vmcs12->host_idtr_base);
        vmcs_writel(GUEST_GDTR_BASE, vmcs12->host_gdtr_base);
-       vmcs_writel(GUEST_TR_BASE, vmcs12->host_tr_base);
-       vmcs_writel(GUEST_GS_BASE, vmcs12->host_gs_base);
-       vmcs_writel(GUEST_FS_BASE, vmcs12->host_fs_base);
-       vmcs_write16(GUEST_ES_SELECTOR, vmcs12->host_es_selector);
-       vmcs_write16(GUEST_CS_SELECTOR, vmcs12->host_cs_selector);
-       vmcs_write16(GUEST_SS_SELECTOR, vmcs12->host_ss_selector);
-       vmcs_write16(GUEST_DS_SELECTOR, vmcs12->host_ds_selector);
-       vmcs_write16(GUEST_FS_SELECTOR, vmcs12->host_fs_selector);
-       vmcs_write16(GUEST_GS_SELECTOR, vmcs12->host_gs_selector);
-       vmcs_write16(GUEST_TR_SELECTOR, vmcs12->host_tr_selector);
 
        if (vmcs12->vm_exit_controls & VM_EXIT_LOAD_IA32_PAT)
                vmcs_write64(GUEST_IA32_PAT, vmcs12->host_ia32_pat);
@@ -8018,6 +8031,52 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu,
                vmcs_write64(GUEST_IA32_PERF_GLOBAL_CTRL,
                        vmcs12->host_ia32_perf_global_ctrl);
 
+       /* Set L1 segment info according to Intel SDM
+           27.5.2 Loading Host Segment and Descriptor-Table Registers */
+       seg = (struct kvm_segment) {
+               .base = 0,
+               .limit = 0xFFFFFFFF,
+               .selector = vmcs12->host_cs_selector,
+               .type = 11,
+               .present = 1,
+               .s = 1,
+               .g = 1
+       };
+       if (vmcs12->vm_exit_controls & VM_EXIT_HOST_ADDR_SPACE_SIZE)
+               seg.l = 1;
+       else
+               seg.db = 1;
+       vmx_set_segment(vcpu, &seg, VCPU_SREG_CS);
+       seg = (struct kvm_segment) {
+               .base = 0,
+               .limit = 0xFFFFFFFF,
+               .type = 3,
+               .present = 1,
+               .s = 1,
+               .db = 1,
+               .g = 1
+       };
+       seg.selector = vmcs12->host_ds_selector;
+       vmx_set_segment(vcpu, &seg, VCPU_SREG_DS);
+       seg.selector = vmcs12->host_es_selector;
+       vmx_set_segment(vcpu, &seg, VCPU_SREG_ES);
+       seg.selector = vmcs12->host_ss_selector;
+       vmx_set_segment(vcpu, &seg, VCPU_SREG_SS);
+       seg.selector = vmcs12->host_fs_selector;
+       seg.base = vmcs12->host_fs_base;
+       vmx_set_segment(vcpu, &seg, VCPU_SREG_FS);
+       seg.selector = vmcs12->host_gs_selector;
+       seg.base = vmcs12->host_gs_base;
+       vmx_set_segment(vcpu, &seg, VCPU_SREG_GS);
+       seg = (struct kvm_segment) {
+               .base = 0,
+               .limit = 0x67,
+               .selector = vmcs12->host_tr_selector,
+               .type = 11,
+               .present = 1
+       };
+       vmx_set_segment(vcpu, &seg, VCPU_SREG_TR);
+
        kvm_set_dr(vcpu, 7, 0x400);
        vmcs_write64(GUEST_IA32_DEBUGCTL, 0);
 }
index d21bce5053155535f51d1507f7f38306023eb994..05afd1ac5563c70653faa85da860aed3124ecede 100644 (file)
@@ -850,7 +850,8 @@ static u32 msrs_to_save[] = {
 #ifdef CONFIG_X86_64
        MSR_CSTAR, MSR_KERNEL_GS_BASE, MSR_SYSCALL_MASK, MSR_LSTAR,
 #endif
-       MSR_IA32_TSC, MSR_IA32_CR_PAT, MSR_VM_HSAVE_PA
+       MSR_IA32_TSC, MSR_IA32_CR_PAT, MSR_VM_HSAVE_PA,
+       MSR_IA32_FEATURE_CONTROL
 };
 
 static unsigned num_msrs_to_save;
@@ -4955,6 +4956,97 @@ static bool retry_instruction(struct x86_emulate_ctxt *ctxt,
 static int complete_emulated_mmio(struct kvm_vcpu *vcpu);
 static int complete_emulated_pio(struct kvm_vcpu *vcpu);
 
+static int kvm_vcpu_check_hw_bp(unsigned long addr, u32 type, u32 dr7,
+                               unsigned long *db)
+{
+       u32 dr6 = 0;
+       int i;
+       u32 enable, rwlen;
+
+       enable = dr7;
+       rwlen = dr7 >> 16;
+       for (i = 0; i < 4; i++, enable >>= 2, rwlen >>= 4)
+               if ((enable & 3) && (rwlen & 15) == type && db[i] == addr)
+                       dr6 |= (1 << i);
+       return dr6;
+}
+
+static void kvm_vcpu_check_singlestep(struct kvm_vcpu *vcpu, int *r)
+{
+       struct kvm_run *kvm_run = vcpu->run;
+
+       /*
+        * Use the "raw" value to see if TF was passed to the processor.
+        * Note that the new value of the flags has not been saved yet.
+        *
+        * This is correct even for TF set by the guest, because "the
+        * processor will not generate this exception after the instruction
+        * that sets the TF flag".
+        */
+       unsigned long rflags = kvm_x86_ops->get_rflags(vcpu);
+
+       if (unlikely(rflags & X86_EFLAGS_TF)) {
+               if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
+                       kvm_run->debug.arch.dr6 = DR6_BS | DR6_FIXED_1;
+                       kvm_run->debug.arch.pc = vcpu->arch.singlestep_rip;
+                       kvm_run->debug.arch.exception = DB_VECTOR;
+                       kvm_run->exit_reason = KVM_EXIT_DEBUG;
+                       *r = EMULATE_USER_EXIT;
+               } else {
+                       vcpu->arch.emulate_ctxt.eflags &= ~X86_EFLAGS_TF;
+                       /*
+                        * "Certain debug exceptions may clear bit 0-3.  The
+                        * remaining contents of the DR6 register are never
+                        * cleared by the processor".
+                        */
+                       vcpu->arch.dr6 &= ~15;
+                       vcpu->arch.dr6 |= DR6_BS;
+                       kvm_queue_exception(vcpu, DB_VECTOR);
+               }
+       }
+}
+
+static bool kvm_vcpu_check_breakpoint(struct kvm_vcpu *vcpu, int *r)
+{
+       struct kvm_run *kvm_run = vcpu->run;
+       unsigned long eip = vcpu->arch.emulate_ctxt.eip;
+       u32 dr6 = 0;
+
+       if (unlikely(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP) &&
+           (vcpu->arch.guest_debug_dr7 & DR7_BP_EN_MASK)) {
+               dr6 = kvm_vcpu_check_hw_bp(eip, 0,
+                                          vcpu->arch.guest_debug_dr7,
+                                          vcpu->arch.eff_db);
+
+               if (dr6 != 0) {
+                       kvm_run->debug.arch.dr6 = dr6 | DR6_FIXED_1;
+                       kvm_run->debug.arch.pc = kvm_rip_read(vcpu) +
+                               get_segment_base(vcpu, VCPU_SREG_CS);
+
+                       kvm_run->debug.arch.exception = DB_VECTOR;
+                       kvm_run->exit_reason = KVM_EXIT_DEBUG;
+                       *r = EMULATE_USER_EXIT;
+                       return true;
+               }
+       }
+
+       if (unlikely(vcpu->arch.dr7 & DR7_BP_EN_MASK)) {
+               dr6 = kvm_vcpu_check_hw_bp(eip, 0,
+                                          vcpu->arch.dr7,
+                                          vcpu->arch.db);
+
+               if (dr6 != 0) {
+                       vcpu->arch.dr6 &= ~15;
+                       vcpu->arch.dr6 |= dr6;
+                       kvm_queue_exception(vcpu, DB_VECTOR);
+                       *r = EMULATE_DONE;
+                       return true;
+               }
+       }
+
+       return false;
+}
+
 int x86_emulate_instruction(struct kvm_vcpu *vcpu,
                            unsigned long cr2,
                            int emulation_type,
@@ -4975,6 +5067,16 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu,
 
        if (!(emulation_type & EMULTYPE_NO_DECODE)) {
                init_emulate_ctxt(vcpu);
+
+               /*
+                * We will reenter on the same instruction since
+                * we do not set complete_userspace_io.  This does not
+                * handle watchpoints yet, those would be handled in
+                * the emulate_ops.
+                */
+               if (kvm_vcpu_check_breakpoint(vcpu, &r))
+                       return r;
+
                ctxt->interruptibility = 0;
                ctxt->have_exception = false;
                ctxt->perm_ok = false;
@@ -5037,11 +5139,11 @@ restart:
                        writeback = false;
                        vcpu->arch.complete_userspace_io = complete_emulated_pio;
                }
-               r = EMULATE_DO_MMIO;
+               r = EMULATE_USER_EXIT;
        } else if (vcpu->mmio_needed) {
                if (!vcpu->mmio_is_write)
                        writeback = false;
-               r = EMULATE_DO_MMIO;
+               r = EMULATE_USER_EXIT;
                vcpu->arch.complete_userspace_io = complete_emulated_mmio;
        } else if (r == EMULATION_RESTART)
                goto restart;
@@ -5050,10 +5152,12 @@ restart:
 
        if (writeback) {
                toggle_interruptibility(vcpu, ctxt->interruptibility);
-               kvm_set_rflags(vcpu, ctxt->eflags);
                kvm_make_request(KVM_REQ_EVENT, vcpu);
                vcpu->arch.emulate_regs_need_sync_to_vcpu = false;
                kvm_rip_write(vcpu, ctxt->eip);
+               if (r == EMULATE_DONE)
+                       kvm_vcpu_check_singlestep(vcpu, &r);
+               kvm_set_rflags(vcpu, ctxt->eflags);
        } else
                vcpu->arch.emulate_regs_need_sync_to_vcpu = true;
 
@@ -5347,7 +5451,7 @@ static struct notifier_block pvclock_gtod_notifier = {
 int kvm_arch_init(void *opaque)
 {
        int r;
-       struct kvm_x86_ops *ops = (struct kvm_x86_ops *)opaque;
+       struct kvm_x86_ops *ops = opaque;
 
        if (kvm_x86_ops) {
                printk(KERN_ERR "kvm: already loaded the other module\n");
@@ -7019,6 +7123,15 @@ out_free:
        return -ENOMEM;
 }
 
+void kvm_arch_memslots_updated(struct kvm *kvm)
+{
+       /*
+        * memslots->generation has been incremented.
+        * mmio generation may have reached its maximum value.
+        */
+       kvm_mmu_invalidate_mmio_sptes(kvm);
+}
+
 int kvm_arch_prepare_memory_region(struct kvm *kvm,
                                struct kvm_memory_slot *memslot,
                                struct kvm_userspace_memory_region *mem,
@@ -7079,11 +7192,6 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
         */
        if ((change != KVM_MR_DELETE) && (mem->flags & KVM_MEM_LOG_DIRTY_PAGES))
                kvm_mmu_slot_remove_write_access(kvm, mem->slot);
-       /*
-        * If memory slot is created, or moved, we need to clear all
-        * mmio sptes.
-        */
-       kvm_mmu_invalidate_mmio_sptes(kvm);
 }
 
 void kvm_arch_flush_shadow_all(struct kvm *kvm)
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 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 c74436e687bf8984b722efa1a657e1a6a8b47f3b..72074d5284009a35265580a13eaa99e6f11588b4 100644 (file)
@@ -85,15 +85,18 @@ static notrace cycle_t vread_pvclock(int *mode)
        cycle_t ret;
        u64 last;
        u32 version;
-       u32 migrate_count;
        u8 flags;
        unsigned cpu, cpu1;
 
 
        /*
-        * When looping to get a consistent (time-info, tsc) pair, we
-        * also need to deal with the possibility we can switch vcpus,
-        * so make sure we always re-fetch time-info for the current vcpu.
+        * Note: hypervisor must guarantee that:
+        * 1. cpu ID number maps 1:1 to per-CPU pvclock time info.
+        * 2. that per-CPU pvclock time info is updated if the
+        *    underlying CPU changes.
+        * 3. that version is increased whenever underlying CPU
+        *    changes.
+        *
         */
        do {
                cpu = __getcpu() & VGETCPU_CPU_MASK;
@@ -104,8 +107,6 @@ static notrace cycle_t vread_pvclock(int *mode)
 
                pvti = get_pvti(cpu);
 
-               migrate_count = pvti->migrate_count;
-
                version = __pvclock_read_cycles(&pvti->pvti, &ret, &flags);
 
                /*
@@ -117,8 +118,7 @@ static notrace cycle_t vread_pvclock(int *mode)
                cpu1 = __getcpu() & VGETCPU_CPU_MASK;
        } while (unlikely(cpu != cpu1 ||
                          (pvti->pvti.version & 1) ||
-                         pvti->pvti.version != version ||
-                         pvti->migrate_count != migrate_count));
+                         pvti->pvti.version != version));
 
        if (unlikely(!(flags & PVCLOCK_TSC_STABLE_BIT)))
                *mode = VCLOCK_NONE;
index 42a8bba0b0ead4235add5133b7e849187641da53..101012bc1ff6d4d99ce408ad8614d1f6f3e2322e 100644 (file)
@@ -170,8 +170,7 @@ static int __init parse_tag_fdt(const bp_tag_t *tag)
 
 __tagtable(BP_TAG_FDT, parse_tag_fdt);
 
-void __init early_init_dt_setup_initrd_arch(unsigned long start,
-               unsigned long end)
+void __init early_init_dt_setup_initrd_arch(u64 start, u64 end)
 {
        initrd_start = (void *)__va(start);
        initrd_end = (void *)__va(end);
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 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 ec9b57d428a1e028a0cdf3215e3ebddad9634818..8ec37bbdd6991939107c4bde2a54d3652290f0e6 100644 (file)
@@ -409,6 +409,34 @@ static void ghes_clear_estatus(struct ghes *ghes)
        ghes->flags &= ~GHES_TO_CLEAR;
 }
 
+static void ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, int sev)
+{
+#ifdef CONFIG_ACPI_APEI_MEMORY_FAILURE
+       unsigned long pfn;
+       int sec_sev = ghes_severity(gdata->error_severity);
+       struct cper_sec_mem_err *mem_err;
+       mem_err = (struct cper_sec_mem_err *)(gdata + 1);
+
+       if (sec_sev == GHES_SEV_CORRECTED &&
+           (gdata->flags & CPER_SEC_ERROR_THRESHOLD_EXCEEDED) &&
+           (mem_err->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS)) {
+               pfn = mem_err->physical_addr >> PAGE_SHIFT;
+               if (pfn_valid(pfn))
+                       memory_failure_queue(pfn, 0, MF_SOFT_OFFLINE);
+               else if (printk_ratelimit())
+                       pr_warn(FW_WARN GHES_PFX
+                       "Invalid address in generic error data: %#llx\n",
+                       mem_err->physical_addr);
+       }
+       if (sev == GHES_SEV_RECOVERABLE &&
+           sec_sev == GHES_SEV_RECOVERABLE &&
+           mem_err->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS) {
+               pfn = mem_err->physical_addr >> PAGE_SHIFT;
+               memory_failure_queue(pfn, 0, 0);
+       }
+#endif
+}
+
 static void ghes_do_proc(struct ghes *ghes,
                         const struct acpi_hest_generic_status *estatus)
 {
@@ -428,15 +456,7 @@ static void ghes_do_proc(struct ghes *ghes,
                        apei_mce_report_mem_error(sev == GHES_SEV_CORRECTED,
                                                  mem_err);
 #endif
-#ifdef CONFIG_ACPI_APEI_MEMORY_FAILURE
-                       if (sev == GHES_SEV_RECOVERABLE &&
-                           sec_sev == GHES_SEV_RECOVERABLE &&
-                           mem_err->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS) {
-                               unsigned long pfn;
-                               pfn = mem_err->physical_addr >> PAGE_SHIFT;
-                               memory_failure_queue(pfn, 0, 0);
-                       }
-#endif
+                       ghes_handle_memory_failure(gdata, sev);
                }
 #ifdef CONFIG_ACPI_APEI_PCIEAER
                else if (!uuid_le_cmp(*(uuid_le *)gdata->section_type,
index f5ef5d54e4ac2ec4c6d4a963ed6b6f3fd7f16ca1..502024502b13362f8ee5761cf2f149ea6454a1d0 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/io.h>
 #include <linux/platform_device.h>
 #include <acpi/apei.h>
+#include <asm/mce.h>
 
 #include "apei-internal.h"
 
@@ -121,6 +122,40 @@ int apei_hest_parse(apei_hest_func_t func, void *data)
 }
 EXPORT_SYMBOL_GPL(apei_hest_parse);
 
+/*
+ * Check if firmware advertises firmware first mode. We need FF bit to be set
+ * along with a set of MC banks which work in FF mode.
+ */
+static int __init hest_parse_cmc(struct acpi_hest_header *hest_hdr, void *data)
+{
+       int i;
+       struct acpi_hest_ia_corrected *cmc;
+       struct acpi_hest_ia_error_bank *mc_bank;
+
+       if (hest_hdr->type != ACPI_HEST_TYPE_IA32_CORRECTED_CHECK)
+               return 0;
+
+       cmc = (struct acpi_hest_ia_corrected *)hest_hdr;
+       if (!cmc->enabled)
+               return 0;
+
+       /*
+        * We expect HEST to provide a list of MC banks that report errors
+        * in firmware first mode. Otherwise, return non-zero value to
+        * indicate that we are done parsing HEST.
+        */
+       if (!(cmc->flags & ACPI_HEST_FIRMWARE_FIRST) || !cmc->num_hardware_banks)
+               return 1;
+
+       pr_info(HEST_PFX "Enabling Firmware First mode for corrected errors.\n");
+
+       mc_bank = (struct acpi_hest_ia_error_bank *)(cmc + 1);
+       for (i = 0; i < cmc->num_hardware_banks; i++, mc_bank++)
+               mce_disable_bank(mc_bank->bank_number);
+
+       return 1;
+}
+
 struct ghes_arr {
        struct platform_device **ghes_devs;
        unsigned int count;
@@ -227,6 +262,9 @@ void __init acpi_hest_init(void)
                goto err;
        }
 
+       if (!acpi_disable_cmcff)
+               apei_hest_parse(hest_parse_cmc, NULL);
+
        if (!ghes_disable) {
                rc = apei_hest_parse(hest_parse_ghes_count, &ghes_count);
                if (rc)
index 082b4dd252a82ab17f7fe7249913e1f7030d35fd..c760b615654133429628d5edca03193b0872133d 100644 (file)
@@ -525,18 +525,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 +544,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 +1026,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 +1056,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 +1068,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 a5bb33bab4485307f7969b19ff9d9ea9cb3f67e2..f2bf7c029ec1b5c0f39d19975c955d9ce09dcc8c 100644 (file)
@@ -345,104 +345,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 +401,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 +414,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 +479,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 +507,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 +597,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 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 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..29b242b413497ca4001ffbb019a4a90806c21f40 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");
@@ -140,7 +141,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 +1378,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 +1454,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;
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..1460c88a7c0eca3f8db4492cc15de42c169e4c63 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;
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..d5993e339a26d72885c1af9afb7e6673e4f38f58 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)
@@ -1336,13 +1307,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 +1340,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 +1362,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 +1381,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;
 
        /*
@@ -1470,28 +1429,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 +1481,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_get_parent(handle, &phandle))
-               return -ENODEV;
+       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_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 +1558,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 +1625,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 +1840,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 +1860,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 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 5daa2599ed48d3fad44223dc904d0cfdc2cbad09..e373671652b0914c10f3237ada35998be9de7fcf 100644 (file)
@@ -200,11 +200,9 @@ config DMA_SHARED_BUFFER
          APIs extension; the file's descriptor can then be passed on to other
          driver.
 
-config CMA
-       bool "Contiguous Memory Allocator"
-       depends on HAVE_DMA_CONTIGUOUS && HAVE_MEMBLOCK
-       select MIGRATION
-       select MEMORY_ISOLATION
+config DMA_CMA
+       bool "DMA Contiguous Memory Allocator"
+       depends on HAVE_DMA_CONTIGUOUS && CMA
        help
          This enables the Contiguous Memory Allocator which allows drivers
          to allocate big physically-contiguous blocks of memory for use with
@@ -213,17 +211,7 @@ config CMA
          For more information see <include/linux/dma-contiguous.h>.
          If unsure, say "n".
 
-if CMA
-
-config CMA_DEBUG
-       bool "CMA debug messages (DEVELOPMENT)"
-       depends on DEBUG_KERNEL
-       help
-         Turns on debug messages in CMA.  This produces KERN_DEBUG
-         messages for every CMA call as well as various messages while
-         processing calls such as dma_alloc_from_contiguous().
-         This option does not affect warning and error messages.
-
+if  DMA_CMA
 comment "Default contiguous memory area size:"
 
 config CMA_SIZE_MBYTES
index 48029aa477d94b1c6b01fe90b367a9e77e2e5dfe..94e8a80e87f87e545638f257ead04c56f73f088b 100644 (file)
@@ -6,7 +6,7 @@ obj-y                   := core.o bus.o dd.o syscore.o \
                           attribute_container.o transport_class.o \
                           topology.o
 obj-$(CONFIG_DEVTMPFS) += devtmpfs.o
-obj-$(CONFIG_CMA) += dma-contiguous.o
+obj-$(CONFIG_DMA_CMA) += dma-contiguous.o
 obj-y                  += power/
 obj-$(CONFIG_HAS_DMA)  += dma-mapping.o
 obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o
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 1643e889bafc7ad7ef3f7ce1d60f60e8be930d79..d10456ffd811f5acc7da0dcd23979b1408d736a9 100644 (file)
@@ -418,6 +418,31 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
                                reg, ret);
                        goto err_alloc;
                }
+
+               if (!chip->init_ack_masked)
+                       continue;
+
+               /* Ack masked but set interrupts */
+               reg = chip->status_base +
+                       (i * map->reg_stride * d->irq_reg_stride);
+               ret = regmap_read(map, reg, &d->status_buf[i]);
+               if (ret != 0) {
+                       dev_err(map->dev, "Failed to read IRQ status: %d\n",
+                               ret);
+                       goto err_alloc;
+               }
+
+               if (d->status_buf[i] && chip->ack_base) {
+                       reg = chip->ack_base +
+                               (i * map->reg_stride * d->irq_reg_stride);
+                       ret = regmap_write(map, reg,
+                                       d->status_buf[i] & d->mask_buf[i]);
+                       if (ret != 0) {
+                               dev_err(map->dev, "Failed to ack 0x%x: %d\n",
+                                       reg, ret);
+                               goto err_alloc;
+                       }
+               }
        }
 
        /* Wake is disabled by default */
index e0d0c7d8a5c527867fb4ba05f4f21e74c43fcff2..17d668035dd19a170ee5eca18a603456d9bfb557 100644 (file)
@@ -303,6 +303,7 @@ static void regmap_unlock_mutex(void *__map)
 }
 
 static void regmap_lock_spinlock(void *__map)
+__acquires(&map->spinlock)
 {
        struct regmap *map = __map;
        unsigned long flags;
@@ -312,6 +313,7 @@ static void regmap_lock_spinlock(void *__map)
 }
 
 static void regmap_unlock_spinlock(void *__map)
+__releases(&map->spinlock)
 {
        struct regmap *map = __map;
        spin_unlock_irqrestore(&map->spinlock, map->spinlock_flags);
@@ -1888,13 +1890,10 @@ EXPORT_SYMBOL_GPL(regmap_async_complete);
 int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
                          int num_regs)
 {
+       struct reg_default *p;
        int i, ret;
        bool bypass;
 
-       /* If needed the implementation can be extended to support this */
-       if (map->patch)
-               return -EBUSY;
-
        map->lock(map->lock_arg);
 
        bypass = map->cache_bypass;
@@ -1911,11 +1910,13 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
                }
        }
 
-       map->patch = kcalloc(num_regs, sizeof(struct reg_default), GFP_KERNEL);
-       if (map->patch != NULL) {
-               memcpy(map->patch, regs,
-                      num_regs * sizeof(struct reg_default));
-               map->patch_regs = num_regs;
+       p = krealloc(map->patch,
+                    sizeof(struct reg_default) * (map->patch_regs + num_regs),
+                    GFP_KERNEL);
+       if (p) {
+               memcpy(p + map->patch_regs, regs, num_regs);
+               map->patch = p;
+               map->patch_regs += num_regs;
        } else {
                ret = -ENOMEM;
        }
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 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 bf5d2477cb77c296dac3a63b3aea2e8a2ec5ce0a..15f2e7025b78e20abcdafc61dee7718800ff1824 100644 (file)
@@ -129,7 +129,8 @@ parisc_agp_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
        off_t j, io_pg_start;
        int io_pg_count;
 
-       if (type != 0 || mem->type != 0) {
+       if (type != mem->type ||
+               agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type)) {
                return -EINVAL;
        }
 
@@ -175,7 +176,8 @@ parisc_agp_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
        struct _parisc_agp_info *info = &parisc_agp_info;
        int i, io_pg_start, io_pg_count;
 
-       if (type != 0 || mem->type != 0) {
+       if (type != mem->type ||
+               agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type)) {
                return -EINVAL;
        }
 
index 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..2cb834fe19a8eee5b864fb168574ce598cb3df0a 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();
 }
index 8b00c5cebfa43d5295ccbb11d8ed95240ee2a9c0..704d6d342adc4f5ebbbc21101fe1f851c0dcb3f2 100644 (file)
@@ -18,6 +18,7 @@ obj-$(CONFIG_ARMADA_370_XP_TIMER)     += time-armada-370-xp.o
 obj-$(CONFIG_ORION_TIMER)      += time-orion.o
 obj-$(CONFIG_ARCH_BCM2835)     += bcm2835_timer.o
 obj-$(CONFIG_ARCH_MARCO)       += timer-marco.o
+obj-$(CONFIG_ARCH_MOXART)      += moxart_timer.o
 obj-$(CONFIG_ARCH_MXS)         += mxs_timer.o
 obj-$(CONFIG_ARCH_PRIMA2)      += timer-prima2.o
 obj-$(CONFIG_SUN4I_TIMER)      += sun4i_timer.o
index 4cbe28c74631eaa5ef8df596865db2a92bd02cb7..b2bb3a4bc20542199cb4a3eab1bc71bcc5022dfa 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/slab.h>
-#include <linux/clk-provider.h>
+#include <linux/sched_clock.h>
 
 /*
  * This driver configures the 2 16-bit count-up timers as follows:
@@ -95,6 +95,8 @@ struct ttc_timer_clockevent {
 #define to_ttc_timer_clkevent(x) \
                container_of(x, struct ttc_timer_clockevent, ce)
 
+static void __iomem *ttc_sched_clock_val_reg;
+
 /**
  * ttc_set_interval - Set the timer interval value
  *
@@ -156,6 +158,11 @@ static cycle_t __ttc_clocksource_read(struct clocksource *cs)
                                TTC_COUNT_VAL_OFFSET);
 }
 
+static u32 notrace ttc_sched_clock_read(void)
+{
+       return __raw_readl(ttc_sched_clock_val_reg);
+}
+
 /**
  * ttc_set_next_event - Sets the time interval for next event
  *
@@ -297,6 +304,10 @@ static void __init ttc_setup_clocksource(struct clk *clk, void __iomem *base)
                kfree(ttccs);
                return;
        }
+
+       ttc_sched_clock_val_reg = base + TTC_COUNT_VAL_OFFSET;
+       setup_sched_clock(ttc_sched_clock_read, 16,
+                       clk_get_rate(ttccs->ttc.clk) / PRESCALE);
 }
 
 static int ttc_rate_change_clockevent_cb(struct notifier_block *nb,
diff --git a/drivers/clocksource/moxart_timer.c b/drivers/clocksource/moxart_timer.c
new file mode 100644 (file)
index 0000000..08a5943
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * MOXA ART SoCs timer handling.
+ *
+ * Copyright (C) 2013 Jonas Jensen
+ *
+ * Jonas Jensen <jonas.jensen@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/clk.h>
+#include <linux/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqreturn.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/io.h>
+#include <linux/clocksource.h>
+
+#define TIMER1_BASE            0x00
+#define TIMER2_BASE            0x10
+#define TIMER3_BASE            0x20
+
+#define REG_COUNT              0x0 /* writable */
+#define REG_LOAD               0x4
+#define REG_MATCH1             0x8
+#define REG_MATCH2             0xC
+
+#define TIMER_CR               0x30
+#define TIMER_INTR_STATE       0x34
+#define TIMER_INTR_MASK                0x38
+
+/*
+ * TIMER_CR flags:
+ *
+ * TIMEREG_CR_*_CLOCK  0: PCLK, 1: EXT1CLK
+ * TIMEREG_CR_*_INT    overflow interrupt enable bit
+ */
+#define TIMEREG_CR_1_ENABLE    BIT(0)
+#define TIMEREG_CR_1_CLOCK     BIT(1)
+#define TIMEREG_CR_1_INT       BIT(2)
+#define TIMEREG_CR_2_ENABLE    BIT(3)
+#define TIMEREG_CR_2_CLOCK     BIT(4)
+#define TIMEREG_CR_2_INT       BIT(5)
+#define TIMEREG_CR_3_ENABLE    BIT(6)
+#define TIMEREG_CR_3_CLOCK     BIT(7)
+#define TIMEREG_CR_3_INT       BIT(8)
+#define TIMEREG_CR_COUNT_UP    BIT(9)
+
+#define TIMER1_ENABLE          (TIMEREG_CR_2_ENABLE | TIMEREG_CR_1_ENABLE)
+#define TIMER1_DISABLE         (TIMEREG_CR_2_ENABLE)
+
+static void __iomem *base;
+static unsigned int clock_count_per_tick;
+
+static void moxart_clkevt_mode(enum clock_event_mode mode,
+                              struct clock_event_device *clk)
+{
+       switch (mode) {
+       case CLOCK_EVT_MODE_RESUME:
+       case CLOCK_EVT_MODE_ONESHOT:
+               writel(TIMER1_DISABLE, base + TIMER_CR);
+               writel(~0, base + TIMER1_BASE + REG_LOAD);
+               break;
+       case CLOCK_EVT_MODE_PERIODIC:
+               writel(clock_count_per_tick, base + TIMER1_BASE + REG_LOAD);
+               writel(TIMER1_ENABLE, base + TIMER_CR);
+               break;
+       case CLOCK_EVT_MODE_UNUSED:
+       case CLOCK_EVT_MODE_SHUTDOWN:
+       default:
+               writel(TIMER1_DISABLE, base + TIMER_CR);
+               break;
+       }
+}
+
+static int moxart_clkevt_next_event(unsigned long cycles,
+                                   struct clock_event_device *unused)
+{
+       u32 u;
+
+       writel(TIMER1_DISABLE, base + TIMER_CR);
+
+       u = readl(base + TIMER1_BASE + REG_COUNT) - cycles;
+       writel(u, base + TIMER1_BASE + REG_MATCH1);
+
+       writel(TIMER1_ENABLE, base + TIMER_CR);
+
+       return 0;
+}
+
+static struct clock_event_device moxart_clockevent = {
+       .name           = "moxart_timer",
+       .rating         = 200,
+       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+       .set_mode       = moxart_clkevt_mode,
+       .set_next_event = moxart_clkevt_next_event,
+};
+
+static irqreturn_t moxart_timer_interrupt(int irq, void *dev_id)
+{
+       struct clock_event_device *evt = dev_id;
+       evt->event_handler(evt);
+       return IRQ_HANDLED;
+}
+
+static struct irqaction moxart_timer_irq = {
+       .name           = "moxart-timer",
+       .flags          = IRQF_TIMER,
+       .handler        = moxart_timer_interrupt,
+       .dev_id         = &moxart_clockevent,
+};
+
+static void __init moxart_timer_init(struct device_node *node)
+{
+       int ret, irq;
+       unsigned long pclk;
+       struct clk *clk;
+
+       base = of_iomap(node, 0);
+       if (!base)
+               panic("%s: of_iomap failed\n", node->full_name);
+
+       irq = irq_of_parse_and_map(node, 0);
+       if (irq <= 0)
+               panic("%s: irq_of_parse_and_map failed\n", node->full_name);
+
+       ret = setup_irq(irq, &moxart_timer_irq);
+       if (ret)
+               panic("%s: setup_irq failed\n", node->full_name);
+
+       clk = of_clk_get(node, 0);
+       if (IS_ERR(clk))
+               panic("%s: of_clk_get failed\n", node->full_name);
+
+       pclk = clk_get_rate(clk);
+
+       if (clocksource_mmio_init(base + TIMER2_BASE + REG_COUNT,
+                                 "moxart_timer", pclk, 200, 32,
+                                 clocksource_mmio_readl_down))
+               panic("%s: clocksource_mmio_init failed\n", node->full_name);
+
+       clock_count_per_tick = DIV_ROUND_CLOSEST(pclk, HZ);
+
+       writel(~0, base + TIMER2_BASE + REG_LOAD);
+       writel(TIMEREG_CR_2_ENABLE, base + TIMER_CR);
+
+       moxart_clockevent.cpumask = cpumask_of(0);
+       moxart_clockevent.irq = irq;
+
+       /*
+        * documentation is not publicly available:
+        * min_delta / max_delta obtained by trial-and-error,
+        * max_delta 0xfffffffe should be ok because count
+        * register size is u32
+        */
+       clockevents_config_and_register(&moxart_clockevent, pclk,
+                                       0x4, 0xfffffffe);
+}
+CLOCKSOURCE_OF_DECLARE(moxart, "moxa,moxart-timer", moxart_timer_init);
index d4674e78ef351de777d2d04751f008c6e205f7c9..8ead0258740a82dc71807bd323f5b1eb9d1535a5 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/irqreturn.h>
+#include <linux/sched_clock.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 
 #define TIMER_IRQ_EN_REG       0x00
-#define TIMER_IRQ_EN(val)              (1 << val)
+#define TIMER_IRQ_EN(val)              BIT(val)
 #define TIMER_IRQ_ST_REG       0x04
 #define TIMER_CTL_REG(val)     (0x10 * val + 0x10)
-#define TIMER_CTL_ENABLE               (1 << 0)
-#define TIMER_CTL_AUTORELOAD           (1 << 1)
-#define TIMER_CTL_ONESHOT              (1 << 7)
-#define TIMER_INTVAL_REG(val)  (0x10 * val + 0x14)
-#define TIMER_CNTVAL_REG(val)  (0x10 * val + 0x18)
-
-#define TIMER_SCAL             16
+#define TIMER_CTL_ENABLE               BIT(0)
+#define TIMER_CTL_RELOAD               BIT(1)
+#define TIMER_CTL_CLK_SRC(val)         (((val) & 0x3) << 2)
+#define TIMER_CTL_CLK_SRC_OSC24M               (1)
+#define TIMER_CTL_CLK_PRES(val)                (((val) & 0x7) << 4)
+#define TIMER_CTL_ONESHOT              BIT(7)
+#define TIMER_INTVAL_REG(val)  (0x10 * (val) + 0x14)
+#define TIMER_CNTVAL_REG(val)  (0x10 * (val) + 0x18)
 
 static void __iomem *timer_base;
+static u32 ticks_per_jiffy;
+
+/*
+ * When we disable a timer, we need to wait at least for 2 cycles of
+ * the timer source clock. We will use for that the clocksource timer
+ * that is already setup and runs at the same frequency than the other
+ * timers, and we never will be disabled.
+ */
+static void sun4i_clkevt_sync(void)
+{
+       u32 old = readl(timer_base + TIMER_CNTVAL_REG(1));
+
+       while ((old - readl(timer_base + TIMER_CNTVAL_REG(1))) < 3)
+               cpu_relax();
+}
+
+static void sun4i_clkevt_time_stop(u8 timer)
+{
+       u32 val = readl(timer_base + TIMER_CTL_REG(timer));
+       writel(val & ~TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG(timer));
+       sun4i_clkevt_sync();
+}
+
+static void sun4i_clkevt_time_setup(u8 timer, unsigned long delay)
+{
+       writel(delay, timer_base + TIMER_INTVAL_REG(timer));
+}
+
+static void sun4i_clkevt_time_start(u8 timer, bool periodic)
+{
+       u32 val = readl(timer_base + TIMER_CTL_REG(timer));
+
+       if (periodic)
+               val &= ~TIMER_CTL_ONESHOT;
+       else
+               val |= TIMER_CTL_ONESHOT;
+
+       writel(val | TIMER_CTL_ENABLE | TIMER_CTL_RELOAD,
+              timer_base + TIMER_CTL_REG(timer));
+}
 
 static void sun4i_clkevt_mode(enum clock_event_mode mode,
                              struct clock_event_device *clk)
 {
-       u32 u = readl(timer_base + TIMER_CTL_REG(0));
-
        switch (mode) {
        case CLOCK_EVT_MODE_PERIODIC:
-               u &= ~(TIMER_CTL_ONESHOT);
-               writel(u | TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG(0));
+               sun4i_clkevt_time_stop(0);
+               sun4i_clkevt_time_setup(0, ticks_per_jiffy);
+               sun4i_clkevt_time_start(0, true);
                break;
-
        case CLOCK_EVT_MODE_ONESHOT:
-               writel(u | TIMER_CTL_ONESHOT, timer_base + TIMER_CTL_REG(0));
+               sun4i_clkevt_time_stop(0);
+               sun4i_clkevt_time_start(0, false);
                break;
        case CLOCK_EVT_MODE_UNUSED:
        case CLOCK_EVT_MODE_SHUTDOWN:
        default:
-               writel(u & ~(TIMER_CTL_ENABLE), timer_base + TIMER_CTL_REG(0));
+               sun4i_clkevt_time_stop(0);
                break;
        }
 }
@@ -62,10 +103,9 @@ static void sun4i_clkevt_mode(enum clock_event_mode mode,
 static int sun4i_clkevt_next_event(unsigned long evt,
                                   struct clock_event_device *unused)
 {
-       u32 u = readl(timer_base + TIMER_CTL_REG(0));
-       writel(evt, timer_base + TIMER_CNTVAL_REG(0));
-       writel(u | TIMER_CTL_ENABLE | TIMER_CTL_AUTORELOAD,
-              timer_base + TIMER_CTL_REG(0));
+       sun4i_clkevt_time_stop(0);
+       sun4i_clkevt_time_setup(0, evt);
+       sun4i_clkevt_time_start(0, false);
 
        return 0;
 }
@@ -96,6 +136,11 @@ static struct irqaction sun4i_timer_irq = {
        .dev_id = &sun4i_clockevent,
 };
 
+static u32 sun4i_timer_sched_read(void)
+{
+       return ~readl(timer_base + TIMER_CNTVAL_REG(1));
+}
+
 static void __init sun4i_timer_init(struct device_node *node)
 {
        unsigned long rate = 0;
@@ -114,22 +159,23 @@ static void __init sun4i_timer_init(struct device_node *node)
        clk = of_clk_get(node, 0);
        if (IS_ERR(clk))
                panic("Can't get timer clock");
+       clk_prepare_enable(clk);
 
        rate = clk_get_rate(clk);
 
-       writel(rate / (TIMER_SCAL * HZ),
-              timer_base + TIMER_INTVAL_REG(0));
+       writel(~0, timer_base + TIMER_INTVAL_REG(1));
+       writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD |
+              TIMER_CTL_CLK_SRC(TIMER_CTL_CLK_SRC_OSC24M),
+              timer_base + TIMER_CTL_REG(1));
+
+       setup_sched_clock(sun4i_timer_sched_read, 32, rate);
+       clocksource_mmio_init(timer_base + TIMER_CNTVAL_REG(1), node->name,
+                             rate, 300, 32, clocksource_mmio_readl_down);
 
-       /* set clock source to HOSC, 16 pre-division */
-       val = readl(timer_base + TIMER_CTL_REG(0));
-       val &= ~(0x07 << 4);
-       val &= ~(0x03 << 2);
-       val |= (4 << 4) | (1 << 2);
-       writel(val, timer_base + TIMER_CTL_REG(0));
+       ticks_per_jiffy = DIV_ROUND_UP(rate, HZ);
 
-       /* set mode to auto reload */
-       val = readl(timer_base + TIMER_CTL_REG(0));
-       writel(val | TIMER_CTL_AUTORELOAD, timer_base + TIMER_CTL_REG(0));
+       writel(TIMER_CTL_CLK_SRC(TIMER_CTL_CLK_SRC_OSC24M),
+              timer_base + TIMER_CTL_REG(0));
 
        ret = setup_irq(irq, &sun4i_timer_irq);
        if (ret)
@@ -141,8 +187,8 @@ static void __init sun4i_timer_init(struct device_node *node)
 
        sun4i_clockevent.cpumask = cpumask_of(0);
 
-       clockevents_config_and_register(&sun4i_clockevent, rate / TIMER_SCAL,
-                                       0x1, 0xff);
+       clockevents_config_and_register(&sun4i_clockevent, rate, 0x1,
+                                       0xffffffff);
 }
 CLOCKSOURCE_OF_DECLARE(sun4i, "allwinner,sun4i-timer",
                       sun4i_timer_init);
index ecbeb68102154f15a0ec5989449dc396bbd5fc6e..9c7f018a67cad356a2e85cfe270117a6404ac547 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/spinlock.h>
-#include <asm/sched_clock.h>
+#include <linux/sched_clock.h>
 
 #define TIMER_CTRL             0x00
 #define  TIMER0_EN             BIT(0)
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..c1a917a5cb384c370ff4cb6f5c44d93d715a82d8 100644 (file)
@@ -1177,14 +1177,11 @@ static int __cpufreq_remove_dev(struct device *dev,
                                __func__, cpu_dev->id, cpu);
        }
 
-       if ((cpus == 1) && (cpufreq_driver->target))
-               __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT);
-
-       pr_debug("%s: removing link, cpu: %d\n", __func__, cpu);
-       cpufreq_cpu_put(data);
-
        /* If cpu is last user of policy, free policy */
        if (cpus == 1) {
+               if (cpufreq_driver->target)
+                       __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT);
+
                lock_policy_rwsem_read(cpu);
                kobj = &data->kobj;
                cmp = &data->kobj_unregister;
@@ -1205,9 +1202,13 @@ static int __cpufreq_remove_dev(struct device *dev,
                free_cpumask_var(data->related_cpus);
                free_cpumask_var(data->cpus);
                kfree(data);
-       } else if (cpufreq_driver->target) {
-               __cpufreq_governor(data, CPUFREQ_GOV_START);
-               __cpufreq_governor(data, CPUFREQ_GOV_LIMITS);
+       } else {
+               pr_debug("%s: removing link, cpu: %d\n", __func__, cpu);
+               cpufreq_cpu_put(data);
+               if (cpufreq_driver->target) {
+                       __cpufreq_governor(data, CPUFREQ_GOV_START);
+                       __cpufreq_governor(data, CPUFREQ_GOV_LIMITS);
+               }
        }
 
        per_cpu(cpufreq_policy_cpu, cpu) = -1;
@@ -1593,18 +1594,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
  */
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 *
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 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 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 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 8b6a0343c2208121cf858c6a22aea1816f427f16..8b3d90143514d79eee35dafec8d726174b30fd38 100644 (file)
@@ -2470,8 +2470,15 @@ static int amd64_init_one_instance(struct pci_dev *F2)
        layers[0].size = pvt->csels[0].b_cnt;
        layers[0].is_virt_csrow = true;
        layers[1].type = EDAC_MC_LAYER_CHANNEL;
-       layers[1].size = pvt->channel_count;
+
+       /*
+        * Always allocate two channels since we can have setups with DIMMs on
+        * only one channel. Also, this simplifies handling later for the price
+        * of a couple of KBs tops.
+        */
+       layers[1].size = 2;
        layers[1].is_virt_csrow = false;
+
        mci = edac_mc_alloc(nid, ARRAY_SIZE(layers), layers, 0);
        if (!mci)
                goto err_siblings;
index e7c32c4f783737962b575a232f03b5ed19d3629b..9f7e0e609516c536ae9a7366f8e1c23e1c6cf32c 100644 (file)
@@ -58,8 +58,10 @@ static int edac_set_poll_msec(const char *val, struct kernel_param *kp)
        if (!val)
                return -EINVAL;
 
-       ret = strict_strtol(val, 0, &l);
-       if (ret == -EINVAL || ((int)l != l))
+       ret = kstrtol(val, 0, &l);
+       if (ret)
+               return ret;
+       if ((int)l != l)
                return -EINVAL;
        *((int *)kp->arg) = l;
 
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 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 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 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..82ea281b2182f1c185d8ccdc9b3189772eeac0f6 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,20 @@ 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_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 +1688,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 +1744,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 +1917,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 +2001,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 +2101,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 +2109,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 +2116,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 +2134,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 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 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 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 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 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 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 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..d71037f4f68ffb05bb8b067c3e7628f5bddd0d6a 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
@@ -5651,7 +5651,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 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 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 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..510fa8f8d16beb71f3159e55bf66f30ace4a243b 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_KERNEL);
+       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..a32f5a24b27ceadcdfe33e05a8fe9715eed4d38a 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;
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;
 
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 99418285222cf118cbc09e4d9029c80ba3493fcf..ada164e1b3a1fd909c8c6a437dc2cc5cb424a845 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;
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 99cec18254203c5ebfa59ba0b1cbfdecabf77aac..25e2c7bea48c97022e1916c242716117f2b3bbf1 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;
 
-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),
+       return attr->mode;
+}
+
+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;
+
+       return attr->mode;
+}
 
-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),
+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;
+       }
 
-       for (i = 0; i < ARRAY_SIZE(sda_pwm_step); i++)
-               device_remove_file(dev, &sda_pwm_step[i].dev_attr);
+       if (index == 4 || index == 5) {
+               if (data->BEEP_BITS[INTRUSION_ALARM_BASE + index - 4] < 0)
+                       return 0;
+       }
+
+       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,
@@ -3422,9 +3292,10 @@ static int nct6775_probe(struct platform_device *pdev)
        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);
        }
@@ -4074,17 +4015,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 +4039,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 +4051,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 +4065,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 +4078,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 +4102,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 +4124,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 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 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 e43402dd1dead6aa6e2e77cc4b392287402727a0..77329ce672cb9b148ae9a204a202f078f64a043b 100644 (file)
@@ -194,11 +194,11 @@ config LEDS_LP3944
          module will be called leds-lp3944.
 
 config LEDS_LP55XX_COMMON
-       tristate "Common Driver for TI/National LP5521, LP5523/55231 and LP5562"
-       depends on LEDS_LP5521 || LEDS_LP5523 || LEDS_LP5562
+       tristate "Common Driver for TI/National LP5521/5523/55231/5562/8501"
+       depends on LEDS_LP5521 || LEDS_LP5523 || LEDS_LP5562 || LEDS_LP8501
        select FW_LOADER
        help
-         This option supports common operations for LP5521 and LP5523/55231
+         This option supports common operations for LP5521/5523/55231/5562/8501
          devices.
 
 config LEDS_LP5521
@@ -232,6 +232,18 @@ config LEDS_LP5562
          Driver provides direct control via LED class and interface for
          programming the engines.
 
+config LEDS_LP8501
+       tristate "LED Support for TI LP8501 LED driver chip"
+       depends on LEDS_CLASS && I2C
+       select LEDS_LP55XX_COMMON
+       help
+         If you say yes here you get support for TI LP8501 LED driver.
+         It is 9 channel chip with programmable engines.
+         Driver provides direct control via LED class and interface for
+         programming the engines.
+         It is similar as LP5523, but output power selection is available.
+         And register layout and engine program schemes are different.
+
 config LEDS_LP8788
        tristate "LED support for the TI LP8788 PMIC"
        depends on LEDS_CLASS
index ac2897732b0219c071f4e60ea1dea84047d9c78f..3013113e74d2859f9b288886216b46382e932bbb 100644 (file)
@@ -27,6 +27,7 @@ obj-$(CONFIG_LEDS_LP55XX_COMMON)      += leds-lp55xx-common.o
 obj-$(CONFIG_LEDS_LP5521)              += leds-lp5521.o
 obj-$(CONFIG_LEDS_LP5523)              += leds-lp5523.o
 obj-$(CONFIG_LEDS_LP5562)              += leds-lp5562.o
+obj-$(CONFIG_LEDS_LP8501)              += leds-lp8501.o
 obj-$(CONFIG_LEDS_LP8788)              += leds-lp8788.o
 obj-$(CONFIG_LEDS_TCA6507)             += leds-tca6507.o
 obj-$(CONFIG_LEDS_CLEVO_MAIL)          += leds-clevo-mail.o
index 232b3ce902e55f6d3c7ea696a93808121e304ace..5f588c0a376eb0eaec12843fea7022c65f9a1418 100644 (file)
@@ -157,7 +157,7 @@ static int pm860x_led_dt_init(struct platform_device *pdev,
 static int pm860x_led_probe(struct platform_device *pdev)
 {
        struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
-       struct pm860x_led_pdata *pdata = pdev->dev.platform_data;
+       struct pm860x_led_pdata *pdata = dev_get_platdata(&pdev->dev);
        struct pm860x_led *data;
        struct resource *res;
        int ret = 0;
index e8072abe76e5fb81e1e155ac25c9a7d8481b0673..7e311a120b11abe9f457550ffc85df2c4cbf1748 100644 (file)
@@ -87,7 +87,7 @@ static int adp5520_led_setup(struct adp5520_led *led)
 
 static int adp5520_led_prepare(struct platform_device *pdev)
 {
-       struct adp5520_leds_platform_data *pdata = pdev->dev.platform_data;
+       struct adp5520_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct device *dev = pdev->dev.parent;
        int ret = 0;
 
@@ -103,7 +103,7 @@ static int adp5520_led_prepare(struct platform_device *pdev)
 
 static int adp5520_led_probe(struct platform_device *pdev)
 {
-       struct adp5520_leds_platform_data *pdata = pdev->dev.platform_data;
+       struct adp5520_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct adp5520_led *led, *led_dat;
        struct led_info *cur_led;
        int ret, i;
@@ -185,7 +185,7 @@ err:
 
 static int adp5520_led_remove(struct platform_device *pdev)
 {
-       struct adp5520_leds_platform_data *pdata = pdev->dev.platform_data;
+       struct adp5520_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct adp5520_led *led;
        int i;
 
index cf9efe421c2be0674ddc2db79a0059811b5df859..6de216a89a0c1d3dc766f45f1e19466b80fe316f 100644 (file)
@@ -94,7 +94,7 @@ static int blink_set(struct led_classdev *cdev,
 
 static int asic3_led_probe(struct platform_device *pdev)
 {
-       struct asic3_led *led = pdev->dev.platform_data;
+       struct asic3_led *led = dev_get_platdata(&pdev->dev);
        int ret;
 
        ret = mfd_cell_enable(pdev);
@@ -127,7 +127,7 @@ out:
 
 static int asic3_led_remove(struct platform_device *pdev)
 {
-       struct asic3_led *led = pdev->dev.platform_data;
+       struct asic3_led *led = dev_get_platdata(&pdev->dev);
 
        led_classdev_unregister(led->cdev);
 
index 90518f84b9c07aeacf06664c0adcf32671512269..56cec8d6a2ac7a56de5b4f03d6d0f2a0920b3bfc 100644 (file)
@@ -42,7 +42,7 @@ static int pwmled_probe(struct platform_device *pdev)
        int                                     i;
        int                                     status;
 
-       pdata = pdev->dev.platform_data;
+       pdata = dev_get_platdata(&pdev->dev);
        if (!pdata || pdata->num_leds < 1)
                return -ENODEV;
 
@@ -119,7 +119,7 @@ static int pwmled_remove(struct platform_device *pdev)
        struct pwmled                           *leds;
        unsigned                                i;
 
-       pdata = pdev->dev.platform_data;
+       pdata = dev_get_platdata(&pdev->dev);
        leds = platform_get_drvdata(pdev);
 
        for (i = 0; i < pdata->num_leds; i++) {
index 2db04231a79276e049a930469aef66b90b3eb4ca..fb5a3472d61444c1cd8d491ee8a5ee571f39765c 100644 (file)
@@ -684,7 +684,7 @@ static int bd2802_probe(struct i2c_client *client,
        }
 
        led->client = client;
-       pdata = led->pdata = client->dev.platform_data;
+       pdata = led->pdata = dev_get_platdata(&client->dev);
        i2c_set_clientdata(client, led);
 
        /* Configure RESET GPIO (L: RESET, H: RESET cancel) */
index c263a21db8298d057ca1cf5b9b28196d0af8e864..2a4b87f8091ab699706577e1442efe68de645049 100644 (file)
@@ -93,7 +93,7 @@ static void da903x_led_set(struct led_classdev *led_cdev,
 
 static int da903x_led_probe(struct platform_device *pdev)
 {
-       struct led_info *pdata = pdev->dev.platform_data;
+       struct led_info *pdata = dev_get_platdata(&pdev->dev);
        struct da903x_led *led;
        int id, ret;
 
index efec43344e9f98b1ab56ae20f800d9fb5348ad56..865d4faf874a627424611314eb454e8ca2ba9d6e 100644 (file)
@@ -112,7 +112,7 @@ static int da9052_led_probe(struct platform_device *pdev)
        int i;
 
        da9052 = dev_get_drvdata(pdev->dev.parent);
-       pdata = da9052->dev->platform_data;
+       pdata = dev_get_platdata(da9052->dev);
        if (pdata == NULL) {
                dev_err(&pdev->dev, "No platform data\n");
                goto err;
@@ -185,7 +185,7 @@ static int da9052_led_remove(struct platform_device *pdev)
        int i;
 
        da9052 = dev_get_drvdata(pdev->dev.parent);
-       pdata = da9052->dev->platform_data;
+       pdata = dev_get_platdata(da9052->dev);
        pled = pdata->pled;
 
        for (i = 0; i < pled->num_leds; i++) {
index 84d74c373cae89cd046554f653b7da34fb761a64..e8b01e57348d675cae0821ddb9179b85d92a03f1 100644 (file)
@@ -233,7 +233,7 @@ static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)
 
 static int gpio_led_probe(struct platform_device *pdev)
 {
-       struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
+       struct gpio_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct gpio_leds_priv *priv;
        int i, ret = 0;
 
index a036a19040fea90b70ba93a93eac99401f85567a..652368c2ea9a5b9ca1d806de4057747a2c2fea0a 100644 (file)
@@ -403,7 +403,7 @@ static DEVICE_ATTR(mode, 0644, lm3530_mode_get, lm3530_mode_set);
 static int lm3530_probe(struct i2c_client *client,
                           const struct i2c_device_id *id)
 {
-       struct lm3530_platform_data *pdata = client->dev.platform_data;
+       struct lm3530_platform_data *pdata = dev_get_platdata(&client->dev);
        struct lm3530_data *drvdata;
        int err = 0;
 
index bbf24d038a7fc2139b0c78845b52bbb266f13b2c..027ede73b80da01d716aacd6dbd2d07e20b90092 100644 (file)
@@ -671,7 +671,7 @@ static int lm3533_led_probe(struct platform_device *pdev)
        if (!lm3533)
                return -EINVAL;
 
-       pdata = pdev->dev.platform_data;
+       pdata = dev_get_platdata(&pdev->dev);
        if (!pdata) {
                dev_err(&pdev->dev, "no platform data\n");
                return -EINVAL;
index d81a8e7afd6ce2a6ae3d21adfa95e4cb25a0d2fe..591eb5e58ae3f80ad3766cee4ded90917cf167b0 100644 (file)
@@ -423,7 +423,7 @@ static const struct regmap_config lm355x_regmap = {
 static int lm355x_probe(struct i2c_client *client,
                                  const struct i2c_device_id *id)
 {
-       struct lm355x_platform_data *pdata = client->dev.platform_data;
+       struct lm355x_platform_data *pdata = dev_get_platdata(&client->dev);
        struct lm355x_chip_data *chip;
 
        int err;
index f361bbef2decc2aa7d1e6d904587dea147c30146..ceb6b3cde6fe8a3dd261d9b94a94cd0c8cebb7b3 100644 (file)
@@ -316,7 +316,7 @@ static const struct regmap_config lm3642_regmap = {
 static int lm3642_probe(struct i2c_client *client,
                                  const struct i2c_device_id *id)
 {
-       struct lm3642_platform_data *pdata = client->dev.platform_data;
+       struct lm3642_platform_data *pdata = dev_get_platdata(&client->dev);
        struct lm3642_chip_data *chip;
 
        int err;
index 0c4386e656c162fcea462743d618638037094124..2b53d10e5607330a32f87bb8db57b64dee28c161 100644 (file)
@@ -377,7 +377,8 @@ exit:
 static int lp3944_probe(struct i2c_client *client,
                                  const struct i2c_device_id *id)
 {
-       struct lp3944_platform_data *lp3944_pdata = client->dev.platform_data;
+       struct lp3944_platform_data *lp3944_pdata =
+                       dev_get_platdata(&client->dev);
        struct lp3944_data *data;
        int err;
 
@@ -413,7 +414,7 @@ static int lp3944_probe(struct i2c_client *client,
 
 static int lp3944_remove(struct i2c_client *client)
 {
-       struct lp3944_platform_data *pdata = client->dev.platform_data;
+       struct lp3944_platform_data *pdata = dev_get_platdata(&client->dev);
        struct lp3944_data *data = i2c_get_clientdata(client);
        int i;
 
index 1392feb1bcf7849559ba29b38f163afa01a305bb..9e28dd073e26131c7f6e217bf12c856f8de496b9 100644 (file)
@@ -420,7 +420,7 @@ static int lp5521_probe(struct i2c_client *client,
        struct lp55xx_platform_data *pdata;
        struct device_node *np = client->dev.of_node;
 
-       if (!client->dev.platform_data) {
+       if (!dev_get_platdata(&client->dev)) {
                if (np) {
                        ret = lp55xx_of_populate_pdata(&client->dev, np);
                        if (ret < 0)
@@ -430,7 +430,7 @@ static int lp5521_probe(struct i2c_client *client,
                        return -EINVAL;
                }
        }
-       pdata = client->dev.platform_data;
+       pdata = dev_get_platdata(&client->dev);
 
        chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
        if (!chip)
index 3979428f3100ab9d274a5e3bb3afa1333399efee..72c10e2d4b0252b0e208c1ed80d8b973dbcb30c4 100644 (file)
@@ -432,7 +432,7 @@ static int lp5523_probe(struct i2c_client *client,
        struct lp55xx_platform_data *pdata;
        struct device_node *np = client->dev.of_node;
 
-       if (!client->dev.platform_data) {
+       if (!dev_get_platdata(&client->dev)) {
                if (np) {
                        ret = lp55xx_of_populate_pdata(&client->dev, np);
                        if (ret < 0)
@@ -442,7 +442,7 @@ static int lp5523_probe(struct i2c_client *client,
                        return -EINVAL;
                }
        }
-       pdata = client->dev.platform_data;
+       pdata = dev_get_platdata(&client->dev);
 
        chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
        if (!chip)
index cbd856dac15041c3c6396741aa7913bfee85ab34..a2c7398f1f55baa2fd7e6f43e2d003dc1baf8ad5 100644 (file)
@@ -518,7 +518,7 @@ static int lp5562_probe(struct i2c_client *client,
        struct lp55xx_platform_data *pdata;
        struct device_node *np = client->dev.of_node;
 
-       if (!client->dev.platform_data) {
+       if (!dev_get_platdata(&client->dev)) {
                if (np) {
                        ret = lp55xx_of_populate_pdata(&client->dev, np);
                        if (ret < 0)
@@ -528,7 +528,7 @@ static int lp5562_probe(struct i2c_client *client,
                        return -EINVAL;
                }
        }
-       pdata = client->dev.platform_data;
+       pdata = dev_get_platdata(&client->dev);
 
        chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
        if (!chip)
index c2fecd4d391ce33cee56aad60d3d1d80a62ffc02..351825b96f16b534923b36d97e5fd0ccaacbdf6c 100644 (file)
@@ -593,6 +593,9 @@ int lp55xx_of_populate_pdata(struct device *dev, struct device_node *np)
        of_property_read_string(np, "label", &pdata->label);
        of_property_read_u8(np, "clock-mode", &pdata->clock_mode);
 
+       /* LP8501 specific */
+       of_property_read_u8(np, "pwr-sel", (u8 *)&pdata->pwr_sel);
+
        dev->platform_data = pdata;
 
        return 0;
diff --git a/drivers/leds/leds-lp8501.c b/drivers/leds/leds-lp8501.c
new file mode 100644 (file)
index 0000000..8d55a78
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+ * TI LP8501 9 channel LED Driver
+ *
+ * Copyright (C) 2013 Texas Instruments
+ *
+ * Author: Milo(Woogyom) Kim <milo.kim@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.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_data/leds-lp55xx.h>
+#include <linux/slab.h>
+
+#include "leds-lp55xx-common.h"
+
+#define LP8501_PROGRAM_LENGTH          32
+#define LP8501_MAX_LEDS                        9
+
+/* Registers */
+#define LP8501_REG_ENABLE              0x00
+#define LP8501_ENABLE                  BIT(6)
+#define LP8501_EXEC_M                  0x3F
+#define LP8501_EXEC_ENG1_M             0x30
+#define LP8501_EXEC_ENG2_M             0x0C
+#define LP8501_EXEC_ENG3_M             0x03
+#define LP8501_RUN_ENG1                        0x20
+#define LP8501_RUN_ENG2                        0x08
+#define LP8501_RUN_ENG3                        0x02
+
+#define LP8501_REG_OP_MODE             0x01
+#define LP8501_MODE_ENG1_M             0x30
+#define LP8501_MODE_ENG2_M             0x0C
+#define LP8501_MODE_ENG3_M             0x03
+#define LP8501_LOAD_ENG1               0x10
+#define LP8501_LOAD_ENG2               0x04
+#define LP8501_LOAD_ENG3               0x01
+
+#define LP8501_REG_PWR_CONFIG          0x05
+#define LP8501_PWR_CONFIG_M            0x03
+
+#define LP8501_REG_LED_PWM_BASE                0x16
+
+#define LP8501_REG_LED_CURRENT_BASE    0x26
+
+#define LP8501_REG_CONFIG              0x36
+#define LP8501_PWM_PSAVE               BIT(7)
+#define LP8501_AUTO_INC                        BIT(6)
+#define LP8501_PWR_SAVE                        BIT(5)
+#define LP8501_CP_AUTO                 0x18
+#define LP8501_INT_CLK                 BIT(0)
+#define LP8501_DEFAULT_CFG     \
+       (LP8501_PWM_PSAVE | LP8501_AUTO_INC | LP8501_PWR_SAVE | LP8501_CP_AUTO)
+
+#define LP8501_REG_RESET               0x3D
+#define LP8501_RESET                   0xFF
+
+#define LP8501_REG_PROG_PAGE_SEL       0x4F
+#define LP8501_PAGE_ENG1               0
+#define LP8501_PAGE_ENG2               1
+#define LP8501_PAGE_ENG3               2
+
+#define LP8501_REG_PROG_MEM            0x50
+
+#define LP8501_ENG1_IS_LOADING(mode)   \
+       ((mode & LP8501_MODE_ENG1_M) == LP8501_LOAD_ENG1)
+#define LP8501_ENG2_IS_LOADING(mode)   \
+       ((mode & LP8501_MODE_ENG2_M) == LP8501_LOAD_ENG2)
+#define LP8501_ENG3_IS_LOADING(mode)   \
+       ((mode & LP8501_MODE_ENG3_M) == LP8501_LOAD_ENG3)
+
+static inline void lp8501_wait_opmode_done(void)
+{
+       usleep_range(1000, 2000);
+}
+
+static void lp8501_set_led_current(struct lp55xx_led *led, u8 led_current)
+{
+       led->led_current = led_current;
+       lp55xx_write(led->chip, LP8501_REG_LED_CURRENT_BASE + led->chan_nr,
+               led_current);
+}
+
+static int lp8501_post_init_device(struct lp55xx_chip *chip)
+{
+       int ret;
+       u8 val = LP8501_DEFAULT_CFG;
+
+       ret = lp55xx_write(chip, LP8501_REG_ENABLE, LP8501_ENABLE);
+       if (ret)
+               return ret;
+
+       /* Chip startup time is 500 us, 1 - 2 ms gives some margin */
+       usleep_range(1000, 2000);
+
+       if (chip->pdata->clock_mode != LP55XX_CLOCK_EXT)
+               val |= LP8501_INT_CLK;
+
+       ret = lp55xx_write(chip, LP8501_REG_CONFIG, val);
+       if (ret)
+               return ret;
+
+       /* Power selection for each output */
+       return lp55xx_update_bits(chip, LP8501_REG_PWR_CONFIG,
+                               LP8501_PWR_CONFIG_M, chip->pdata->pwr_sel);
+}
+
+static void lp8501_load_engine(struct lp55xx_chip *chip)
+{
+       enum lp55xx_engine_index idx = chip->engine_idx;
+       u8 mask[] = {
+               [LP55XX_ENGINE_1] = LP8501_MODE_ENG1_M,
+               [LP55XX_ENGINE_2] = LP8501_MODE_ENG2_M,
+               [LP55XX_ENGINE_3] = LP8501_MODE_ENG3_M,
+       };
+
+       u8 val[] = {
+               [LP55XX_ENGINE_1] = LP8501_LOAD_ENG1,
+               [LP55XX_ENGINE_2] = LP8501_LOAD_ENG2,
+               [LP55XX_ENGINE_3] = LP8501_LOAD_ENG3,
+       };
+
+       u8 page_sel[] = {
+               [LP55XX_ENGINE_1] = LP8501_PAGE_ENG1,
+               [LP55XX_ENGINE_2] = LP8501_PAGE_ENG2,
+               [LP55XX_ENGINE_3] = LP8501_PAGE_ENG3,
+       };
+
+       lp55xx_update_bits(chip, LP8501_REG_OP_MODE, mask[idx], val[idx]);
+
+       lp8501_wait_opmode_done();
+
+       lp55xx_write(chip, LP8501_REG_PROG_PAGE_SEL, page_sel[idx]);
+}
+
+static void lp8501_stop_engine(struct lp55xx_chip *chip)
+{
+       lp55xx_write(chip, LP8501_REG_OP_MODE, 0);
+       lp8501_wait_opmode_done();
+}
+
+static void lp8501_turn_off_channels(struct lp55xx_chip *chip)
+{
+       int i;
+
+       for (i = 0; i < LP8501_MAX_LEDS; i++)
+               lp55xx_write(chip, LP8501_REG_LED_PWM_BASE + i, 0);
+}
+
+static void lp8501_run_engine(struct lp55xx_chip *chip, bool start)
+{
+       int ret;
+       u8 mode;
+       u8 exec;
+
+       /* stop engine */
+       if (!start) {
+               lp8501_stop_engine(chip);
+               lp8501_turn_off_channels(chip);
+               return;
+       }
+
+       /*
+        * To run the engine,
+        * operation mode and enable register should updated at the same time
+        */
+
+       ret = lp55xx_read(chip, LP8501_REG_OP_MODE, &mode);
+       if (ret)
+               return;
+
+       ret = lp55xx_read(chip, LP8501_REG_ENABLE, &exec);
+       if (ret)
+               return;
+
+       /* change operation mode to RUN only when each engine is loading */
+       if (LP8501_ENG1_IS_LOADING(mode)) {
+               mode = (mode & ~LP8501_MODE_ENG1_M) | LP8501_RUN_ENG1;
+               exec = (exec & ~LP8501_EXEC_ENG1_M) | LP8501_RUN_ENG1;
+       }
+
+       if (LP8501_ENG2_IS_LOADING(mode)) {
+               mode = (mode & ~LP8501_MODE_ENG2_M) | LP8501_RUN_ENG2;
+               exec = (exec & ~LP8501_EXEC_ENG2_M) | LP8501_RUN_ENG2;
+       }
+
+       if (LP8501_ENG3_IS_LOADING(mode)) {
+               mode = (mode & ~LP8501_MODE_ENG3_M) | LP8501_RUN_ENG3;
+               exec = (exec & ~LP8501_EXEC_ENG3_M) | LP8501_RUN_ENG3;
+       }
+
+       lp55xx_write(chip, LP8501_REG_OP_MODE, mode);
+       lp8501_wait_opmode_done();
+
+       lp55xx_update_bits(chip, LP8501_REG_ENABLE, LP8501_EXEC_M, exec);
+}
+
+static int lp8501_update_program_memory(struct lp55xx_chip *chip,
+                                       const u8 *data, size_t size)
+{
+       u8 pattern[LP8501_PROGRAM_LENGTH] = {0};
+       unsigned cmd;
+       char c[3];
+       int update_size;
+       int nrchars;
+       int offset = 0;
+       int ret;
+       int i;
+
+       /* clear program memory before updating */
+       for (i = 0; i < LP8501_PROGRAM_LENGTH; i++)
+               lp55xx_write(chip, LP8501_REG_PROG_MEM + i, 0);
+
+       i = 0;
+       while ((offset < size - 1) && (i < LP8501_PROGRAM_LENGTH)) {
+               /* separate sscanfs because length is working only for %s */
+               ret = sscanf(data + offset, "%2s%n ", c, &nrchars);
+               if (ret != 1)
+                       goto err;
+
+               ret = sscanf(c, "%2x", &cmd);
+               if (ret != 1)
+                       goto err;
+
+               pattern[i] = (u8)cmd;
+               offset += nrchars;
+               i++;
+       }
+
+       /* Each instruction is 16bit long. Check that length is even */
+       if (i % 2)
+               goto err;
+
+       update_size = i;
+       for (i = 0; i < update_size; i++)
+               lp55xx_write(chip, LP8501_REG_PROG_MEM + i, pattern[i]);
+
+       return 0;
+
+err:
+       dev_err(&chip->cl->dev, "wrong pattern format\n");
+       return -EINVAL;
+}
+
+static void lp8501_firmware_loaded(struct lp55xx_chip *chip)
+{
+       const struct firmware *fw = chip->fw;
+
+       if (fw->size > LP8501_PROGRAM_LENGTH) {
+               dev_err(&chip->cl->dev, "firmware data size overflow: %zu\n",
+                       fw->size);
+               return;
+       }
+
+       /*
+        * Program momery sequence
+        *  1) set engine mode to "LOAD"
+        *  2) write firmware data into program memory
+        */
+
+       lp8501_load_engine(chip);
+       lp8501_update_program_memory(chip, fw->data, fw->size);
+}
+
+static void lp8501_led_brightness_work(struct work_struct *work)
+{
+       struct lp55xx_led *led = container_of(work, struct lp55xx_led,
+                                             brightness_work);
+       struct lp55xx_chip *chip = led->chip;
+
+       mutex_lock(&chip->lock);
+       lp55xx_write(chip, LP8501_REG_LED_PWM_BASE + led->chan_nr,
+                    led->brightness);
+       mutex_unlock(&chip->lock);
+}
+
+/* Chip specific configurations */
+static struct lp55xx_device_config lp8501_cfg = {
+       .reset = {
+               .addr = LP8501_REG_RESET,
+               .val  = LP8501_RESET,
+       },
+       .enable = {
+               .addr = LP8501_REG_ENABLE,
+               .val  = LP8501_ENABLE,
+       },
+       .max_channel  = LP8501_MAX_LEDS,
+       .post_init_device   = lp8501_post_init_device,
+       .brightness_work_fn = lp8501_led_brightness_work,
+       .set_led_current    = lp8501_set_led_current,
+       .firmware_cb        = lp8501_firmware_loaded,
+       .run_engine         = lp8501_run_engine,
+};
+
+static int lp8501_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       int ret;
+       struct lp55xx_chip *chip;
+       struct lp55xx_led *led;
+       struct lp55xx_platform_data *pdata;
+       struct device_node *np = client->dev.of_node;
+
+       if (!dev_get_platdata(&client->dev)) {
+               if (np) {
+                       ret = lp55xx_of_populate_pdata(&client->dev, np);
+                       if (ret < 0)
+                               return ret;
+               } else {
+                       dev_err(&client->dev, "no platform data\n");
+                       return -EINVAL;
+               }
+       }
+       pdata = dev_get_platdata(&client->dev);
+
+       chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       led = devm_kzalloc(&client->dev,
+                       sizeof(*led) * pdata->num_channels, GFP_KERNEL);
+       if (!led)
+               return -ENOMEM;
+
+       chip->cl = client;
+       chip->pdata = pdata;
+       chip->cfg = &lp8501_cfg;
+
+       mutex_init(&chip->lock);
+
+       i2c_set_clientdata(client, led);
+
+       ret = lp55xx_init_device(chip);
+       if (ret)
+               goto err_init;
+
+       dev_info(&client->dev, "%s Programmable led chip found\n", id->name);
+
+       ret = lp55xx_register_leds(led, chip);
+       if (ret)
+               goto err_register_leds;
+
+       ret = lp55xx_register_sysfs(chip);
+       if (ret) {
+               dev_err(&client->dev, "registering sysfs failed\n");
+               goto err_register_sysfs;
+       }
+
+       return 0;
+
+err_register_sysfs:
+       lp55xx_unregister_leds(led, chip);
+err_register_leds:
+       lp55xx_deinit_device(chip);
+err_init:
+       return ret;
+}
+
+static int lp8501_remove(struct i2c_client *client)
+{
+       struct lp55xx_led *led = i2c_get_clientdata(client);
+       struct lp55xx_chip *chip = led->chip;
+
+       lp8501_stop_engine(chip);
+       lp55xx_unregister_sysfs(chip);
+       lp55xx_unregister_leds(led, chip);
+       lp55xx_deinit_device(chip);
+
+       return 0;
+}
+
+static const struct i2c_device_id lp8501_id[] = {
+       { "lp8501",  0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, lp8501_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id of_lp8501_leds_match[] = {
+       { .compatible = "ti,lp8501", },
+       {},
+};
+
+MODULE_DEVICE_TABLE(of, of_lp8501_leds_match);
+#endif
+
+static struct i2c_driver lp8501_driver = {
+       .driver = {
+               .name   = "lp8501",
+               .of_match_table = of_match_ptr(of_lp8501_leds_match),
+       },
+       .probe          = lp8501_probe,
+       .remove         = lp8501_remove,
+       .id_table       = lp8501_id,
+};
+
+module_i2c_driver(lp8501_driver);
+
+MODULE_DESCRIPTION("Texas Instruments LP8501 LED drvier");
+MODULE_AUTHOR("Milo Kim");
+MODULE_LICENSE("GPL");
index ca48a7d5502d35fb919de639a4ddb067b6f80baf..3417e5be7b575fa8b44185a2f9fc9bfa9bd154a3 100644 (file)
@@ -135,7 +135,7 @@ static void delete_lt3593_led(struct lt3593_led_data *led)
 
 static int lt3593_led_probe(struct platform_device *pdev)
 {
-       struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
+       struct gpio_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct lt3593_led_data *leds_data;
        int i, ret = 0;
 
@@ -169,7 +169,7 @@ err:
 static int lt3593_led_remove(struct platform_device *pdev)
 {
        int i;
-       struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
+       struct gpio_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct lt3593_led_data *leds_data;
 
        leds_data = platform_get_drvdata(pdev);
index c61c5ebcc08e824e4bea68e3184aabf191632a02..2f9f141084baa2c2743105fa06c30170b84c89ef 100644 (file)
@@ -306,7 +306,7 @@ create_netxbig_led(struct platform_device *pdev,
                   struct netxbig_led_data *led_dat,
                   const struct netxbig_led *template)
 {
-       struct netxbig_led_platform_data *pdata = pdev->dev.platform_data;
+       struct netxbig_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
        int ret;
 
        spin_lock_init(&led_dat->lock);
@@ -354,7 +354,7 @@ create_netxbig_led(struct platform_device *pdev,
 
 static int netxbig_led_probe(struct platform_device *pdev)
 {
-       struct netxbig_led_platform_data *pdata = pdev->dev.platform_data;
+       struct netxbig_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct netxbig_led_data *leds_data;
        int i;
        int ret;
@@ -391,7 +391,7 @@ err_free_leds:
 
 static int netxbig_led_remove(struct platform_device *pdev)
 {
-       struct netxbig_led_platform_data *pdata = pdev->dev.platform_data;
+       struct netxbig_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct netxbig_led_data *leds_data;
        int i;
 
index e7df9875c400f3af314a8aaf8d74ce0f323e720e..141f13438e80ff3c9846c79948cc954466511719 100644 (file)
@@ -321,7 +321,7 @@ static inline int sizeof_ns2_led_priv(int num_leds)
 
 static int ns2_led_probe(struct platform_device *pdev)
 {
-       struct ns2_led_platform_data *pdata = pdev->dev.platform_data;
+       struct ns2_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct ns2_led_priv *priv;
        int i;
        int ret;
index 0c597bdd23f9d175ed4e6ad69af6b446d02746f9..4a0e786b7832bb8834ea4e6a46e20f4e24cf7898 100644 (file)
@@ -446,7 +446,8 @@ static int pca9532_probe(struct i2c_client *client,
        const struct i2c_device_id *id)
 {
        struct pca9532_data *data = i2c_get_clientdata(client);
-       struct pca9532_platform_data *pca9532_pdata = client->dev.platform_data;
+       struct pca9532_platform_data *pca9532_pdata =
+                       dev_get_platdata(&client->dev);
 
        if (!pca9532_pdata)
                return -EIO;
index edf485b773c8730960e0923615d0f8aba348ba04..c3a08b60535bc31048d1246c1d5ef01dd5c12c6b 100644 (file)
@@ -267,7 +267,7 @@ static int pca955x_probe(struct i2c_client *client,
 
        chip = &pca955x_chipdefs[id->driver_data];
        adapter = to_i2c_adapter(client->dev.parent);
-       pdata = client->dev.platform_data;
+       pdata = dev_get_platdata(&client->dev);
 
        /* Make sure the slave address / chip type combo given is possible */
        if ((client->addr & ~((1 << chip->slv_addr_shift) - 1)) !=
index 9aae5679ffb225e8ff48b60ea8875802785c0436..a1065faa84f957bb6a7dc42edb8a3d1c0921eb4e 100644 (file)
  *
  * LED driver for the PCA9633 I2C LED driver (7-bit slave address 0x62)
  *
+ * Note that hardware blinking violates the leds infrastructure driver
+ * interface since the hardware only supports blinking all LEDs with the
+ * same delay_on/delay_off rates.  That is, only the LEDs that are set to
+ * blink will actually blink but all LEDs that are set to blink will blink
+ * in identical fashion.  The delay_on/delay_off values of the last LED
+ * that is set to blink will be used for all of the blinking LEDs.
+ * Hardware blinking is disabled by default but can be enabled by setting
+ * the 'blink_type' member in the platform_data struct to 'PCA9633_HW_BLINK'
+ * or by adding the 'nxp,hw-blink' property to the DTS.
  */
 
 #include <linux/module.h>
@@ -22,6 +31,7 @@
 #include <linux/i2c.h>
 #include <linux/workqueue.h>
 #include <linux/slab.h>
+#include <linux/of.h>
 #include <linux/platform_data/leds-pca9633.h>
 
 /* LED select registers determine the source that drives LED outputs */
 #define PCA9633_LED_PWM                0x2     /* Controlled through PWM */
 #define PCA9633_LED_GRP_PWM    0x3     /* Controlled through PWM/GRPPWM */
 
+#define PCA9633_MODE2_DMBLNK   0x20    /* Enable blinking */
+
 #define PCA9633_MODE1          0x00
 #define PCA9633_MODE2          0x01
 #define PCA9633_PWM_BASE       0x02
+#define PCA9633_GRPPWM         0x06
+#define PCA9633_GRPFREQ                0x07
 #define PCA9633_LEDOUT         0x08
 
+/* Total blink period in milliseconds */
+#define PCA9632_BLINK_PERIOD_MIN       42
+#define PCA9632_BLINK_PERIOD_MAX       10667
+
 static const struct i2c_device_id pca9633_id[] = {
        { "pca9633", 0 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, pca9633_id);
 
+enum pca9633_cmd {
+       BRIGHTNESS_SET,
+       BLINK_SET,
+};
+
 struct pca9633_led {
        struct i2c_client *client;
        struct work_struct work;
        enum led_brightness brightness;
        struct led_classdev led_cdev;
        int led_num; /* 0 .. 3 potentially */
+       enum pca9633_cmd cmd;
        char name[32];
+       u8 gdc;
+       u8 gfrq;
 };
 
-static void pca9633_led_work(struct work_struct *work)
+static void pca9633_brightness_work(struct pca9633_led *pca9633)
 {
-       struct pca9633_led *pca9633 = container_of(work,
-               struct pca9633_led, work);
        u8 ledout = i2c_smbus_read_byte_data(pca9633->client, PCA9633_LEDOUT);
        int shift = 2 * pca9633->led_num;
        u8 mask = 0x3 << shift;
@@ -77,6 +101,43 @@ static void pca9633_led_work(struct work_struct *work)
        }
 }
 
+static void pca9633_blink_work(struct pca9633_led *pca9633)
+{
+       u8 ledout = i2c_smbus_read_byte_data(pca9633->client, PCA9633_LEDOUT);
+       u8 mode2 = i2c_smbus_read_byte_data(pca9633->client, PCA9633_MODE2);
+       int shift = 2 * pca9633->led_num;
+       u8 mask = 0x3 << shift;
+
+       i2c_smbus_write_byte_data(pca9633->client, PCA9633_GRPPWM,
+               pca9633->gdc);
+
+       i2c_smbus_write_byte_data(pca9633->client, PCA9633_GRPFREQ,
+               pca9633->gfrq);
+
+       if (!(mode2 & PCA9633_MODE2_DMBLNK))
+               i2c_smbus_write_byte_data(pca9633->client, PCA9633_MODE2,
+                       mode2 | PCA9633_MODE2_DMBLNK);
+
+       if ((ledout & mask) != (PCA9633_LED_GRP_PWM << shift))
+               i2c_smbus_write_byte_data(pca9633->client, PCA9633_LEDOUT,
+                       (ledout & ~mask) | (PCA9633_LED_GRP_PWM << shift));
+}
+
+static void pca9633_work(struct work_struct *work)
+{
+       struct pca9633_led *pca9633 = container_of(work,
+               struct pca9633_led, work);
+
+       switch (pca9633->cmd) {
+       case BRIGHTNESS_SET:
+               pca9633_brightness_work(pca9633);
+               break;
+       case BLINK_SET:
+               pca9633_blink_work(pca9633);
+               break;
+       };
+}
+
 static void pca9633_led_set(struct led_classdev *led_cdev,
        enum led_brightness value)
 {
@@ -84,6 +145,7 @@ static void pca9633_led_set(struct led_classdev *led_cdev,
 
        pca9633 = container_of(led_cdev, struct pca9633_led, led_cdev);
 
+       pca9633->cmd = BRIGHTNESS_SET;
        pca9633->brightness = value;
 
        /*
@@ -93,6 +155,131 @@ static void pca9633_led_set(struct led_classdev *led_cdev,
        schedule_work(&pca9633->work);
 }
 
+static int pca9633_blink_set(struct led_classdev *led_cdev,
+               unsigned long *delay_on, unsigned long *delay_off)
+{
+       struct pca9633_led *pca9633;
+       unsigned long time_on, time_off, period;
+       u8 gdc, gfrq;
+
+       pca9633 = container_of(led_cdev, struct pca9633_led, led_cdev);
+
+       time_on = *delay_on;
+       time_off = *delay_off;
+
+       /* If both zero, pick reasonable defaults of 500ms each */
+       if (!time_on && !time_off) {
+               time_on = 500;
+               time_off = 500;
+       }
+
+       period = time_on + time_off;
+
+       /* If period not supported by hardware, default to someting sane. */
+       if ((period < PCA9632_BLINK_PERIOD_MIN) ||
+           (period > PCA9632_BLINK_PERIOD_MAX)) {
+               time_on = 500;
+               time_off = 500;
+               period = time_on + time_off;
+       }
+
+       /*
+        * From manual: duty cycle = (GDC / 256) ->
+        *      (time_on / period) = (GDC / 256) ->
+        *              GDC = ((time_on * 256) / period)
+        */
+       gdc = (time_on * 256) / period;
+
+       /*
+        * From manual: period = ((GFRQ + 1) / 24) in seconds.
+        * So, period (in ms) = (((GFRQ + 1) / 24) * 1000) ->
+        *              GFRQ = ((period * 24 / 1000) - 1)
+        */
+       gfrq = (period * 24 / 1000) - 1;
+
+       pca9633->cmd = BLINK_SET;
+       pca9633->gdc = gdc;
+       pca9633->gfrq = gfrq;
+
+       /*
+        * Must use workqueue for the actual I/O since I2C operations
+        * can sleep.
+        */
+       schedule_work(&pca9633->work);
+
+       *delay_on = time_on;
+       *delay_off = time_off;
+
+       return 0;
+}
+
+#if IS_ENABLED(CONFIG_OF)
+static struct pca9633_platform_data *
+pca9633_dt_init(struct i2c_client *client)
+{
+       struct device_node *np = client->dev.of_node, *child;
+       struct pca9633_platform_data *pdata;
+       struct led_info *pca9633_leds;
+       int count;
+
+       count = of_get_child_count(np);
+       if (!count || count > 4)
+               return ERR_PTR(-ENODEV);
+
+       pca9633_leds = devm_kzalloc(&client->dev,
+                               sizeof(struct led_info) * count, GFP_KERNEL);
+       if (!pca9633_leds)
+               return ERR_PTR(-ENOMEM);
+
+       for_each_child_of_node(np, child) {
+               struct led_info led;
+               u32 reg;
+               int res;
+
+               led.name =
+                       of_get_property(child, "label", NULL) ? : child->name;
+               led.default_trigger =
+                       of_get_property(child, "linux,default-trigger", NULL);
+               res = of_property_read_u32(child, "reg", &reg);
+               if (res != 0)
+                       continue;
+               pca9633_leds[reg] = led;
+       }
+       pdata = devm_kzalloc(&client->dev,
+                            sizeof(struct pca9633_platform_data), GFP_KERNEL);
+       if (!pdata)
+               return ERR_PTR(-ENOMEM);
+
+       pdata->leds.leds = pca9633_leds;
+       pdata->leds.num_leds = count;
+
+       /* default to open-drain unless totem pole (push-pull) is specified */
+       if (of_property_read_bool(np, "nxp,totem-pole"))
+               pdata->outdrv = PCA9633_TOTEM_POLE;
+       else
+               pdata->outdrv = PCA9633_OPEN_DRAIN;
+
+       /* default to software blinking unless hardware blinking is specified */
+       if (of_property_read_bool(np, "nxp,hw-blink"))
+               pdata->blink_type = PCA9633_HW_BLINK;
+       else
+               pdata->blink_type = PCA9633_SW_BLINK;
+
+       return pdata;
+}
+
+static const struct of_device_id of_pca9633_match[] = {
+       { .compatible = "nxp,pca963x", },
+       {},
+};
+#else
+static struct pca9633_platform_data *
+pca9633_dt_init(struct i2c_client *client)
+{
+       return ERR_PTR(-ENODEV);
+}
+#endif
+
 static int pca9633_probe(struct i2c_client *client,
                                        const struct i2c_device_id *id)
 {
@@ -100,7 +287,15 @@ static int pca9633_probe(struct i2c_client *client,
        struct pca9633_platform_data *pdata;
        int i, err;
 
-       pdata = client->dev.platform_data;
+       pdata = dev_get_platdata(&client->dev);
+
+       if (!pdata) {
+               pdata = pca9633_dt_init(client);
+               if (IS_ERR(pdata)) {
+                       dev_warn(&client->dev, "could not parse configuration\n");
+                       pdata = NULL;
+               }
+       }
 
        if (pdata) {
                if (pdata->leds.num_leds <= 0 || pdata->leds.num_leds > 4) {
@@ -136,7 +331,10 @@ static int pca9633_probe(struct i2c_client *client,
                pca9633[i].led_cdev.name = pca9633[i].name;
                pca9633[i].led_cdev.brightness_set = pca9633_led_set;
 
-               INIT_WORK(&pca9633[i].work, pca9633_led_work);
+               if (pdata && pdata->blink_type == PCA9633_HW_BLINK)
+                       pca9633[i].led_cdev.blink_set = pca9633_blink_set;
+
+               INIT_WORK(&pca9633[i].work, pca9633_work);
 
                err = led_classdev_register(&client->dev, &pca9633[i].led_cdev);
                if (err < 0)
@@ -181,6 +379,7 @@ static struct i2c_driver pca9633_driver = {
        .driver = {
                .name   = "leds-pca9633",
                .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(of_pca9633_match),
        },
        .probe  = pca9633_probe,
        .remove = pca9633_remove,
index faf52c005e8c230ef255407294e3f44b6beb6b0b..bb6f948985413d4e8c1f5a6b575493a00b2ecef6 100644 (file)
@@ -147,7 +147,7 @@ err:
 
 static int led_pwm_probe(struct platform_device *pdev)
 {
-       struct led_pwm_platform_data *pdata = pdev->dev.platform_data;
+       struct led_pwm_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct led_pwm_priv *priv;
        int i, ret = 0;
 
index 4253a9b03dbfd6b520691003e640bb8e6f0cf29e..358430db6e66d2e2adce01fff0a0ffa66ed8c830 100644 (file)
@@ -142,7 +142,8 @@ static void regulator_led_brightness_set(struct led_classdev *led_cdev,
 
 static int regulator_led_probe(struct platform_device *pdev)
 {
-       struct led_regulator_platform_data *pdata = pdev->dev.platform_data;
+       struct led_regulator_platform_data *pdata =
+                       dev_get_platdata(&pdev->dev);
        struct regulator_led *led;
        struct regulator *vcc;
        int ret = 0;
index adebf4931e1e0fdc65a9f199819b6a26fd975059..397b92a282e737b9047dc28f03473d277b71a7be 100644 (file)
@@ -65,7 +65,7 @@ static DEFINE_SPINLOCK(r_tpu_lock);
 
 static inline u16 r_tpu_read(struct r_tpu_priv *p, int reg_nr)
 {
-       struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data;
+       struct led_renesas_tpu_config *cfg = dev_get_platdata(&p->pdev->dev);
        void __iomem *base = p->mapbase;
        unsigned long offs = reg_nr << 2;
 
@@ -77,7 +77,7 @@ static inline u16 r_tpu_read(struct r_tpu_priv *p, int reg_nr)
 
 static inline void r_tpu_write(struct r_tpu_priv *p, int reg_nr, u16 value)
 {
-       struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data;
+       struct led_renesas_tpu_config *cfg = dev_get_platdata(&p->pdev->dev);
        void __iomem *base = p->mapbase;
        unsigned long offs = reg_nr << 2;
 
@@ -91,7 +91,7 @@ static inline void r_tpu_write(struct r_tpu_priv *p, int reg_nr, u16 value)
 
 static void r_tpu_start_stop_ch(struct r_tpu_priv *p, int start)
 {
-       struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data;
+       struct led_renesas_tpu_config *cfg = dev_get_platdata(&p->pdev->dev);
        unsigned long flags;
        u16 value;
 
@@ -110,7 +110,7 @@ static void r_tpu_start_stop_ch(struct r_tpu_priv *p, int start)
 
 static int r_tpu_enable(struct r_tpu_priv *p, enum led_brightness brightness)
 {
-       struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data;
+       struct led_renesas_tpu_config *cfg = dev_get_platdata(&p->pdev->dev);
        int prescaler[] = { 1, 4, 16, 64 };
        int k, ret;
        unsigned long rate, tmp;
@@ -190,7 +190,7 @@ static void r_tpu_disable(struct r_tpu_priv *p)
 static void r_tpu_set_pin(struct r_tpu_priv *p, enum r_tpu_pin new_state,
                          enum led_brightness brightness)
 {
-       struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data;
+       struct led_renesas_tpu_config *cfg = dev_get_platdata(&p->pdev->dev);
 
        if (p->pin_state == new_state) {
                if (p->pin_state == R_TPU_PIN_GPIO)
@@ -241,7 +241,7 @@ static void r_tpu_set_brightness(struct led_classdev *ldev,
 
 static int r_tpu_probe(struct platform_device *pdev)
 {
-       struct led_renesas_tpu_config *cfg = pdev->dev.platform_data;
+       struct led_renesas_tpu_config *cfg = dev_get_platdata(&pdev->dev);
        struct r_tpu_priv *p;
        struct resource *res;
        int ret;
index e1a0df63a37f7dcdfdf73660a7a9643c4ba68a3d..76483fb5ee45e4f04a025265cb75fffc47c7b932 100644 (file)
@@ -71,7 +71,7 @@ static int s3c24xx_led_remove(struct platform_device *dev)
 
 static int s3c24xx_led_probe(struct platform_device *dev)
 {
-       struct s3c24xx_led_platdata *pdata = dev->dev.platform_data;
+       struct s3c24xx_led_platdata *pdata = dev_get_platdata(&dev->dev);
        struct s3c24xx_gpio_led *led;
        int ret;
 
index 98fe021ba276f9db64fccc23cca6896245c15e1f..8cc304f36728a4e217cbf6716f893a3e6f5aed0c 100644 (file)
@@ -737,7 +737,7 @@ static int tca6507_probe(struct i2c_client *client,
        int i = 0;
 
        adapter = to_i2c_adapter(client->dev.parent);
-       pdata = client->dev.platform_data;
+       pdata = dev_get_platdata(&client->dev);
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
                return -EIO;
index 120815a427014dc80bf5ebb5ccce35c52e4ec46b..c32dad4aedfb265261f074bbd700884d8b725e07 100644 (file)
@@ -246,8 +246,8 @@ static int wm831x_status_probe(struct platform_device *pdev)
        drvdata->wm831x = wm831x;
        drvdata->reg = res->start;
 
-       if (wm831x->dev->platform_data)
-               chip_pdata = wm831x->dev->platform_data;
+       if (dev_get_platdata(wm831x->dev))
+               chip_pdata = dev_get_platdata(wm831x->dev);
        else
                chip_pdata = NULL;
 
index 8a181d56602d89f601ebfdc4766b8744f141b759..3f75fd22fd495d0db8bf552061355be43315a8e8 100644 (file)
@@ -203,7 +203,7 @@ static int wm8350_led_probe(struct platform_device *pdev)
 {
        struct regulator *isink, *dcdc;
        struct wm8350_led *led;
-       struct wm8350_led_platform_data *pdata = pdev->dev.platform_data;
+       struct wm8350_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
        int i;
 
        if (pdata == NULL) {
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 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 07f257d44a1e00a67b84a58685c5a2e490ce5ca8..da3af631f21be91a79c46ce383aca340271085bb 100644 (file)
@@ -106,7 +106,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 +273,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];
@@ -715,15 +715,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 +722,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, 0);
+               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 +739,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)
@@ -1249,8 +1218,9 @@ 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;
 
@@ -1258,14 +1228,6 @@ static void __bond_netpoll_cleanup(struct bonding *bond)
                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)
 {
@@ -1273,23 +1235,15 @@ static int bond_netpoll_setup(struct net_device *dev, struct netpoll_info *ni, g
        struct slave *slave;
        int i, err = 0;
 
-       read_lock(&bond->lock);
        bond_for_each_slave(bond, slave, i) {
                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)
 {
@@ -1834,7 +1788,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);
@@ -3234,6 +3188,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;
        }
index dc36a3d7d9e983a15583260a572e6dac7451acb5..ae02c194c01b6909e379144ac68f2dbb8a08a20d 100644 (file)
@@ -501,20 +501,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 (!rtnl_trylock())
+               return restart_syscall();
+
        if (bond->slave_cnt != 0) {
                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 +527,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,
@@ -1295,8 +1302,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 +1313,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",
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 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 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 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 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 712779fb12b7d80416db0a4349257f046ae0d11d..9647976d11834e4186adbcae647fd83707d19c52 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)
@@ -262,8 +262,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 +277,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 +287,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 */
@@ -904,9 +935,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);
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 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..aec6f5802da584e07a8fa0d05201e424dd96bfae 100644 (file)
@@ -1705,3 +1705,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..f1d818f9bb01b526b55acfe7cba48be336124046 100644 (file)
@@ -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 205753a04cfcb22e8904dbe2e3e203d82df32552..40374063c01ecadd862fa40e75729158e1022a42 100644 (file)
@@ -1113,7 +1113,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 +1142,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 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 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..fedc0a05b218324c891364eac55379a12ca1f4ef 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,26 @@ 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_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 +1145,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 +2773,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 36435499814b78d34020503caa41fdb00d2cd57f..f66ac2000c001c541c8ae7bee6e488af07db2692 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>
 
@@ -156,10 +157,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 +222,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. */
@@ -847,6 +849,8 @@ static bool tile_net_poll_aux(struct tile_net_cpu *info, int index)
                }
        }
 
+       u64_stats_update_begin(&stats->syncp);
+
        if (filter) {
 
                /* ISSUE: Update "drop" statistics? */
@@ -881,6 +885,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 +1913,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);
@@ -2089,8 +2097,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 +2137,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 +2318,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,
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..74907f53fdb40d45046749c88398967cf704edb4 100644 (file)
@@ -597,6 +597,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))
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 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 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..76e38d3540c00d6102705b734126e45112a269dd 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;
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 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 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 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 3952ddf2ddb2bb596ffca3d0ff951238774bdb98..1531a4fc09601bd101fde1e20a528d7631f8baf8 100644 (file)
@@ -758,7 +758,7 @@ int iwl_alive_start(struct iwl_priv *priv)
                                         BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
                if (ret)
                        return ret;
-       } else {
+       } else if (priv->lib->bt_params) {
                /*
                 * default is 2-wire BT coexexistence support
                 */
index ff8cc75c189d4d842abf8611fb8c5e7c7a63bf38..a70c7b9d9bad897345fb1e1e89d5c421e0d8a3da 100644 (file)
@@ -97,6 +97,8 @@
 
 #define APMG_PCIDEV_STT_VAL_L1_ACT_DIS         (0x00000800)
 
+#define APMG_RTC_INT_STT_RFKILL                (0x10000000)
+
 /* Device system time */
 #define DEVICE_SYSTEM_TIME_REG 0xA0206C
 
index 7e5e5c2f9f87316f5319605b1d9c6814c2940dc0..83da884cf3032564df37a96be42c1601496fbc52 100644 (file)
@@ -134,7 +134,7 @@ struct wowlan_key_data {
        struct iwl_wowlan_rsc_tsc_params_cmd *rsc_tsc;
        struct iwl_wowlan_tkip_params_cmd *tkip;
        bool error, use_rsc_tsc, use_tkip;
-       int gtk_key_idx;
+       int wep_key_idx;
 };
 
 static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
@@ -188,8 +188,8 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
                        wkc.wep_key.key_offset = 0;
                } else {
                        /* others start at 1 */
-                       data->gtk_key_idx++;
-                       wkc.wep_key.key_offset = data->gtk_key_idx;
+                       data->wep_key_idx++;
+                       wkc.wep_key.key_offset = data->wep_key_idx;
                }
 
                ret = iwl_mvm_send_cmd_pdu(mvm, WEP_KEY, CMD_SYNC,
@@ -316,8 +316,13 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
                mvm->ptk_ivlen = key->iv_len;
                mvm->ptk_icvlen = key->icv_len;
        } else {
-               data->gtk_key_idx++;
-               key->hw_key_idx = data->gtk_key_idx;
+               /*
+                * firmware only supports TSC/RSC for a single key,
+                * so if there are multiple keep overwriting them
+                * with new ones -- this relies on mac80211 doing
+                * list_add_tail().
+                */
+               key->hw_key_idx = 1;
                mvm->gtk_ivlen = key->iv_len;
                mvm->gtk_icvlen = key->icv_len;
        }
index e56ed2a848886ce6c9001ef9a69a12d54c5f102b..c24a744910acd447c0b7376670e5e97b038cb09c 100644 (file)
@@ -988,7 +988,11 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        char buf[100];
 
-       if (!dbgfs_dir)
+       /*
+        * Check if debugfs directory already exist before creating it.
+        * This may happen when, for example, resetting hw or suspend-resume
+        */
+       if (!dbgfs_dir || mvmvif->dbgfs_dir)
                return;
 
        mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir);
index b60d14151721da3cb141b9b74ac0e3aee2d43a92..365095a0c3b3101e3c87b76036dbd82b352b9deb 100644 (file)
@@ -69,7 +69,6 @@
 /* Scan Commands, Responses, Notifications */
 
 /* Masks for iwl_scan_channel.type flags */
-#define SCAN_CHANNEL_TYPE_PASSIVE      0
 #define SCAN_CHANNEL_TYPE_ACTIVE       BIT(0)
 #define SCAN_CHANNEL_NARROW_BAND       BIT(22)
 
index e08683b2053183f7e7ea9df370a37bdb4b70c2e4..f19baf0dea6b9c84dac1a86d393c8ddb68aa5f53 100644 (file)
@@ -257,7 +257,11 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
        if (ret)
                return ret;
 
-       return ieee80211_register_hw(mvm->hw);
+       ret = ieee80211_register_hw(mvm->hw);
+       if (ret)
+               iwl_mvm_leds_exit(mvm);
+
+       return ret;
 }
 
 static void iwl_mvm_mac_tx(struct ieee80211_hw *hw,
@@ -385,6 +389,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
        ieee80211_wake_queues(mvm->hw);
 
        mvm->vif_count = 0;
+       mvm->rx_ba_sessions = 0;
 }
 
 static int iwl_mvm_mac_start(struct ieee80211_hw *hw)
@@ -506,6 +511,27 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
        if (ret)
                goto out_unlock;
 
+       /*
+        * TODO: remove this temporary code.
+        * Currently MVM FW supports power management only on single MAC.
+        * If new interface added, disable PM on existing interface.
+        * P2P device is a special case, since it is handled by FW similary to
+        * scan. If P2P deviced is added, PM remains enabled on existing
+        * interface.
+        * Note: the method below does not count the new interface being added
+        * at this moment.
+        */
+       if (vif->type != NL80211_IFTYPE_P2P_DEVICE)
+               mvm->vif_count++;
+       if (mvm->vif_count > 1) {
+               IWL_DEBUG_MAC80211(mvm,
+                                  "Disable power on existing interfaces\n");
+               ieee80211_iterate_active_interfaces_atomic(
+                                           mvm->hw,
+                                           IEEE80211_IFACE_ITER_NORMAL,
+                                           iwl_mvm_pm_disable_iterator, mvm);
+       }
+
        /*
         * The AP binding flow can be done only after the beacon
         * template is configured (which happens only in the mac80211
@@ -529,27 +555,6 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
                goto out_unlock;
        }
 
-       /*
-        * TODO: remove this temporary code.
-        * Currently MVM FW supports power management only on single MAC.
-        * If new interface added, disable PM on existing interface.
-        * P2P device is a special case, since it is handled by FW similary to
-        * scan. If P2P deviced is added, PM remains enabled on existing
-        * interface.
-        * Note: the method below does not count the new interface being added
-        * at this moment.
-        */
-       if (vif->type != NL80211_IFTYPE_P2P_DEVICE)
-               mvm->vif_count++;
-       if (mvm->vif_count > 1) {
-               IWL_DEBUG_MAC80211(mvm,
-                                  "Disable power on existing interfaces\n");
-               ieee80211_iterate_active_interfaces_atomic(
-                                           mvm->hw,
-                                           IEEE80211_IFACE_ITER_NORMAL,
-                                           iwl_mvm_pm_disable_iterator, mvm);
-       }
-
        ret = iwl_mvm_mac_ctxt_add(mvm, vif);
        if (ret)
                goto out_release;
@@ -1006,6 +1011,21 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
        mutex_lock(&mvm->mutex);
        if (old_state == IEEE80211_STA_NOTEXIST &&
            new_state == IEEE80211_STA_NONE) {
+               /*
+                * Firmware bug - it'll crash if the beacon interval is less
+                * than 16. We can't avoid connecting at all, so refuse the
+                * station state change, this will cause mac80211 to abandon
+                * attempts to connect to this AP, and eventually wpa_s will
+                * blacklist the AP...
+                */
+               if (vif->type == NL80211_IFTYPE_STATION &&
+                   vif->bss_conf.beacon_int < 16) {
+                       IWL_ERR(mvm,
+                               "AP %pM beacon interval is %d, refusing due to firmware bug!\n",
+                               sta->addr, vif->bss_conf.beacon_int);
+                       ret = -EINVAL;
+                       goto out_unlock;
+               }
                ret = iwl_mvm_add_sta(mvm, vif, sta);
        } else if (old_state == IEEE80211_STA_NONE &&
                   new_state == IEEE80211_STA_AUTH) {
@@ -1038,6 +1058,7 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
        } else {
                ret = -EIO;
        }
+ out_unlock:
        mutex_unlock(&mvm->mutex);
 
        return ret;
index d40d7db185d6cdbb22ca2a2d1fefef0794970971..420e82d379d9826690d297de690c3e84a2307f87 100644 (file)
@@ -419,6 +419,7 @@ struct iwl_mvm {
        struct work_struct sta_drained_wk;
        unsigned long sta_drained[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)];
        atomic_t pending_frames[IWL_MVM_STATION_COUNT];
+       u8 rx_ba_sessions;
 
        /* configured by mac80211 */
        u32 rts_threshold;
index 2157b0f8ced5cc7c314a246d758a869128e57c59..acdff6b67e0460e669e5c25192af245df93ac4b5 100644 (file)
@@ -137,8 +137,8 @@ static void iwl_mvm_scan_fill_ssids(struct iwl_scan_cmd *cmd,
 {
        int fw_idx, req_idx;
 
-       fw_idx = 0;
-       for (req_idx = req->n_ssids - 1; req_idx > 0; req_idx--) {
+       for (req_idx = req->n_ssids - 1, fw_idx = 0; req_idx > 0;
+            req_idx--, fw_idx++) {
                cmd->direct_scan[fw_idx].id = WLAN_EID_SSID;
                cmd->direct_scan[fw_idx].len = req->ssids[req_idx].ssid_len;
                memcpy(cmd->direct_scan[fw_idx].ssid,
@@ -153,7 +153,9 @@ static void iwl_mvm_scan_fill_ssids(struct iwl_scan_cmd *cmd,
  * just to notify that this scan is active and not passive.
  * In order to notify the FW of the number of SSIDs we wish to scan (including
  * the zero-length one), we need to set the corresponding bits in chan->type,
- * one for each SSID, and set the active bit (first).
+ * one for each SSID, and set the active bit (first). The first SSID is already
+ * included in the probe template, so we need to set only req->n_ssids - 1 bits
+ * in addition to the first bit.
  */
 static u16 iwl_mvm_get_active_dwell(enum ieee80211_band band, int n_ssids)
 {
@@ -176,19 +178,12 @@ static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd,
        struct iwl_scan_channel *chan = (struct iwl_scan_channel *)
                (cmd->data + le16_to_cpu(cmd->tx_cmd.len));
        int i;
-       __le32 chan_type_value;
-
-       if (req->n_ssids > 0)
-               chan_type_value = cpu_to_le32(BIT(req->n_ssids + 1) - 1);
-       else
-               chan_type_value = SCAN_CHANNEL_TYPE_PASSIVE;
 
        for (i = 0; i < cmd->channel_count; i++) {
                chan->channel = cpu_to_le16(req->channels[i]->hw_value);
+               chan->type = cpu_to_le32(BIT(req->n_ssids) - 1);
                if (req->channels[i]->flags & IEEE80211_CHAN_PASSIVE_SCAN)
-                       chan->type = SCAN_CHANNEL_TYPE_PASSIVE;
-               else
-                       chan->type = chan_type_value;
+                       chan->type &= cpu_to_le32(~SCAN_CHANNEL_TYPE_ACTIVE);
                chan->active_dwell = cpu_to_le16(active_dwell);
                chan->passive_dwell = cpu_to_le16(passive_dwell);
                chan->iteration_count = cpu_to_le16(1);
index 62fe5209093bf7637cb024b2c81dfd301cfd4649..563f559b902da8560f7cbdd06726872d7849b34b 100644 (file)
@@ -608,6 +608,8 @@ int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *bsta)
        return ret;
 }
 
+#define IWL_MAX_RX_BA_SESSIONS 16
+
 int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                       int tid, u16 ssn, bool start)
 {
@@ -618,11 +620,20 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
 
        lockdep_assert_held(&mvm->mutex);
 
+       if (start && mvm->rx_ba_sessions >= IWL_MAX_RX_BA_SESSIONS) {
+               IWL_WARN(mvm, "Not enough RX BA SESSIONS\n");
+               return -ENOSPC;
+       }
+
        cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color);
        cmd.sta_id = mvm_sta->sta_id;
        cmd.add_modify = STA_MODE_MODIFY;
-       cmd.add_immediate_ba_tid = (u8) tid;
-       cmd.add_immediate_ba_ssn = cpu_to_le16(ssn);
+       if (start) {
+               cmd.add_immediate_ba_tid = (u8) tid;
+               cmd.add_immediate_ba_ssn = cpu_to_le16(ssn);
+       } else {
+               cmd.remove_immediate_ba_tid = (u8) tid;
+       }
        cmd.modify_mask = start ? STA_MODIFY_ADD_BA_TID :
                                  STA_MODIFY_REMOVE_BA_TID;
 
@@ -648,6 +659,14 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                break;
        }
 
+       if (!ret) {
+               if (start)
+                       mvm->rx_ba_sessions++;
+               else if (mvm->rx_ba_sessions > 0)
+                       /* check that restart flow didn't zero the counter */
+                       mvm->rx_ba_sessions--;
+       }
+
        return ret;
 }
 
@@ -896,6 +915,7 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
        struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
        u16 txq_id;
+       enum iwl_mvm_agg_state old_state;
 
        /*
         * First set the agg state to OFF to avoid calling
@@ -905,13 +925,17 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        txq_id = tid_data->txq_id;
        IWL_DEBUG_TX_QUEUES(mvm, "Flush AGG: sta %d tid %d q %d state %d\n",
                            mvmsta->sta_id, tid, txq_id, tid_data->state);
+       old_state = tid_data->state;
        tid_data->state = IWL_AGG_OFF;
        spin_unlock_bh(&mvmsta->lock);
 
-       if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), true))
-               IWL_ERR(mvm, "Couldn't flush the AGG queue\n");
+       if (old_state >= IWL_AGG_ON) {
+               if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), true))
+                       IWL_ERR(mvm, "Couldn't flush the AGG queue\n");
+
+               iwl_trans_txq_disable(mvm->trans, tid_data->txq_id);
+       }
 
-       iwl_trans_txq_disable(mvm->trans, tid_data->txq_id);
        mvm->queue_to_mac80211[tid_data->txq_id] =
                                IWL_INVALID_MAC80211_QUEUE;
 
index 81f3ea5b09a4b7f26d0f4bb7877e50dedea6cd38..ff13458efc27096343f17e5c408465d9dce1253a 100644 (file)
@@ -130,6 +130,7 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
        {IWL_PCI_DEVICE(0x423C, 0x1306, iwl5150_abg_cfg)}, /* Half Mini Card */
        {IWL_PCI_DEVICE(0x423C, 0x1221, iwl5150_agn_cfg)}, /* Mini Card */
        {IWL_PCI_DEVICE(0x423C, 0x1321, iwl5150_agn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x423C, 0x1326, iwl5150_abg_cfg)}, /* Half Mini Card */
 
        {IWL_PCI_DEVICE(0x423D, 0x1211, iwl5150_agn_cfg)}, /* Mini Card */
        {IWL_PCI_DEVICE(0x423D, 0x1311, iwl5150_agn_cfg)}, /* Half Mini Card */
index fd848cd1583ebeb3372792911849a0eec25d9667..f600e68a410a1abe454170bd65d29b5937df41a9 100644 (file)
@@ -888,6 +888,14 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
 
                iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
                if (hw_rfkill) {
+                       /*
+                        * Clear the interrupt in APMG if the NIC is going down.
+                        * Note that when the NIC exits RFkill (else branch), we
+                        * can't access prph and the NIC will be reset in
+                        * start_hw anyway.
+                        */
+                       iwl_write_prph(trans, APMG_RTC_INT_STT_REG,
+                                      APMG_RTC_INT_STT_RFKILL);
                        set_bit(STATUS_RFKILL, &trans_pcie->status);
                        if (test_and_clear_bit(STATUS_HCMD_ACTIVE,
                                               &trans_pcie->status))
index 826c15602c469a524b857c135f7b38cb4e5782a1..96cfcdd390794060ee6c72c3951984f33da5ff38 100644 (file)
@@ -670,6 +670,11 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
                return err;
        }
 
+       /* Reset the entire device */
+       iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+
+       usleep_range(10, 15);
+
        iwl_pcie_apm_init(trans);
 
        /* From now on, the op_mode will be kept updated about RF kill state */
index 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..cc334d529dbe9eae4d5cda6bd4dfc029715c1b73 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");
+       }
 }
 
 /*
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..ba043ca2a34a87fbb01f1a468f799e6ab30bf525 100644 (file)
@@ -1425,6 +1425,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..5644c7f86fcb1cb93b18b9faf711f29618a0edd4 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,7 +409,7 @@ 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;
@@ -403,7 +418,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
        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 +431,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 +442,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 +460,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,11 +496,39 @@ 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);
+       mwifiex_free_adapter(adapter);
 done:
        if (adapter->cal_data) {
                release_firmware(adapter->cal_data);
@@ -487,6 +536,7 @@ done:
        }
        release_firmware(adapter->firmware);
        complete(&adapter->fw_load);
+       up(adapter->card_sem);
        return;
 }
 
@@ -796,18 +846,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 +874,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 +894,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 +905,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 +920,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 +956,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..9ee3b1b7c3656b4bcf6f3d27bc4ed61b82f7b15f 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);
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 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..c071ce91c8b2ea7c67fdf73787a9f210173efb0d 100644 (file)
@@ -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 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 6bb7cf2de556b559d1f54f9d1c7c3ff297138a3a..3f473d158d79567447ae720dd8d4bb48cf1e53b6 100644 (file)
@@ -550,7 +550,8 @@ int __init of_flat_dt_match(unsigned long node, const char *const *compat)
  */
 void __init early_init_dt_check_for_initrd(unsigned long node)
 {
-       unsigned long start, end, len;
+       u64 start, end;
+       unsigned long len;
        __be32 *prop;
 
        pr_debug("Looking for initrd properties... ");
@@ -558,15 +559,16 @@ void __init early_init_dt_check_for_initrd(unsigned long node)
        prop = of_get_flat_dt_prop(node, "linux,initrd-start", &len);
        if (!prop)
                return;
-       start = of_read_ulong(prop, len/4);
+       start = of_read_number(prop, len/4);
 
        prop = of_get_flat_dt_prop(node, "linux,initrd-end", &len);
        if (!prop)
                return;
-       end = of_read_ulong(prop, len/4);
+       end = of_read_number(prop, len/4);
 
        early_init_dt_setup_initrd_arch(start, end);
-       pr_debug("initrd_start=0x%lx  initrd_end=0x%lx\n", start, end);
+       pr_debug("initrd_start=0x%llx  initrd_end=0x%llx\n",
+                (unsigned long long)start, (unsigned long long)end);
 }
 #else
 inline void early_init_dt_check_for_initrd(unsigned long node)
index e0a6514ab46c20eb902453c3b321774d1e787ba0..b0d1ff8b09917dbcd197ec1a50ac0bcd1f93fd4a 100644 (file)
@@ -196,7 +196,7 @@ EXPORT_SYMBOL(of_device_alloc);
  * Returns pointer to created platform device, or NULL if a device was not
  * registered.  Unavailable devices will not get registered.
  */
-struct platform_device *of_platform_device_create_pdata(
+static struct platform_device *of_platform_device_create_pdata(
                                        struct device_node *np,
                                        const char *bus_id,
                                        void *platform_data,
index e79e006eb9abc4eab4722aa483d2c6fb38a8c455..9ee04b4b68bf39569acd6dd360c62a6cb4e4b76e 100644 (file)
@@ -811,18 +811,28 @@ int iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev)
        return pcidev->irq;
 }
 
-static struct iosapic_info *first_isi = NULL;
+static struct iosapic_info *iosapic_list;
 
 #ifdef CONFIG_64BIT
-int iosapic_serial_irq(int num)
+int iosapic_serial_irq(struct parisc_device *dev)
 {
-       struct iosapic_info *isi = first_isi;
-       struct irt_entry *irte = NULL;  /* only used if PAT PDC */
+       struct iosapic_info *isi;
+       struct irt_entry *irte;
        struct vector_info *vi;
-       int isi_line;   /* line used by device */
+       int cnt;
+       int intin;
+
+       intin = (dev->mod_info >> 24) & 15;
 
        /* lookup IRT entry for isi/slot/pin set */
-       irte = &irt_cell[num];
+       for (cnt = 0; cnt < irt_num_entry; cnt++) {
+               irte = &irt_cell[cnt];
+               if (COMPARE_IRTE_ADDR(irte, dev->mod0) &&
+                   irte->dest_iosapic_intin == intin)
+                       break;
+       }
+       if (cnt >= irt_num_entry)
+               return 0; /* no irq found, force polling */
 
        DBG_IRT("iosapic_serial_irq(): irte %p %x %x %x %x %x %x %x %x\n",
                irte,
@@ -834,11 +844,17 @@ int iosapic_serial_irq(int num)
                irte->src_seg_id,
                irte->dest_iosapic_intin,
                (u32) irte->dest_iosapic_addr);
-       isi_line = irte->dest_iosapic_intin;
+
+       /* search for iosapic */
+       for (isi = iosapic_list; isi; isi = isi->isi_next)
+               if (isi->isi_hpa == dev->mod0)
+                       break;
+       if (!isi)
+               return 0; /* no iosapic found, force polling */
 
        /* get vector info for this input line */
-       vi = isi->isi_vector + isi_line;
-       DBG_IRT("iosapic_serial_irq:  line %d vi 0x%p\n", isi_line, vi);
+       vi = isi->isi_vector + intin;
+       DBG_IRT("iosapic_serial_irq:  line %d vi 0x%p\n", iosapic_intin, vi);
 
        /* If this IRQ line has already been setup, skip it */
        if (vi->irte)
@@ -941,8 +957,8 @@ void *iosapic_register(unsigned long hpa)
                vip->irqline = (unsigned char) cnt;
                vip->iosapic = isi;
        }
-       if (!first_isi)
-               first_isi = isi;
+       isi->isi_next = iosapic_list;
+       iosapic_list = isi;
        return isi;
 }
 
index 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 dbdc5f7e2b294fad4adfe3ae676e258c5af6abbe..c78cc432edab798b68404af1a02b67128e7c3ec1 100644 (file)
@@ -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 e37fea6e178d2dab00d3334848d231117d525013..a599a6bbdf375cf5d50bea221275738020907888 100644 (file)
@@ -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;
 }
 
index 569f82fc9e22bb826fbfca36ba74b891cc15b0d8..3b94cfcfa03bee1dd1a1d319f9d038a46b07b834 100644 (file)
@@ -14,15 +14,12 @@ config PCIEPORTBUS
 # Include service Kconfig here
 #
 config HOTPLUG_PCI_PCIE
-       tristate "PCI Express Hotplug driver"
+       bool "PCI Express Hotplug driver"
        depends on HOTPLUG_PCI && PCIEPORTBUS
        help
          Say Y here if you have a motherboard that supports PCI Express Native
          Hotplug
 
-         To compile this driver as a module, choose M here: the
-         module will be called pciehp.
-
          When in doubt, say N.
 
 source "drivers/pci/pcie/aer/Kconfig"
index 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,
 };
 
diff --git a/drivers/regulator/88pm800.c b/drivers/regulator/88pm800.c
new file mode 100644 (file)
index 0000000..c72fe95
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ * Regulators driver for Marvell 88PM800
+ *
+ * Copyright (C) 2012 Marvell International Ltd.
+ * Joseph(Yossi) Hanin <yhanin@marvell.com>
+ * Yi Zhang <yizhang@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/88pm80x.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/regulator/of_regulator.h>
+
+/* LDO1 with DVC[0..3] */
+#define PM800_LDO1_VOUT                (0x08) /* VOUT1 */
+#define PM800_LDO1_VOUT_2      (0x09)
+#define PM800_LDO1_VOUT_3      (0x0A)
+#define PM800_LDO2_VOUT                (0x0B)
+#define PM800_LDO3_VOUT                (0x0C)
+#define PM800_LDO4_VOUT                (0x0D)
+#define PM800_LDO5_VOUT                (0x0E)
+#define PM800_LDO6_VOUT                (0x0F)
+#define PM800_LDO7_VOUT                (0x10)
+#define PM800_LDO8_VOUT                (0x11)
+#define PM800_LDO9_VOUT                (0x12)
+#define PM800_LDO10_VOUT       (0x13)
+#define PM800_LDO11_VOUT       (0x14)
+#define PM800_LDO12_VOUT       (0x15)
+#define PM800_LDO13_VOUT       (0x16)
+#define PM800_LDO14_VOUT       (0x17)
+#define PM800_LDO15_VOUT       (0x18)
+#define PM800_LDO16_VOUT       (0x19)
+#define PM800_LDO17_VOUT       (0x1A)
+#define PM800_LDO18_VOUT       (0x1B)
+#define PM800_LDO19_VOUT       (0x1C)
+
+/* BUCK1 with DVC[0..3] */
+#define PM800_BUCK1            (0x3C)
+#define PM800_BUCK1_1          (0x3D)
+#define PM800_BUCK1_2          (0x3E)
+#define PM800_BUCK1_3          (0x3F)
+#define PM800_BUCK2            (0x40)
+#define PM800_BUCK3            (0x41)
+#define PM800_BUCK3            (0x41)
+#define PM800_BUCK4            (0x42)
+#define PM800_BUCK4_1          (0x43)
+#define PM800_BUCK4_2          (0x44)
+#define PM800_BUCK4_3          (0x45)
+#define PM800_BUCK5            (0x46)
+
+#define PM800_BUCK_ENA         (0x50)
+#define PM800_LDO_ENA1_1       (0x51)
+#define PM800_LDO_ENA1_2       (0x52)
+#define PM800_LDO_ENA1_3       (0x53)
+
+#define PM800_LDO_ENA2_1       (0x56)
+#define PM800_LDO_ENA2_2       (0x57)
+#define PM800_LDO_ENA2_3       (0x58)
+
+#define PM800_BUCK1_MISC1      (0x78)
+#define PM800_BUCK3_MISC1      (0x7E)
+#define PM800_BUCK4_MISC1      (0x81)
+#define PM800_BUCK5_MISC1      (0x84)
+
+struct pm800_regulator_info {
+       struct regulator_desc desc;
+       int max_ua;
+};
+
+struct pm800_regulators {
+       struct regulator_dev *regulators[PM800_ID_RG_MAX];
+       struct pm80x_chip *chip;
+       struct regmap *map;
+};
+
+/*
+ * vreg - the buck regs string.
+ * ereg - the string for the enable register.
+ * ebit - the bit number in the enable register.
+ * amax - the current
+ * Buck has 2 kinds of voltage steps. It is easy to find voltage by ranges,
+ * not the constant voltage table.
+ * n_volt - Number of available selectors
+ */
+#define PM800_BUCK(vreg, ereg, ebit, amax, volt_ranges, n_volt)                \
+{                                                                      \
+       .desc   = {                                                     \
+               .name   = #vreg,                                        \
+               .ops    = &pm800_volt_range_ops,                        \
+               .type   = REGULATOR_VOLTAGE,                            \
+               .id     = PM800_ID_##vreg,                              \
+               .owner  = THIS_MODULE,                                  \
+               .n_voltages             = n_volt,                       \
+               .linear_ranges          = volt_ranges,                  \
+               .n_linear_ranges        = ARRAY_SIZE(volt_ranges),      \
+               .vsel_reg               = PM800_##vreg,                 \
+               .vsel_mask              = 0x7f,                         \
+               .enable_reg             = PM800_##ereg,                 \
+               .enable_mask            = 1 << (ebit),                  \
+       },                                                              \
+       .max_ua         = (amax),                                       \
+}
+
+/*
+ * vreg - the LDO regs string
+ * ereg -  the string for the enable register.
+ * ebit - the bit number in the enable register.
+ * amax - the current
+ * volt_table - the LDO voltage table
+ * For all the LDOes, there are too many ranges. Using volt_table will be
+ * simpler and faster.
+ */
+#define PM800_LDO(vreg, ereg, ebit, amax, ldo_volt_table)              \
+{                                                                      \
+       .desc   = {                                                     \
+               .name   = #vreg,                                        \
+               .ops    = &pm800_volt_table_ops,                        \
+               .type   = REGULATOR_VOLTAGE,                            \
+               .id     = PM800_ID_##vreg,                              \
+               .owner  = THIS_MODULE,                                  \
+               .n_voltages = ARRAY_SIZE(ldo_volt_table),               \
+               .vsel_reg       = PM800_##vreg##_VOUT,                  \
+               .vsel_mask      = 0x1f,                                 \
+               .enable_reg     = PM800_##ereg,                         \
+               .enable_mask    = 1 << (ebit),                          \
+               .volt_table     = ldo_volt_table,                       \
+       },                                                              \
+       .max_ua         = (amax),                                       \
+}
+
+/* Ranges are sorted in ascending order. */
+static const struct regulator_linear_range buck1_volt_range[] = {
+       { .min_uV = 600000, .max_uV = 1587500, .min_sel = 0, .max_sel = 0x4f,
+         .uV_step = 12500 },
+       { .min_uV = 1600000, .max_uV = 1800000, .min_sel = 0x50,
+         .max_sel = 0x54, .uV_step = 50000 },
+};
+
+/* BUCK 2~5 have same ranges. */
+static const struct regulator_linear_range buck2_5_volt_range[] = {
+       { .min_uV = 600000, .max_uV = 1587500,  .min_sel = 0, .max_sel = 0x4f,
+         .uV_step = 12500 },
+       { .min_uV = 1600000, .max_uV = 3300000, .min_sel = 0x50,
+         .max_sel = 0x72, .uV_step = 50000 },
+};
+
+static const unsigned int ldo1_volt_table[] = {
+       600000,  650000,  700000,  750000,  800000,  850000,  900000,  950000,
+       1000000, 1050000, 1100000, 1150000, 1200000, 1300000, 1400000, 1500000,
+};
+
+static const unsigned int ldo2_volt_table[] = {
+       1700000, 1800000, 1900000, 2000000, 2100000, 2500000, 2700000, 2800000,
+};
+
+/* LDO 3~17 have same voltage table. */
+static const unsigned int ldo3_17_volt_table[] = {
+       1200000, 1250000, 1700000, 1800000, 1850000, 1900000, 2500000, 2600000,
+       2700000, 2750000, 2800000, 2850000, 2900000, 3000000, 3100000, 3300000,
+};
+
+/* LDO 18~19 have same voltage table. */
+static const unsigned int ldo18_19_volt_table[] = {
+       1700000, 1800000, 1900000, 2500000, 2800000, 2900000, 3100000, 3300000,
+};
+
+static int pm800_get_current_limit(struct regulator_dev *rdev)
+{
+       struct pm800_regulator_info *info = rdev_get_drvdata(rdev);
+
+       return info->max_ua;
+}
+
+static struct regulator_ops pm800_volt_range_ops = {
+       .list_voltage = regulator_list_voltage_linear_range,
+       .map_voltage = regulator_map_voltage_linear_range,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .get_current_limit = pm800_get_current_limit,
+};
+
+static struct regulator_ops pm800_volt_table_ops = {
+       .list_voltage = regulator_list_voltage_table,
+       .map_voltage = regulator_map_voltage_iterate,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .get_current_limit = pm800_get_current_limit,
+};
+
+/* The array is indexed by id(PM800_ID_XXX) */
+static struct pm800_regulator_info pm800_regulator_info[] = {
+       PM800_BUCK(BUCK1, BUCK_ENA, 0, 3000000, buck1_volt_range, 0x55),
+       PM800_BUCK(BUCK2, BUCK_ENA, 1, 1200000, buck2_5_volt_range, 0x73),
+       PM800_BUCK(BUCK3, BUCK_ENA, 2, 1200000, buck2_5_volt_range, 0x73),
+       PM800_BUCK(BUCK4, BUCK_ENA, 3, 1200000, buck2_5_volt_range, 0x73),
+       PM800_BUCK(BUCK5, BUCK_ENA, 4, 1200000, buck2_5_volt_range, 0x73),
+
+       PM800_LDO(LDO1, LDO_ENA1_1, 0, 200000, ldo1_volt_table),
+       PM800_LDO(LDO2, LDO_ENA1_1, 1, 10000, ldo2_volt_table),
+       PM800_LDO(LDO3, LDO_ENA1_1, 2, 300000, ldo3_17_volt_table),
+       PM800_LDO(LDO4, LDO_ENA1_1, 3, 300000, ldo3_17_volt_table),
+       PM800_LDO(LDO5, LDO_ENA1_1, 4, 300000, ldo3_17_volt_table),
+       PM800_LDO(LDO6, LDO_ENA1_1, 5, 300000, ldo3_17_volt_table),
+       PM800_LDO(LDO7, LDO_ENA1_1, 6, 300000, ldo3_17_volt_table),
+       PM800_LDO(LDO8, LDO_ENA1_1, 7, 300000, ldo3_17_volt_table),
+       PM800_LDO(LDO9, LDO_ENA1_2, 0, 300000, ldo3_17_volt_table),
+       PM800_LDO(LDO10, LDO_ENA1_2, 1, 300000, ldo3_17_volt_table),
+       PM800_LDO(LDO11, LDO_ENA1_2, 2, 300000, ldo3_17_volt_table),
+       PM800_LDO(LDO12, LDO_ENA1_2, 3, 300000, ldo3_17_volt_table),
+       PM800_LDO(LDO13, LDO_ENA1_2, 4, 300000, ldo3_17_volt_table),
+       PM800_LDO(LDO14, LDO_ENA1_2, 5, 300000, ldo3_17_volt_table),
+       PM800_LDO(LDO15, LDO_ENA1_2, 6, 300000, ldo3_17_volt_table),
+       PM800_LDO(LDO16, LDO_ENA1_2, 7, 300000, ldo3_17_volt_table),
+       PM800_LDO(LDO17, LDO_ENA1_3, 0, 300000, ldo3_17_volt_table),
+       PM800_LDO(LDO18, LDO_ENA1_3, 1, 200000, ldo18_19_volt_table),
+       PM800_LDO(LDO19, LDO_ENA1_3, 2, 200000, ldo18_19_volt_table),
+};
+
+#define PM800_REGULATOR_OF_MATCH(_name, _id)                           \
+       [PM800_ID_##_id] = {                                            \
+               .name = #_name,                                         \
+               .driver_data = &pm800_regulator_info[PM800_ID_##_id],   \
+       }
+
+static struct of_regulator_match pm800_regulator_matches[] = {
+       PM800_REGULATOR_OF_MATCH(buck1, BUCK1),
+       PM800_REGULATOR_OF_MATCH(buck2, BUCK2),
+       PM800_REGULATOR_OF_MATCH(buck3, BUCK3),
+       PM800_REGULATOR_OF_MATCH(buck4, BUCK4),
+       PM800_REGULATOR_OF_MATCH(buck5, BUCK5),
+       PM800_REGULATOR_OF_MATCH(ldo1, LDO1),
+       PM800_REGULATOR_OF_MATCH(ldo2, LDO2),
+       PM800_REGULATOR_OF_MATCH(ldo3, LDO3),
+       PM800_REGULATOR_OF_MATCH(ldo4, LDO4),
+       PM800_REGULATOR_OF_MATCH(ldo5, LDO5),
+       PM800_REGULATOR_OF_MATCH(ldo6, LDO6),
+       PM800_REGULATOR_OF_MATCH(ldo7, LDO7),
+       PM800_REGULATOR_OF_MATCH(ldo8, LDO8),
+       PM800_REGULATOR_OF_MATCH(ldo9, LDO9),
+       PM800_REGULATOR_OF_MATCH(ldo10, LDO10),
+       PM800_REGULATOR_OF_MATCH(ldo11, LDO11),
+       PM800_REGULATOR_OF_MATCH(ldo12, LDO12),
+       PM800_REGULATOR_OF_MATCH(ldo13, LDO13),
+       PM800_REGULATOR_OF_MATCH(ldo14, LDO14),
+       PM800_REGULATOR_OF_MATCH(ldo15, LDO15),
+       PM800_REGULATOR_OF_MATCH(ldo16, LDO16),
+       PM800_REGULATOR_OF_MATCH(ldo17, LDO17),
+       PM800_REGULATOR_OF_MATCH(ldo18, LDO18),
+       PM800_REGULATOR_OF_MATCH(ldo19, LDO19),
+};
+
+static int pm800_regulator_dt_init(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       int ret;
+
+       ret = of_regulator_match(&pdev->dev, np,
+                                pm800_regulator_matches,
+                                ARRAY_SIZE(pm800_regulator_matches));
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int pm800_regulator_probe(struct platform_device *pdev)
+{
+       struct pm80x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+       struct pm80x_platform_data *pdata = dev_get_platdata(pdev->dev.parent);
+       struct pm800_regulators *pm800_data;
+       struct pm800_regulator_info *info;
+       struct regulator_config config = { };
+       struct regulator_init_data *init_data;
+       int i, ret;
+
+       if (!pdata || pdata->num_regulators == 0) {
+               if (IS_ENABLED(CONFIG_OF)) {
+                       ret = pm800_regulator_dt_init(pdev);
+                       if (ret)
+                               return ret;
+               } else {
+                       return -ENODEV;
+               }
+       } else if (pdata->num_regulators) {
+               /* Check whether num_regulator is valid. */
+               unsigned int count = 0;
+               for (i = 0; pdata->regulators[i]; i++)
+                       count++;
+               if (count != pdata->num_regulators)
+                       return -EINVAL;
+       } else {
+               return -EINVAL;
+       }
+
+       pm800_data = devm_kzalloc(&pdev->dev, sizeof(*pm800_data),
+                                       GFP_KERNEL);
+       if (!pm800_data) {
+               dev_err(&pdev->dev, "Failed to allocate pm800_regualtors");
+               return -ENOMEM;
+       }
+
+       pm800_data->map = chip->subchip->regmap_power;
+       pm800_data->chip = chip;
+
+       platform_set_drvdata(pdev, pm800_data);
+
+       for (i = 0; i < PM800_ID_RG_MAX; i++) {
+               if (!pdata || pdata->num_regulators == 0)
+                       init_data = pm800_regulator_matches[i].init_data;
+               else
+                       init_data = pdata->regulators[i];
+               if (!init_data)
+                       continue;
+               info = pm800_regulator_matches[i].driver_data;
+               config.dev = &pdev->dev;
+               config.init_data = init_data;
+               config.driver_data = info;
+               config.regmap = pm800_data->map;
+               config.of_node = pm800_regulator_matches[i].of_node;
+
+               pm800_data->regulators[i] =
+                               regulator_register(&info->desc, &config);
+               if (IS_ERR(pm800_data->regulators[i])) {
+                       ret = PTR_ERR(pm800_data->regulators[i]);
+                       dev_err(&pdev->dev, "Failed to register %s\n",
+                               info->desc.name);
+
+                       while (--i >= 0)
+                               regulator_unregister(pm800_data->regulators[i]);
+
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int pm800_regulator_remove(struct platform_device *pdev)
+{
+       struct pm800_regulators *pm800_data = platform_get_drvdata(pdev);
+       int i;
+
+       for (i = 0; i < PM800_ID_RG_MAX; i++)
+               regulator_unregister(pm800_data->regulators[i]);
+
+       return 0;
+}
+
+static struct platform_driver pm800_regulator_driver = {
+       .driver         = {
+               .name   = "88pm80x-regulator",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = pm800_regulator_probe,
+       .remove         = pm800_regulator_remove,
+};
+
+module_platform_driver(pm800_regulator_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Joseph(Yossi) Hanin <yhanin@marvell.com>");
+MODULE_DESCRIPTION("Regulator Driver for Marvell 88PM800 PMIC");
+MODULE_ALIAS("platform:88pm800-regulator");
index 8a7cb1f43046acf8c17572088d250c5396a9b070..70230974468cb97ae9c76fe9fdb69ebc04e13560 100644 (file)
@@ -346,7 +346,7 @@ static int pm8607_regulator_probe(struct platform_device *pdev)
 {
        struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
        struct pm8607_regulator_info *info = NULL;
-       struct regulator_init_data *pdata = pdev->dev.platform_data;
+       struct regulator_init_data *pdata = dev_get_platdata(&pdev->dev);
        struct regulator_config config = { };
        struct resource *res;
        int i;
index f1e6ad98eebaa2c784a748e700785af479b80e96..fe77cd9504d58bdb37ca279cba27cf148ba6f09a 100644 (file)
@@ -64,15 +64,21 @@ config REGULATOR_USERSPACE_CONSUMER
 
          If unsure, say no.
 
-config REGULATOR_GPIO
-       tristate "GPIO regulator support"
-       depends on GPIOLIB
+config REGULATOR_88PM800
+       tristate "Marvell 88PM800 Power regulators"
+       depends on MFD_88PM800
        help
-         This driver provides support for regulators that can be
-         controlled via gpios.
-         It is capable of supporting current and voltage regulators
-         and the platform has to provide a mapping of GPIO-states
-         to target volts/amps.
+         This driver supports Marvell 88PM800 voltage regulator chips.
+         It delivers digitally programmable output,
+         the voltage is programmed via I2C interface.
+         It's suitable to support PXA988 chips to control VCC_MAIN and
+         various voltages.
+
+config REGULATOR_88PM8607
+       bool "Marvell 88PM8607 Power regulators"
+       depends on MFD_88PM860X=y
+       help
+         This driver supports 88PM8607 voltage regulator chips.
 
 config REGULATOR_AD5398
        tristate "Analog Devices AD5398/AD5821 regulators"
@@ -81,6 +87,14 @@ config REGULATOR_AD5398
          This driver supports AD5398 and AD5821 current regulator chips.
          If building into module, its name is ad5398.ko.
 
+config REGULATOR_ANATOP
+       tristate "Freescale i.MX on-chip ANATOP LDO regulators"
+       depends on MFD_SYSCON
+       help
+         Say y here to support Freescale i.MX on-chip ANATOP LDOs
+         regulators. It is recommended that this option be
+         enabled on i.MX6 platform.
+
 config REGULATOR_AAT2870
        tristate "AnalogicTech AAT2870 Regulators"
        depends on MFD_AAT2870_CORE
@@ -88,6 +102,22 @@ config REGULATOR_AAT2870
          If you have a AnalogicTech AAT2870 say Y to enable the
          regulator driver.
 
+config REGULATOR_AB3100
+       tristate "ST-Ericsson AB3100 Regulator functions"
+       depends on AB3100_CORE
+       default y if AB3100_CORE
+       help
+        These regulators correspond to functionality in the
+        AB3100 analog baseband dealing with power regulators
+        for the system.
+
+config REGULATOR_AB8500
+       bool "ST-Ericsson AB8500 Power Regulators"
+       depends on AB8500_CORE
+       help
+         This driver supports the regulators found on the ST-Ericsson mixed
+         signal AB8500 PMIC
+
 config REGULATOR_ARIZONA
        tristate "Wolfson Arizona class devices"
        depends on MFD_ARIZONA
@@ -96,6 +126,13 @@ config REGULATOR_ARIZONA
          Support for the regulators found on Wolfson Arizona class
          devices.
 
+config REGULATOR_AS3711
+       tristate "AS3711 PMIC"
+       depends on MFD_AS3711
+       help
+         This driver provides support for the voltage regulators on the
+         AS3711 PMIC
+
 config REGULATOR_DA903X
        tristate "Dialog Semiconductor DA9030/DA9034 regulators"
        depends on PMIC_DA903X
@@ -120,6 +157,17 @@ config REGULATOR_DA9055
          This driver can also be built as a module. If so, the module
          will be called da9055-regulator.
 
+config REGULATOR_DBX500_PRCMU
+       bool
+
+config REGULATOR_DB8500_PRCMU
+       bool "ST-Ericsson DB8500 Voltage Domain Regulators"
+       depends on MFD_DB8500_PRCMU
+       select REGULATOR_DBX500_PRCMU
+       help
+         This driver supports the voltage domain regulators controlled by the
+         DB8500 PRCMU
+
 config REGULATOR_FAN53555
        tristate "Fairchild FAN53555 Regulator"
        depends on I2C
@@ -131,44 +179,57 @@ config REGULATOR_FAN53555
          input voltage supply of 2.5V to 5.5V. The output voltage is
          programmed through an I2C interface.
 
-config REGULATOR_ANATOP
-       tristate "Freescale i.MX on-chip ANATOP LDO regulators"
-       depends on MFD_SYSCON
+config REGULATOR_GPIO
+       tristate "GPIO regulator support"
+       depends on GPIOLIB
        help
-         Say y here to support Freescale i.MX on-chip ANATOP LDOs
-         regulators. It is recommended that this option be
-         enabled on i.MX6 platform.
+         This driver provides support for regulators that can be
+         controlled via gpios.
+         It is capable of supporting current and voltage regulators
+         and the platform has to provide a mapping of GPIO-states
+         to target volts/amps.
 
-config REGULATOR_MC13XXX_CORE
-       tristate
+config REGULATOR_ISL6271A
+       tristate "Intersil ISL6271A Power regulator"
+       depends on I2C
+       help
+         This driver supports ISL6271A voltage regulator chip.
 
-config REGULATOR_MC13783
-       tristate "Freescale MC13783 regulator driver"
-       depends on MFD_MC13783
-       select REGULATOR_MC13XXX_CORE
+config REGULATOR_LP3971
+       tristate "National Semiconductors LP3971 PMIC regulator driver"
+       depends on I2C
        help
-         Say y here to support the regulators found on the Freescale MC13783
-         PMIC.
+        Say Y here to support the voltage regulators and convertors
+        on National Semiconductors LP3971 PMIC
 
-config REGULATOR_MC13892
-       tristate "Freescale MC13892 regulator driver"
-       depends on MFD_MC13XXX
-       select REGULATOR_MC13XXX_CORE
+config REGULATOR_LP3972
+       tristate "National Semiconductors LP3972 PMIC regulator driver"
+       depends on I2C
        help
-         Say y here to support the regulators found on the Freescale MC13892
-         PMIC.
+        Say Y here to support the voltage regulators and convertors
+        on National Semiconductors LP3972 PMIC
 
-config REGULATOR_ISL6271A
-       tristate "Intersil ISL6271A Power regulator"
+config REGULATOR_LP872X
+       bool "TI/National Semiconductor LP8720/LP8725 voltage regulators"
+       depends on I2C=y
+       select REGMAP_I2C
+       help
+         This driver supports LP8720/LP8725 PMIC
+
+config REGULATOR_LP8755
+       tristate "TI LP8755 High Performance PMU driver"
        depends on I2C
+       select REGMAP_I2C
        help
-         This driver supports ISL6271A voltage regulator chip.
+         This driver supports LP8755 High Performance PMU driver. This
+         chip contains six step-down DC/DC converters which can support
+         9 mode multiphase configuration.
 
-config REGULATOR_88PM8607
-       bool "Marvell 88PM8607 Power regulators"
-       depends on MFD_88PM860X=y
+config REGULATOR_LP8788
+       bool "TI LP8788 Power Regulators"
+       depends on MFD_LP8788
        help
-         This driver supports 88PM8607 voltage regulator chips.
+         This driver supports LP8788 voltage regulator chip.
 
 config REGULATOR_MAX1586
        tristate "Maxim 1586/1587 voltage regulator"
@@ -259,48 +320,43 @@ config REGULATOR_MAX77693
          and one current regulator 'CHARGER'. This is suitable for
          Exynos-4x12 chips.
 
-config REGULATOR_PCAP
-       tristate "Motorola PCAP2 regulator driver"
-       depends on EZX_PCAP
-       help
-        This driver provides support for the voltage regulators of the
-        PCAP2 PMIC.
+config REGULATOR_MC13XXX_CORE
+       tristate
 
-config REGULATOR_LP3971
-       tristate "National Semiconductors LP3971 PMIC regulator driver"
-       depends on I2C
+config REGULATOR_MC13783
+       tristate "Freescale MC13783 regulator driver"
+       depends on MFD_MC13783
+       select REGULATOR_MC13XXX_CORE
        help
-        Say Y here to support the voltage regulators and convertors
-        on National Semiconductors LP3971 PMIC
+         Say y here to support the regulators found on the Freescale MC13783
+         PMIC.
 
-config REGULATOR_LP3972
-       tristate "National Semiconductors LP3972 PMIC regulator driver"
-       depends on I2C
+config REGULATOR_MC13892
+       tristate "Freescale MC13892 regulator driver"
+       depends on MFD_MC13XXX
+       select REGULATOR_MC13XXX_CORE
        help
-        Say Y here to support the voltage regulators and convertors
-        on National Semiconductors LP3972 PMIC
+         Say y here to support the regulators found on the Freescale MC13892
+         PMIC.
 
-config REGULATOR_LP872X
-       bool "TI/National Semiconductor LP8720/LP8725 voltage regulators"
-       depends on I2C=y
-       select REGMAP_I2C
+config REGULATOR_PALMAS
+       tristate "TI Palmas PMIC Regulators"
+       depends on MFD_PALMAS
        help
-         This driver supports LP8720/LP8725 PMIC
+         If you wish to control the regulators on the Palmas series of
+         chips say Y here. This will enable support for all the software
+         controllable SMPS/LDO regulators.
 
-config REGULATOR_LP8755
-       tristate "TI LP8755 High Performance PMU driver"
-       depends on I2C
-       select REGMAP_I2C
-       help
-         This driver supports LP8755 High Performance PMU driver. This
-         chip contains six step-down DC/DC converters which can support
-         9 mode multiphase configuration.
+         The regulators available on Palmas series chips vary depending
+         on the muxing. This is handled automatically in the driver by
+         reading the mux info from OTP.
 
-config REGULATOR_LP8788
-       bool "TI LP8788 Power Regulators"
-       depends on MFD_LP8788
+config REGULATOR_PCAP
+       tristate "Motorola PCAP2 regulator driver"
+       depends on EZX_PCAP
        help
-         This driver supports LP8788 voltage regulator chip.
+        This driver provides support for the voltage regulators of the
+        PCAP2 PMIC.
 
 config REGULATOR_PCF50633
        tristate "NXP PCF50633 regulator driver"
@@ -309,6 +365,14 @@ config REGULATOR_PCF50633
         Say Y here to support the voltage regulators and convertors
         on PCF50633
 
+config REGULATOR_PFUZE100
+       tristate "Support regulators on Freescale PFUZE100 PMIC"
+       depends on I2C
+       select REGMAP_I2C
+       help
+         Say y here to support the regulators found on the Freescale PFUZE100
+         PMIC.
+
 config REGULATOR_RC5T583
        tristate "RICOH RC5T583 Power regulators"
        depends on MFD_RC5T583
@@ -335,44 +399,15 @@ config REGULATOR_S5M8767
         via I2C bus. S5M8767A have 9 Bucks and 28 LDOs output and
         supports DVS mode with 8bits of output voltage control.
 
-config REGULATOR_AB3100
-       tristate "ST-Ericsson AB3100 Regulator functions"
-       depends on AB3100_CORE
-       default y if AB3100_CORE
-       help
-        These regulators correspond to functionality in the
-        AB3100 analog baseband dealing with power regulators
-        for the system.
-
-config REGULATOR_AB8500
-       bool "ST-Ericsson AB8500 Power Regulators"
-       depends on AB8500_CORE
-       help
-         This driver supports the regulators found on the ST-Ericsson mixed
-         signal AB8500 PMIC
-
-config REGULATOR_DBX500_PRCMU
-       bool
-
-config REGULATOR_DB8500_PRCMU
-       bool "ST-Ericsson DB8500 Voltage Domain Regulators"
-       depends on MFD_DB8500_PRCMU
-       select REGULATOR_DBX500_PRCMU
-       help
-         This driver supports the voltage domain regulators controlled by the
-         DB8500 PRCMU
-
-config REGULATOR_PALMAS
-       tristate "TI Palmas PMIC Regulators"
-       depends on MFD_PALMAS
+config REGULATOR_TI_ABB
+       bool "TI Adaptive Body Bias on-chip LDO"
+       depends on ARCH_OMAP
        help
-         If you wish to control the regulators on the Palmas series of
-         chips say Y here. This will enable support for all the software
-         controllable SMPS/LDO regulators.
-
-         The regulators available on Palmas series chips vary depending
-         on the muxing. This is handled automatically in the driver by
-         reading the mux info from OTP.
+         Select this option to support Texas Instruments' on-chip Adaptive Body
+         Bias (ABB) LDO regulators. It is recommended that this option be
+         enabled on required TI SoC. Certain Operating Performance Points
+         on TI SoCs may be unstable without enabling this as it provides
+         device specific optimized bias to allow/optimize functionality.
 
 config REGULATOR_TPS51632
        tristate "TI TPS51632 Power Regulator"
@@ -481,16 +516,6 @@ config REGULATOR_TWL4030
          This driver supports the voltage regulators provided by
          this family of companion chips.
 
-config REGULATOR_TI_ABB
-       bool "TI Adaptive Body Bias on-chip LDO"
-       depends on ARCH_OMAP
-       help
-         Select this option to support Texas Instruments' on-chip Adaptive Body
-         Bias (ABB) LDO regulators. It is recommended that this option be
-         enabled on required TI SoC. Certain Operating Performance Points
-         on TI SoCs may be unstable without enabling this as it provides
-         device specific optimized bias to allow/optimize functionality.
-
 config REGULATOR_VEXPRESS
        tristate "Versatile Express regulators"
        depends on VEXPRESS_CONFIG
@@ -526,12 +551,5 @@ config REGULATOR_WM8994
          This driver provides support for the voltage regulators on the
          WM8994 CODEC.
 
-config REGULATOR_AS3711
-       tristate "AS3711 PMIC"
-       depends on MFD_AS3711
-       help
-         This driver provides support for the voltage regulators on the
-         AS3711 PMIC
-
 endif
 
index ba4a3cf3afec57eef79179abf72ae1f51d5b3073..8c14d2942220f6e1aa53f6aa09ba5ecf202840ea 100644 (file)
@@ -9,6 +9,7 @@ obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o
 obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
 obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o
 
+obj-$(CONFIG_REGULATOR_88PM800) += 88pm800.o
 obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o
 obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o
 obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o
@@ -46,12 +47,14 @@ obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
 obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
 obj-$(CONFIG_REGULATOR_MC13XXX_CORE) +=  mc13xxx-regulator-core.o
 obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
+obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o
 obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-regulator.o
 obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
 obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
 obj-$(CONFIG_REGULATOR_RC5T583)  += rc5t583-regulator.o
 obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
 obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
+obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o
 obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
 obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o
 obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o
@@ -64,7 +67,6 @@ obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o
 obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o
 obj-$(CONFIG_REGULATOR_TPS80031) += tps80031-regulator.o
 obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o
-obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o
 obj-$(CONFIG_REGULATOR_VEXPRESS) += vexpress.o
 obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o
 obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o
index 8b5876356db97da46cd5ac0dd59dccb4b2521361..881159dfcb5e70fc3532d7a9ccc20cad99354459 100644 (file)
@@ -174,7 +174,7 @@ static int aat2870_regulator_probe(struct platform_device *pdev)
 
        config.dev = &pdev->dev;
        config.driver_data = ri;
-       config.init_data = pdev->dev.platform_data;
+       config.init_data = dev_get_platdata(&pdev->dev);
 
        rdev = regulator_register(&ri->desc, &config);
        if (IS_ERR(rdev)) {
index 3be9e46594a134286b59010c3fa83511fa9c510e..7d5eaa874b2da9337e387b1271bd2e38a3d25d2e 100644 (file)
@@ -660,7 +660,7 @@ ab3100_regulator_of_probe(struct platform_device *pdev, struct device_node *np)
 
 static int ab3100_regulators_probe(struct platform_device *pdev)
 {
-       struct ab3100_platform_data *plfdata = pdev->dev.platform_data;
+       struct ab3100_platform_data *plfdata = dev_get_platdata(&pdev->dev);
        struct device_node *np = pdev->dev.of_node;
        int err = 0;
        u8 data;
index 6b981b5faa7015c53f10a463d7a53097edeab075..b2b203cb6b2f9373a0d09f5773f3d912922614dd 100644 (file)
@@ -214,7 +214,7 @@ MODULE_DEVICE_TABLE(i2c, ad5398_id);
 static int ad5398_probe(struct i2c_client *client,
                                const struct i2c_device_id *id)
 {
-       struct regulator_init_data *init_data = client->dev.platform_data;
+       struct regulator_init_data *init_data = dev_get_platdata(&client->dev);
        struct regulator_config config = { };
        struct ad5398_chip_info *chip;
        const struct ad5398_current_data_format *df =
index 3da6bd6950cf9cafe43b1bd296d13f5f61c7b577..8406cd745da29e6a60a76624d1199516d7d46121 100644 (file)
@@ -30,102 +30,6 @@ struct as3711_regulator {
        struct regulator_dev *rdev;
 };
 
-static int as3711_list_voltage_sd(struct regulator_dev *rdev,
-                                 unsigned int selector)
-{
-       if (selector >= rdev->desc->n_voltages)
-               return -EINVAL;
-
-       if (!selector)
-               return 0;
-       if (selector < 0x41)
-               return 600000 + selector * 12500;
-       if (selector < 0x71)
-               return 1400000 + (selector - 0x40) * 25000;
-       return 2600000 + (selector - 0x70) * 50000;
-}
-
-static int as3711_list_voltage_aldo(struct regulator_dev *rdev,
-                                   unsigned int selector)
-{
-       if (selector >= rdev->desc->n_voltages)
-               return -EINVAL;
-
-       if (selector < 0x10)
-               return 1200000 + selector * 50000;
-       return 1800000 + (selector - 0x10) * 100000;
-}
-
-static int as3711_list_voltage_dldo(struct regulator_dev *rdev,
-                                   unsigned int selector)
-{
-       if (selector >= rdev->desc->n_voltages ||
-           (selector > 0x10 && selector < 0x20))
-               return -EINVAL;
-
-       if (selector < 0x11)
-               return 900000 + selector * 50000;
-       return 1750000 + (selector - 0x20) * 50000;
-}
-
-static int as3711_bound_check(struct regulator_dev *rdev,
-                             int *min_uV, int *max_uV)
-{
-       struct as3711_regulator *reg = rdev_get_drvdata(rdev);
-       struct as3711_regulator_info *info = reg->reg_info;
-
-       dev_dbg(&rdev->dev, "%s(), %d, %d, %d\n", __func__,
-               *min_uV, rdev->desc->min_uV, info->max_uV);
-
-       if (*max_uV < *min_uV ||
-           *min_uV > info->max_uV || rdev->desc->min_uV > *max_uV)
-               return -EINVAL;
-
-       if (rdev->desc->n_voltages == 1)
-               return 0;
-
-       if (*max_uV > info->max_uV)
-               *max_uV = info->max_uV;
-
-       if (*min_uV < rdev->desc->min_uV)
-               *min_uV = rdev->desc->min_uV;
-
-       return *min_uV;
-}
-
-static int as3711_sel_check(int min, int max, int bottom, int step)
-{
-       int sel, voltage;
-
-       /* Round up min, when dividing: keeps us within the range */
-       sel = DIV_ROUND_UP(min - bottom, step);
-       voltage = sel * step + bottom;
-       pr_debug("%s(): select %d..%d in %d+N*%d: %d\n", __func__,
-              min, max, bottom, step, sel);
-       if (voltage > max)
-               return -EINVAL;
-
-       return sel;
-}
-
-static int as3711_map_voltage_sd(struct regulator_dev *rdev,
-                                int min_uV, int max_uV)
-{
-       int ret;
-
-       ret = as3711_bound_check(rdev, &min_uV, &max_uV);
-       if (ret <= 0)
-               return ret;
-
-       if (min_uV <= 1400000)
-               return as3711_sel_check(min_uV, max_uV, 600000, 12500);
-
-       if (min_uV <= 2600000)
-               return as3711_sel_check(min_uV, max_uV, 1400000, 25000) + 0x40;
-
-       return as3711_sel_check(min_uV, max_uV, 2600000, 50000) + 0x70;
-}
-
 /*
  * The regulator API supports 4 modes of operataion: FAST, NORMAL, IDLE and
  * STANDBY. We map them in the following way to AS3711 SD1-4 DCDC modes:
@@ -180,44 +84,14 @@ static unsigned int as3711_get_mode_sd(struct regulator_dev *rdev)
        return -EINVAL;
 }
 
-static int as3711_map_voltage_aldo(struct regulator_dev *rdev,
-                                 int min_uV, int max_uV)
-{
-       int ret;
-
-       ret = as3711_bound_check(rdev, &min_uV, &max_uV);
-       if (ret <= 0)
-               return ret;
-
-       if (min_uV <= 1800000)
-               return as3711_sel_check(min_uV, max_uV, 1200000, 50000);
-
-       return as3711_sel_check(min_uV, max_uV, 1800000, 100000) + 0x10;
-}
-
-static int as3711_map_voltage_dldo(struct regulator_dev *rdev,
-                                 int min_uV, int max_uV)
-{
-       int ret;
-
-       ret = as3711_bound_check(rdev, &min_uV, &max_uV);
-       if (ret <= 0)
-               return ret;
-
-       if (min_uV <= 1700000)
-               return as3711_sel_check(min_uV, max_uV, 900000, 50000);
-
-       return as3711_sel_check(min_uV, max_uV, 1750000, 50000) + 0x20;
-}
-
 static struct regulator_ops as3711_sd_ops = {
        .is_enabled             = regulator_is_enabled_regmap,
        .enable                 = regulator_enable_regmap,
        .disable                = regulator_disable_regmap,
        .get_voltage_sel        = regulator_get_voltage_sel_regmap,
        .set_voltage_sel        = regulator_set_voltage_sel_regmap,
-       .list_voltage           = as3711_list_voltage_sd,
-       .map_voltage            = as3711_map_voltage_sd,
+       .list_voltage           = regulator_list_voltage_linear_range,
+       .map_voltage            = regulator_map_voltage_linear_range,
        .get_mode               = as3711_get_mode_sd,
        .set_mode               = as3711_set_mode_sd,
 };
@@ -228,8 +102,8 @@ static struct regulator_ops as3711_aldo_ops = {
        .disable                = regulator_disable_regmap,
        .get_voltage_sel        = regulator_get_voltage_sel_regmap,
        .set_voltage_sel        = regulator_set_voltage_sel_regmap,
-       .list_voltage           = as3711_list_voltage_aldo,
-       .map_voltage            = as3711_map_voltage_aldo,
+       .list_voltage           = regulator_list_voltage_linear_range,
+       .map_voltage            = regulator_map_voltage_linear_range,
 };
 
 static struct regulator_ops as3711_dldo_ops = {
@@ -238,8 +112,31 @@ static struct regulator_ops as3711_dldo_ops = {
        .disable                = regulator_disable_regmap,
        .get_voltage_sel        = regulator_get_voltage_sel_regmap,
        .set_voltage_sel        = regulator_set_voltage_sel_regmap,
-       .list_voltage           = as3711_list_voltage_dldo,
-       .map_voltage            = as3711_map_voltage_dldo,
+       .list_voltage           = regulator_list_voltage_linear_range,
+       .map_voltage            = regulator_map_voltage_linear_range,
+};
+
+static const struct regulator_linear_range as3711_sd_ranges[] = {
+       { .min_uV = 612500, .max_uV = 1400000,
+         .min_sel = 0x1, .max_sel = 0x40, .uV_step = 12500 },
+       { .min_uV = 1425000, .max_uV = 2600000,
+         .min_sel = 0x41, .max_sel = 0x70, .uV_step = 25000 },
+       { .min_uV = 2650000, .max_uV = 3350000,
+         .min_sel = 0x71, .max_sel = 0x7f, .uV_step = 50000 },
+};
+
+static const struct regulator_linear_range as3711_aldo_ranges[] = {
+       { .min_uV = 1200000, .max_uV = 1950000,
+         .min_sel = 0, .max_sel = 0xf, .uV_step = 50000 },
+       { .min_uV = 1800000, .max_uV = 3300000,
+         .min_sel = 0x10, .max_sel = 0x1f, .uV_step = 100000 },
+};
+
+static const struct regulator_linear_range as3711_dldo_ranges[] = {
+       { .min_uV = 900000, .max_uV = 1700000,
+         .min_sel = 0, .max_sel = 0x10, .uV_step = 50000 },
+       { .min_uV = 1750000, .max_uV = 3300000,
+         .min_sel = 0x20, .max_sel = 0x3f, .uV_step = 50000 },
 };
 
 #define AS3711_REG(_id, _en_reg, _en_bit, _vmask, _vshift, _min_uV, _max_uV, _sfx)     \
@@ -256,6 +153,8 @@ static struct regulator_ops as3711_dldo_ops = {
                .enable_reg = AS3711_ ## _en_reg,                                       \
                .enable_mask = BIT(_en_bit),                                            \
                .min_uV = _min_uV,                                                      \
+               .linear_ranges = as3711_ ## _sfx ## _ranges,                            \
+               .n_linear_ranges = ARRAY_SIZE(as3711_ ## _sfx ## _ranges),              \
        },                                                                              \
        .max_uV = _max_uV,                                                              \
 }
index 288c75abc19034c06e62772ea6b6cc62242da473..61e4060ad8e7940ede6340012d2a96fdab6925c3 100644 (file)
@@ -323,13 +323,14 @@ static ssize_t regulator_uA_show(struct device *dev,
 }
 static DEVICE_ATTR(microamps, 0444, regulator_uA_show, NULL);
 
-static ssize_t regulator_name_show(struct device *dev,
-                            struct device_attribute *attr, char *buf)
+static ssize_t name_show(struct device *dev, struct device_attribute *attr,
+                        char *buf)
 {
        struct regulator_dev *rdev = dev_get_drvdata(dev);
 
        return sprintf(buf, "%s\n", rdev_get_name(rdev));
 }
+static DEVICE_ATTR_RO(name);
 
 static ssize_t regulator_print_opmode(char *buf, int mode)
 {
@@ -489,15 +490,16 @@ static ssize_t regulator_total_uA_show(struct device *dev,
 }
 static DEVICE_ATTR(requested_microamps, 0444, regulator_total_uA_show, NULL);
 
-static ssize_t regulator_num_users_show(struct device *dev,
-                                     struct device_attribute *attr, char *buf)
+static ssize_t num_users_show(struct device *dev, struct device_attribute *attr,
+                             char *buf)
 {
        struct regulator_dev *rdev = dev_get_drvdata(dev);
        return sprintf(buf, "%d\n", rdev->use_count);
 }
+static DEVICE_ATTR_RO(num_users);
 
-static ssize_t regulator_type_show(struct device *dev,
-                                 struct device_attribute *attr, char *buf)
+static ssize_t type_show(struct device *dev, struct device_attribute *attr,
+                        char *buf)
 {
        struct regulator_dev *rdev = dev_get_drvdata(dev);
 
@@ -509,6 +511,7 @@ static ssize_t regulator_type_show(struct device *dev,
        }
        return sprintf(buf, "unknown\n");
 }
+static DEVICE_ATTR_RO(type);
 
 static ssize_t regulator_suspend_mem_uV_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
@@ -632,12 +635,13 @@ static DEVICE_ATTR(bypass, 0444,
  * These are the only attributes are present for all regulators.
  * Other attributes are a function of regulator functionality.
  */
-static struct device_attribute regulator_dev_attrs[] = {
-       __ATTR(name, 0444, regulator_name_show, NULL),
-       __ATTR(num_users, 0444, regulator_num_users_show, NULL),
-       __ATTR(type, 0444, regulator_type_show, NULL),
-       __ATTR_NULL,
+static struct attribute *regulator_dev_attrs[] = {
+       &dev_attr_name.attr,
+       &dev_attr_num_users.attr,
+       &dev_attr_type.attr,
+       NULL,
 };
+ATTRIBUTE_GROUPS(regulator_dev);
 
 static void regulator_dev_release(struct device *dev)
 {
@@ -648,7 +652,7 @@ static void regulator_dev_release(struct device *dev)
 static struct class regulator_class = {
        .name = "regulator",
        .dev_release = regulator_dev_release,
-       .dev_attrs = regulator_dev_attrs,
+       .dev_groups = regulator_dev_groups,
 };
 
 /* Calculate the new optimum regulator operating mode based on the new total
@@ -984,7 +988,8 @@ static int set_machine_constraints(struct regulator_dev *rdev,
                }
        }
 
-       if (rdev->constraints->ramp_delay && ops->set_ramp_delay) {
+       if ((rdev->constraints->ramp_delay || rdev->constraints->ramp_disable)
+               && ops->set_ramp_delay) {
                ret = ops->set_ramp_delay(rdev, rdev->constraints->ramp_delay);
                if (ret < 0) {
                        rdev_err(rdev, "failed to set ramp_delay\n");
@@ -1890,8 +1895,9 @@ int regulator_disable_deferred(struct regulator *regulator, int ms)
        rdev->deferred_disables++;
        mutex_unlock(&rdev->mutex);
 
-       ret = schedule_delayed_work(&rdev->disable_work,
-                                   msecs_to_jiffies(ms));
+       ret = queue_delayed_work(system_power_efficient_wq,
+                                &rdev->disable_work,
+                                msecs_to_jiffies(ms));
        if (ret < 0)
                return ret;
        else
@@ -2078,6 +2084,43 @@ int regulator_list_voltage_linear(struct regulator_dev *rdev,
 }
 EXPORT_SYMBOL_GPL(regulator_list_voltage_linear);
 
+/**
+ * regulator_list_voltage_linear_range - List voltages for linear ranges
+ *
+ * @rdev: Regulator device
+ * @selector: Selector to convert into a voltage
+ *
+ * Regulators with a series of simple linear mappings between voltages
+ * and selectors can set linear_ranges in the regulator descriptor and
+ * then use this function as their list_voltage() operation,
+ */
+int regulator_list_voltage_linear_range(struct regulator_dev *rdev,
+                                       unsigned int selector)
+{
+       const struct regulator_linear_range *range;
+       int i;
+
+       if (!rdev->desc->n_linear_ranges) {
+               BUG_ON(!rdev->desc->n_linear_ranges);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < rdev->desc->n_linear_ranges; i++) {
+               range = &rdev->desc->linear_ranges[i];
+
+               if (!(selector >= range->min_sel &&
+                     selector <= range->max_sel))
+                       continue;
+
+               selector -= range->min_sel;
+
+               return range->min_uV + (range->uV_step * selector);
+       }
+
+       return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(regulator_list_voltage_linear_range);
+
 /**
  * regulator_list_voltage_table - List voltages with table based mapping
  *
@@ -2368,6 +2411,64 @@ int regulator_map_voltage_linear(struct regulator_dev *rdev,
 }
 EXPORT_SYMBOL_GPL(regulator_map_voltage_linear);
 
+/**
+ * regulator_map_voltage_linear - map_voltage() for multiple linear ranges
+ *
+ * @rdev: Regulator to operate on
+ * @min_uV: Lower bound for voltage
+ * @max_uV: Upper bound for voltage
+ *
+ * Drivers providing linear_ranges in their descriptor can use this as
+ * their map_voltage() callback.
+ */
+int regulator_map_voltage_linear_range(struct regulator_dev *rdev,
+                                      int min_uV, int max_uV)
+{
+       const struct regulator_linear_range *range;
+       int ret = -EINVAL;
+       int voltage, i;
+
+       if (!rdev->desc->n_linear_ranges) {
+               BUG_ON(!rdev->desc->n_linear_ranges);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < rdev->desc->n_linear_ranges; i++) {
+               range = &rdev->desc->linear_ranges[i];
+
+               if (!(min_uV <= range->max_uV && max_uV >= range->min_uV))
+                       continue;
+
+               if (min_uV <= range->min_uV)
+                       min_uV = range->min_uV;
+
+               /* range->uV_step == 0 means fixed voltage range */
+               if (range->uV_step == 0) {
+                       ret = 0;
+               } else {
+                       ret = DIV_ROUND_UP(min_uV - range->min_uV,
+                                          range->uV_step);
+                       if (ret < 0)
+                               return ret;
+               }
+
+               ret += range->min_sel;
+
+               break;
+       }
+
+       if (i == rdev->desc->n_linear_ranges)
+               return -EINVAL;
+
+       /* Map back into a voltage to verify we're still in bounds */
+       voltage = rdev->desc->ops->list_voltage(rdev, ret);
+       if (voltage < min_uV || voltage > max_uV)
+               return -EINVAL;
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_map_voltage_linear_range);
+
 static int _regulator_do_set_voltage(struct regulator_dev *rdev,
                                     int min_uV, int max_uV)
 {
@@ -2438,8 +2539,8 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
        }
 
        /* Call set_voltage_time_sel if successfully obtained old_selector */
-       if (ret == 0 && _regulator_is_enabled(rdev) && old_selector >= 0 &&
-           old_selector != selector && rdev->desc->ops->set_voltage_time_sel) {
+       if (ret == 0 && !rdev->constraints->ramp_disable && old_selector >= 0
+               && old_selector != selector) {
 
                delay = rdev->desc->ops->set_voltage_time_sel(rdev,
                                                old_selector, selector);
@@ -3740,8 +3841,11 @@ void regulator_unregister(struct regulator_dev *rdev)
        if (rdev == NULL)
                return;
 
-       if (rdev->supply)
+       if (rdev->supply) {
+               while (rdev->use_count--)
+                       regulator_disable(rdev->supply);
                regulator_put(rdev->supply);
+       }
        mutex_lock(&regulator_list_mutex);
        debugfs_remove_recursive(rdev->debugfs);
        flush_work(&rdev->disable_work.work);
index 2afa5730f324ba1ef1bb068b5f63c79e41c11a8f..f06854cf8cf50739866386538668f4eb5acbc34a 100644 (file)
@@ -252,39 +252,12 @@ static int da9034_set_dvc_voltage_sel(struct regulator_dev *rdev,
        return ret;
 }
 
-static int da9034_map_ldo12_voltage(struct regulator_dev *rdev,
-                                   int min_uV, int max_uV)
-{
-       struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
-       int sel;
-
-       if (check_range(info, min_uV, max_uV)) {
-               pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV);
-               return -EINVAL;
-       }
-
-       sel = DIV_ROUND_UP(min_uV - info->desc.min_uV, info->desc.uV_step);
-       sel = (sel >= 20) ? sel - 12 : ((sel > 7) ? 8 : sel);
-
-       return sel;
-}
-
-static int da9034_list_ldo12_voltage(struct regulator_dev *rdev,
-                                    unsigned selector)
-{
-       struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
-       int volt;
-
-       if (selector >= 8)
-               volt = 2700000 + rdev->desc->uV_step * (selector - 8);
-       else
-               volt = rdev->desc->min_uV + rdev->desc->uV_step * selector;
-
-       if (volt > info->max_uV)
-               return -EINVAL;
-
-       return volt;
-}
+static const struct regulator_linear_range da9034_ldo12_ranges[] = {
+       { .min_uV = 1700000, .max_uV = 2050000, .min_sel =  0, .max_sel = 7,
+         .uV_step =  50000 },
+       { .min_uV = 2700000, .max_uV = 3050000, .min_sel =  8, .max_sel = 15,
+         .uV_step =  50000 },
+};
 
 static struct regulator_ops da903x_regulator_ldo_ops = {
        .set_voltage_sel = da903x_set_voltage_sel,
@@ -332,8 +305,8 @@ static struct regulator_ops da9034_regulator_dvc_ops = {
 static struct regulator_ops da9034_regulator_ldo12_ops = {
        .set_voltage_sel = da903x_set_voltage_sel,
        .get_voltage_sel = da903x_get_voltage_sel,
-       .list_voltage   = da9034_list_ldo12_voltage,
-       .map_voltage    = da9034_map_ldo12_voltage,
+       .list_voltage   = regulator_list_voltage_linear_range,
+       .map_voltage    = regulator_map_voltage_linear_range,
        .enable         = da903x_enable,
        .disable        = da903x_disable,
        .is_enabled     = da903x_is_enabled,
@@ -476,6 +449,8 @@ static int da903x_regulator_probe(struct platform_device *pdev)
        if (ri->desc.id == DA9034_ID_LDO12) {
                ri->desc.ops = &da9034_regulator_ldo12_ops;
                ri->desc.n_voltages = 16;
+               ri->desc.linear_ranges = da9034_ldo12_ranges;
+               ri->desc.n_linear_ranges = ARRAY_SIZE(da9034_ldo12_ranges);
        }
 
        if (ri->desc.id == DA9030_ID_LDO14)
@@ -485,7 +460,7 @@ static int da903x_regulator_probe(struct platform_device *pdev)
                ri->desc.ops = &da9030_regulator_ldo1_15_ops;
 
        config.dev = &pdev->dev;
-       config.init_data = pdev->dev.platform_data;
+       config.init_data = dev_get_platdata(&pdev->dev);
        config.driver_data = ri;
 
        rdev = regulator_register(&ri->desc, &config);
index 96b569abb46cfe055a50cdf35a4c362a15ba0a3a..1e4d483f616373a6fb19b339ce6325be7c8a3b33 100644 (file)
@@ -349,7 +349,7 @@ static int da9052_regulator_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        da9052 = dev_get_drvdata(pdev->dev.parent);
-       pdata = da9052->dev->platform_data;
+       pdata = dev_get_platdata(da9052->dev);
        regulator->da9052 = da9052;
 
        regulator->info = find_regulator_info(regulator->da9052->chip_id,
index 30221099d09c4d09bc3f406c94e5fa089dadc5b8..77b53e5a231cabda9eaa915efa718ad9ce5e18f5 100644 (file)
@@ -535,7 +535,7 @@ static int da9055_regulator_probe(struct platform_device *pdev)
        struct regulator_config config = { };
        struct da9055_regulator *regulator;
        struct da9055 *da9055 = dev_get_drvdata(pdev->dev.parent);
-       struct da9055_pdata *pdata = da9055->dev->platform_data;
+       struct da9055_pdata *pdata = dev_get_platdata(da9055->dev);
        int ret, irq;
 
        if (pdata == NULL || pdata->regulators[pdev->id] == NULL)
index f0e1ae52bb05dd5369769d1b8d09f9c206008495..a32b44272a05dcc114ca8b160f1bf95a42589881 100644 (file)
@@ -237,7 +237,7 @@ static int fan53555_regulator_probe(struct i2c_client *client,
        unsigned int val;
        int ret;
 
-       pdata = client->dev.platform_data;
+       pdata = dev_get_platdata(&client->dev);
        if (!pdata || !pdata->regulator) {
                dev_err(&client->dev, "Platform data not found!\n");
                return -ENODEV;
index e5c03b534faefce8d2e8f30a5ebecd48b1a995dc..7610920014d789925368fd4316d35c1104fbf9ac 100644 (file)
@@ -146,7 +146,7 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
                if (IS_ERR(config))
                        return PTR_ERR(config);
        } else {
-               config = pdev->dev.platform_data;
+               config = dev_get_platdata(&pdev->dev);
        }
 
        if (!config)
index 9d39eb4aafa3634762678dcf65d460d66b9de8a7..98a98ffa7fe07d2bcb23f2c9cad593b416aaf203 100644 (file)
@@ -219,7 +219,7 @@ static struct regulator_ops gpio_regulator_current_ops = {
 
 static int gpio_regulator_probe(struct platform_device *pdev)
 {
-       struct gpio_regulator_config *config = pdev->dev.platform_data;
+       struct gpio_regulator_config *config = dev_get_platdata(&pdev->dev);
        struct device_node *np = pdev->dev.of_node;
        struct gpio_regulator_data *drvdata;
        struct regulator_config cfg = { };
index b99c49b9aff0a0577009b57fe509f18269d0e9a4..88c1a3acf563ebad5aa6301636961eda75528365 100644 (file)
@@ -110,7 +110,7 @@ static int isl6271a_probe(struct i2c_client *i2c,
                                     const struct i2c_device_id *id)
 {
        struct regulator_config config = { };
-       struct regulator_init_data *init_data   = i2c->dev.platform_data;
+       struct regulator_init_data *init_data   = dev_get_platdata(&i2c->dev);
        struct isl_pmic *pmic;
        int err, i;
 
index 3809b43816060ca0a4e71fecc024b6c7e472b09d..5a4604ee5ea593d33fa0e3412b36ff9baf6bae40 100644 (file)
@@ -425,7 +425,7 @@ static int lp3971_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
        struct lp3971 *lp3971;
-       struct lp3971_platform_data *pdata = i2c->dev.platform_data;
+       struct lp3971_platform_data *pdata = dev_get_platdata(&i2c->dev);
        int ret;
        u16 val;
 
index 573024039ca0c5751fbd5faf31ca2553d0ee91c1..093e6f44ff8a3e0d9f17eb6cd0001c36d5911b37 100644 (file)
@@ -519,7 +519,7 @@ static int lp3972_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
        struct lp3972 *lp3972;
-       struct lp3972_platform_data *pdata = i2c->dev.platform_data;
+       struct lp3972_platform_data *pdata = dev_get_platdata(&i2c->dev);
        int ret;
        u16 val;
 
index b16336bcd4d46daa099c313fc8cb98b6488ea230..2b84b727a3c498c6e22f97fe9d297d06ee1470c8 100644 (file)
@@ -373,7 +373,7 @@ static int lp8725_buck_set_current_limit(struct regulator_dev *rdev,
                return -EINVAL;
        }
 
-       for (i = ARRAY_SIZE(lp8725_buck_uA) - 1 ; i >= 0; i--) {
+       for (i = ARRAY_SIZE(lp8725_buck_uA) - 1; i >= 0; i--) {
                if (lp8725_buck_uA[i] >= min_uA &&
                        lp8725_buck_uA[i] <= max_uA)
                        return lp872x_update_bits(lp, addr,
@@ -787,7 +787,7 @@ static int lp872x_regulator_register(struct lp872x *lp)
        struct regulator_dev *rdev;
        int i, ret;
 
-       for (i = 0 ; i < lp->num_regulators ; i++) {
+       for (i = 0; i < lp->num_regulators; i++) {
                desc = (lp->chipid == LP8720) ? &lp8720_regulator_desc[i] :
                                                &lp8725_regulator_desc[i];
 
@@ -820,7 +820,7 @@ static void lp872x_regulator_unregister(struct lp872x *lp)
        struct regulator_dev *rdev;
        int i;
 
-       for (i = 0 ; i < lp->num_regulators ; i++) {
+       for (i = 0; i < lp->num_regulators; i++) {
                rdev = *(lp->regulators + i);
                regulator_unregister(rdev);
        }
@@ -907,7 +907,8 @@ static struct lp872x_platform_data
                goto out;
 
        for (i = 0; i < num_matches; i++) {
-               pdata->regulator_data[i].id = (int)match[i].driver_data;
+               pdata->regulator_data[i].id =
+                               (enum lp872x_regulator_id)match[i].driver_data;
                pdata->regulator_data[i].init_data = match[i].init_data;
 
                /* Operation mode configuration for buck/buck1/buck2 */
@@ -961,7 +962,7 @@ static int lp872x_probe(struct i2c_client *cl, const struct i2c_device_id *id)
        }
 
        lp->dev = &cl->dev;
-       lp->pdata = cl->dev.platform_data;
+       lp->pdata = dev_get_platdata(&cl->dev);
        lp->chipid = id->driver_data;
        lp->num_regulators = num_regulators;
        i2c_set_clientdata(cl, lp);
index d9e38b4c2adcd45b39bceba1b7b7b80dff09234d..785a25e9a43744530c2608fea66b4721eb06562e 100644 (file)
@@ -228,6 +228,7 @@ err_i2c:
 }
 
 static struct regulator_ops lp8755_buck_ops = {
+       .map_voltage = regulator_map_voltage_linear,
        .list_voltage = regulator_list_voltage_linear,
        .set_voltage_sel = regulator_set_voltage_sel_regmap,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
@@ -449,7 +450,7 @@ static int lp8755_probe(struct i2c_client *client,
 {
        int ret, icnt;
        struct lp8755_chip *pchip;
-       struct lp8755_platform_data *pdata = client->dev.platform_data;
+       struct lp8755_platform_data *pdata = dev_get_platdata(&client->dev);
 
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
                dev_err(&client->dev, "i2c functionality check fail.\n");
index 54af6101581495c41c686d5c56a6630c6e5a375e..3a599ee0a456000b5058771e5a8325d76afca521 100644 (file)
@@ -163,7 +163,7 @@ static int max1586_pmic_probe(struct i2c_client *client,
                                        const struct i2c_device_id *i2c_id)
 {
        struct regulator_dev **rdev;
-       struct max1586_platform_data *pdata = client->dev.platform_data;
+       struct max1586_platform_data *pdata = dev_get_platdata(&client->dev);
        struct regulator_config config = { };
        struct max1586_data *max1586;
        int i, id, ret = -ENOMEM;
index db6c9be10f3f3470de157a0c0e0592645d5b3a83..19c6f08eafd5bddfe5a626696bafcea8bf5f36ec 100644 (file)
@@ -152,7 +152,7 @@ static struct regmap_config max8649_regmap_config = {
 static int max8649_regulator_probe(struct i2c_client *client,
                                             const struct i2c_device_id *id)
 {
-       struct max8649_platform_data *pdata = client->dev.platform_data;
+       struct max8649_platform_data *pdata = dev_get_platdata(&client->dev);
        struct max8649_regulator_info *info = NULL;
        struct regulator_config config = { };
        unsigned int val;
index d428ef9a626fefde45c5e8487f3ec3125abe05c8..bfd41084c7dfd8a96ea23e9587434cca78cb9f52 100644 (file)
@@ -309,7 +309,7 @@ static int max8660_probe(struct i2c_client *client,
                                   const struct i2c_device_id *i2c_id)
 {
        struct regulator_dev **rdev;
-       struct max8660_platform_data *pdata = client->dev.platform_data;
+       struct max8660_platform_data *pdata = dev_get_platdata(&client->dev);
        struct regulator_config config = { };
        struct max8660 *max8660;
        int boot_on, i, id, ret = -EINVAL;
index e6d54a546d36d40c68aeb0b623c8d83fee79ef0f..d80b5fa758ae5012585acb0a2e2b2947005177ce 100644 (file)
@@ -277,7 +277,7 @@ static int max8925_regulator_dt_init(struct platform_device *pdev,
 static int max8925_regulator_probe(struct platform_device *pdev)
 {
        struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
-       struct regulator_init_data *pdata = pdev->dev.platform_data;
+       struct regulator_init_data *pdata = dev_get_platdata(&pdev->dev);
        struct regulator_config config = { };
        struct max8925_regulator_info *ri;
        struct resource *res;
index 5259c2fea90a78fa85431630e14d5bb149d52a3c..788e5ae2af1b51464b16dca99c4d190a067cc67a 100644 (file)
@@ -196,7 +196,7 @@ static int max8952_pmic_probe(struct i2c_client *client,
                const struct i2c_device_id *i2c_id)
 {
        struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
-       struct max8952_platform_data *pdata = client->dev.platform_data;
+       struct max8952_platform_data *pdata = dev_get_platdata(&client->dev);
        struct regulator_config config = { };
        struct max8952_data *max8952;
 
index 0c5195a842e2ee68b5568f8e1c9cd85081a9df17..5b77ab7762e43c6915dc039e4f7a935a0a4d1adf 100644 (file)
@@ -371,7 +371,7 @@ static int max8973_probe(struct i2c_client *client,
        struct max8973_chip *max;
        int ret;
 
-       pdata = client->dev.platform_data;
+       pdata = dev_get_platdata(&client->dev);
 
        if (!pdata && !client->dev.of_node) {
                dev_err(&client->dev, "No Platform data");
index f3c8f8f9dc39d48e8b586cb808cfdc568ae67d27..7827384680d64a7f62b5e248d687953e5ca8ae7b 100644 (file)
@@ -21,6 +21,7 @@ static void of_get_regulation_constraints(struct device_node *np,
 {
        const __be32 *min_uV, *max_uV, *uV_offset;
        const __be32 *min_uA, *max_uA, *ramp_delay;
+       struct property *prop;
        struct regulation_constraints *constraints = &(*init_data)->constraints;
 
        constraints->name = of_get_property(np, "regulator-name", NULL);
@@ -64,9 +65,14 @@ static void of_get_regulation_constraints(struct device_node *np,
        if (of_property_read_bool(np, "regulator-allow-bypass"))
                constraints->valid_ops_mask |= REGULATOR_CHANGE_BYPASS;
 
-       ramp_delay = of_get_property(np, "regulator-ramp-delay", NULL);
-       if (ramp_delay)
-               constraints->ramp_delay = be32_to_cpu(*ramp_delay);
+       prop = of_find_property(np, "regulator-ramp-delay", NULL);
+       if (prop && prop->value) {
+               ramp_delay = prop->value;
+               if (*ramp_delay)
+                       constraints->ramp_delay = be32_to_cpu(*ramp_delay);
+               else
+                       constraints->ramp_disable = true;
+       }
 }
 
 /**
index d0c87856dd25fdd7eefaf14f784e6f0ad58a48f2..e8877e4e5a5aad848d3a802c06a0acdaed3993a8 100644 (file)
@@ -765,7 +765,7 @@ static void palmas_dt_to_pdata(struct device *dev,
 static int palmas_regulators_probe(struct platform_device *pdev)
 {
        struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);
-       struct palmas_pmic_platform_data *pdata = pdev->dev.platform_data;
+       struct palmas_pmic_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct device_node *node = pdev->dev.of_node;
        struct regulator_dev *rdev;
        struct regulator_config config = { };
index 1a73a297fe730533cc6be23469eee0014f6dbe80..b49eaeedea849f5c380059417050bd9d75f2901e 100644 (file)
@@ -243,7 +243,7 @@ static int pcap_regulator_probe(struct platform_device *pdev)
        struct regulator_config config = { };
 
        config.dev = &pdev->dev;
-       config.init_data = pdev->dev.platform_data;
+       config.init_data = dev_get_platdata(&pdev->dev);
        config.driver_data = pcap;
 
        rdev = regulator_register(&pcap_regulators[pdev->id], &config);
index 54df9f7cb504b7da2f4b6c6b26c8389bcdd3f117..0f3576d48abf9733cb87a27231f471ca263cade9 100644 (file)
@@ -86,7 +86,7 @@ static int pcf50633_regulator_probe(struct platform_device *pdev)
        pcf = dev_to_pcf50633(pdev->dev.parent);
 
        config.dev = &pdev->dev;
-       config.init_data = pdev->dev.platform_data;
+       config.init_data = dev_get_platdata(&pdev->dev);
        config.driver_data = pcf;
        config.regmap = pcf->regmap;
 
diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c
new file mode 100644 (file)
index 0000000..e02d9b9
--- /dev/null
@@ -0,0 +1,456 @@
+/*
+ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/pfuze100.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+
+#define PFUZE_NUMREGS          128
+#define PFUZE100_VOL_OFFSET    0
+#define PFUZE100_STANDBY_OFFSET        1
+#define PFUZE100_MODE_OFFSET   3
+#define PFUZE100_CONF_OFFSET   4
+
+#define PFUZE100_DEVICEID      0x0
+#define PFUZE100_REVID         0x3
+#define PFUZE100_FABID         0x3
+
+#define PFUZE100_SW1ABVOL      0x20
+#define PFUZE100_SW1CVOL       0x2e
+#define PFUZE100_SW2VOL                0x35
+#define PFUZE100_SW3AVOL       0x3c
+#define PFUZE100_SW3BVOL       0x43
+#define PFUZE100_SW4VOL                0x4a
+#define PFUZE100_SWBSTCON1     0x66
+#define PFUZE100_VREFDDRCON    0x6a
+#define PFUZE100_VSNVSVOL      0x6b
+#define PFUZE100_VGEN1VOL      0x6c
+#define PFUZE100_VGEN2VOL      0x6d
+#define PFUZE100_VGEN3VOL      0x6e
+#define PFUZE100_VGEN4VOL      0x6f
+#define PFUZE100_VGEN5VOL      0x70
+#define PFUZE100_VGEN6VOL      0x71
+
+struct pfuze_regulator {
+       struct regulator_desc desc;
+       unsigned char stby_reg;
+       unsigned char stby_mask;
+};
+
+struct pfuze_chip {
+       struct regmap *regmap;
+       struct device *dev;
+       struct pfuze_regulator regulator_descs[PFUZE100_MAX_REGULATOR];
+       struct regulator_dev *regulators[PFUZE100_MAX_REGULATOR];
+};
+
+static const int pfuze100_swbst[] = {
+       5000000, 5050000, 5100000, 5150000,
+};
+
+static const int pfuze100_vsnvs[] = {
+       1000000, 1100000, 1200000, 1300000, 1500000, 1800000, 3000000,
+};
+
+static const struct i2c_device_id pfuze_device_id[] = {
+       {.name = "pfuze100"},
+       {},
+};
+MODULE_DEVICE_TABLE(i2c, pfuze_device_id);
+
+static const struct of_device_id pfuze_dt_ids[] = {
+       { .compatible = "fsl,pfuze100" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, pfuze_dt_ids);
+
+static int pfuze100_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
+{
+       struct pfuze_chip *pfuze100 = rdev_get_drvdata(rdev);
+       int id = rdev->desc->id;
+       unsigned int val, ramp_bits, reg;
+       int ret;
+
+       if (id < PFUZE100_SWBST) {
+               if (id == PFUZE100_SW1AB)
+                       reg = PFUZE100_SW1ABVOL;
+               else
+                       reg = PFUZE100_SW1CVOL + (id - PFUZE100_SW1C) * 7;
+               regmap_read(pfuze100->regmap, reg, &val);
+
+               if (id <= PFUZE100_SW1C)
+                       ramp_delay = 25000 / (2 * ramp_delay);
+               else if (val & 0x40)
+                       ramp_delay = 50000 / (4 * ramp_delay);
+               else
+                       ramp_delay = 25000 / (2 * ramp_delay);
+
+               ramp_bits = (ramp_delay >> 1) - (ramp_delay >> 3);
+               ret = regmap_update_bits(pfuze100->regmap, reg + 4 , 0xc0,
+                               ramp_bits << 6);
+               if (ret < 0)
+                       dev_err(pfuze100->dev, "ramp failed, err %d\n", ret);
+       } else
+               ret = -EACCES;
+
+       return ret;
+}
+
+static struct regulator_ops pfuze100_ldo_regulator_ops = {
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .list_voltage = regulator_list_voltage_linear,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+};
+
+static struct regulator_ops pfuze100_fixed_regulator_ops = {
+       .list_voltage = regulator_list_voltage_linear,
+};
+
+static struct regulator_ops pfuze100_sw_regulator_ops = {
+       .list_voltage = regulator_list_voltage_linear,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .set_voltage_time_sel = regulator_set_voltage_time_sel,
+       .set_ramp_delay = pfuze100_set_ramp_delay,
+};
+
+static struct regulator_ops pfuze100_swb_regulator_ops = {
+       .list_voltage = regulator_list_voltage_table,
+       .map_voltage = regulator_map_voltage_ascend,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+
+};
+
+#define PFUZE100_FIXED_REG(_name, base, voltage)       \
+       [PFUZE100_ ## _name] = {        \
+               .desc = {       \
+                       .name = #_name, \
+                       .n_voltages = 1,        \
+                       .ops = &pfuze100_fixed_regulator_ops,   \
+                       .type = REGULATOR_VOLTAGE,      \
+                       .id = PFUZE100_ ## _name,       \
+                       .owner = THIS_MODULE,   \
+                       .min_uV = (voltage),    \
+                       .enable_reg = (base),   \
+                       .enable_mask = 0x10,    \
+               },      \
+       }
+
+#define PFUZE100_SW_REG(_name, base, min, max, step)   \
+       [PFUZE100_ ## _name] = {        \
+               .desc = {       \
+                       .name = #_name,\
+                       .n_voltages = ((max) - (min)) / (step) + 1,     \
+                       .ops = &pfuze100_sw_regulator_ops,      \
+                       .type = REGULATOR_VOLTAGE,      \
+                       .id = PFUZE100_ ## _name,       \
+                       .owner = THIS_MODULE,   \
+                       .min_uV = (min),        \
+                       .uV_step = (step),      \
+                       .vsel_reg = (base) + PFUZE100_VOL_OFFSET,       \
+                       .vsel_mask = 0x3f,      \
+               },      \
+               .stby_reg = (base) + PFUZE100_STANDBY_OFFSET,   \
+               .stby_mask = 0x3f,      \
+       }
+
+#define PFUZE100_SWB_REG(_name, base, mask, voltages)  \
+       [PFUZE100_ ## _name] = {        \
+               .desc = {       \
+                       .name = #_name, \
+                       .n_voltages = ARRAY_SIZE(voltages),     \
+                       .ops = &pfuze100_swb_regulator_ops,     \
+                       .type = REGULATOR_VOLTAGE,      \
+                       .id = PFUZE100_ ## _name,       \
+                       .owner = THIS_MODULE,   \
+                       .volt_table = voltages, \
+                       .vsel_reg = (base),     \
+                       .vsel_mask = (mask),    \
+               },      \
+       }
+
+#define PFUZE100_VGEN_REG(_name, base, min, max, step) \
+       [PFUZE100_ ## _name] = {        \
+               .desc = {       \
+                       .name = #_name, \
+                       .n_voltages = ((max) - (min)) / (step) + 1,     \
+                       .ops = &pfuze100_ldo_regulator_ops,     \
+                       .type = REGULATOR_VOLTAGE,      \
+                       .id = PFUZE100_ ## _name,       \
+                       .owner = THIS_MODULE,   \
+                       .min_uV = (min),        \
+                       .uV_step = (step),      \
+                       .vsel_reg = (base),     \
+                       .vsel_mask = 0xf,       \
+                       .enable_reg = (base),   \
+                       .enable_mask = 0x10,    \
+               },      \
+               .stby_reg = (base),     \
+               .stby_mask = 0x20,      \
+       }
+
+static struct pfuze_regulator pfuze100_regulators[] = {
+       PFUZE100_SW_REG(SW1AB, PFUZE100_SW1ABVOL, 300000, 1875000, 25000),
+       PFUZE100_SW_REG(SW1C, PFUZE100_SW1CVOL, 300000, 1875000, 25000),
+       PFUZE100_SW_REG(SW2, PFUZE100_SW2VOL, 400000, 1975000, 25000),
+       PFUZE100_SW_REG(SW3A, PFUZE100_SW3AVOL, 400000, 1975000, 25000),
+       PFUZE100_SW_REG(SW3B, PFUZE100_SW3BVOL, 400000, 1975000, 25000),
+       PFUZE100_SW_REG(SW4, PFUZE100_SW4VOL, 400000, 1975000, 25000),
+       PFUZE100_SWB_REG(SWBST, PFUZE100_SWBSTCON1, 0x3 , pfuze100_swbst),
+       PFUZE100_SWB_REG(VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs),
+       PFUZE100_FIXED_REG(VREFDDR, PFUZE100_VREFDDRCON, 750000),
+       PFUZE100_VGEN_REG(VGEN1, PFUZE100_VGEN1VOL, 800000, 1550000, 50000),
+       PFUZE100_VGEN_REG(VGEN2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000),
+       PFUZE100_VGEN_REG(VGEN3, PFUZE100_VGEN3VOL, 1800000, 3300000, 100000),
+       PFUZE100_VGEN_REG(VGEN4, PFUZE100_VGEN4VOL, 1800000, 3300000, 100000),
+       PFUZE100_VGEN_REG(VGEN5, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000),
+       PFUZE100_VGEN_REG(VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000),
+};
+
+#ifdef CONFIG_OF
+static struct of_regulator_match pfuze100_matches[] = {
+       { .name = "sw1ab",      },
+       { .name = "sw1c",       },
+       { .name = "sw2",        },
+       { .name = "sw3a",       },
+       { .name = "sw3b",       },
+       { .name = "sw4",        },
+       { .name = "swbst",      },
+       { .name = "vsnvs",      },
+       { .name = "vrefddr",    },
+       { .name = "vgen1",      },
+       { .name = "vgen2",      },
+       { .name = "vgen3",      },
+       { .name = "vgen4",      },
+       { .name = "vgen5",      },
+       { .name = "vgen6",      },
+};
+
+static int pfuze_parse_regulators_dt(struct pfuze_chip *chip)
+{
+       struct device *dev = chip->dev;
+       struct device_node *np, *parent;
+       int ret;
+
+       np = of_node_get(dev->parent->of_node);
+       if (!np)
+               return 0;
+
+       parent = of_find_node_by_name(np, "regulators");
+       if (!parent) {
+               dev_err(dev, "regulators node not found\n");
+               return -EINVAL;
+       }
+
+       ret = of_regulator_match(dev, parent, pfuze100_matches,
+                                ARRAY_SIZE(pfuze100_matches));
+
+       of_node_put(parent);
+       if (ret < 0) {
+               dev_err(dev, "Error parsing regulator init data: %d\n",
+                       ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static inline struct regulator_init_data *match_init_data(int index)
+{
+       return pfuze100_matches[index].init_data;
+}
+
+static inline struct device_node *match_of_node(int index)
+{
+       return pfuze100_matches[index].of_node;
+}
+#else
+static int pfuze_parse_regulators_dt(struct pfuze_chip *chip)
+{
+       return 0;
+}
+
+static inline struct regulator_init_data *match_init_data(int index)
+{
+       return NULL;
+}
+
+static inline struct device_node *match_of_node(int index)
+{
+       return NULL;
+}
+#endif
+
+static int pfuze_identify(struct pfuze_chip *pfuze_chip)
+{
+       unsigned int value;
+       int ret;
+
+       ret = regmap_read(pfuze_chip->regmap, PFUZE100_DEVICEID, &value);
+       if (ret)
+               return ret;
+
+       if (value & 0x0f) {
+               dev_warn(pfuze_chip->dev, "Illegal ID: %x\n", value);
+               return -ENODEV;
+       }
+
+       ret = regmap_read(pfuze_chip->regmap, PFUZE100_REVID, &value);
+       if (ret)
+               return ret;
+       dev_info(pfuze_chip->dev,
+                "Full lay: %x, Metal lay: %x\n",
+                (value & 0xf0) >> 4, value & 0x0f);
+
+       ret = regmap_read(pfuze_chip->regmap, PFUZE100_FABID, &value);
+       if (ret)
+               return ret;
+       dev_info(pfuze_chip->dev, "FAB: %x, FIN: %x\n",
+                (value & 0xc) >> 2, value & 0x3);
+
+       return 0;
+}
+
+static const struct regmap_config pfuze_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = PFUZE_NUMREGS,
+       .cache_type = REGCACHE_RBTREE,
+};
+
+static int pfuze100_regulator_probe(struct i2c_client *client,
+                                   const struct i2c_device_id *id)
+{
+       struct pfuze_chip *pfuze_chip;
+       struct pfuze_regulator_platform_data *pdata =
+           dev_get_platdata(&client->dev);
+       struct regulator_config config = { };
+       int i, ret;
+
+       pfuze_chip = devm_kzalloc(&client->dev, sizeof(*pfuze_chip),
+                       GFP_KERNEL);
+       if (!pfuze_chip)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, pfuze_chip);
+
+       memcpy(pfuze_chip->regulator_descs, pfuze100_regulators,
+               sizeof(pfuze_chip->regulator_descs));
+
+       pfuze_chip->dev = &client->dev;
+
+       pfuze_chip->regmap = devm_regmap_init_i2c(client, &pfuze_regmap_config);
+       if (IS_ERR(pfuze_chip->regmap)) {
+               ret = PTR_ERR(pfuze_chip->regmap);
+               dev_err(&client->dev,
+                       "regmap allocation failed with err %d\n", ret);
+               return ret;
+       }
+
+       ret = pfuze_identify(pfuze_chip);
+       if (ret) {
+               dev_err(&client->dev, "unrecognized pfuze chip ID!\n");
+               return ret;
+       }
+
+       ret = pfuze_parse_regulators_dt(pfuze_chip);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < PFUZE100_MAX_REGULATOR; i++) {
+               struct regulator_init_data *init_data;
+               struct regulator_desc *desc;
+               int val;
+
+               desc = &pfuze_chip->regulator_descs[i].desc;
+
+               if (pdata)
+                       init_data = pdata->init_data[i];
+               else
+                       init_data = match_init_data(i);
+
+               /* SW2~SW4 high bit check and modify the voltage value table */
+               if (i > PFUZE100_SW1C && i < PFUZE100_SWBST) {
+                       regmap_read(pfuze_chip->regmap, desc->vsel_reg, &val);
+                       if (val & 0x40) {
+                               desc->min_uV = 800000;
+                               desc->uV_step = 50000;
+                               desc->n_voltages = 51;
+                       }
+               }
+
+               config.dev = &client->dev;
+               config.init_data = init_data;
+               config.driver_data = pfuze_chip;
+               config.of_node = match_of_node(i);
+
+               pfuze_chip->regulators[i] = regulator_register(desc, &config);
+               if (IS_ERR(pfuze_chip->regulators[i])) {
+                       dev_err(&client->dev, "register regulator%s failed\n",
+                               pfuze100_regulators[i].desc.name);
+                       ret = PTR_ERR(pfuze_chip->regulators[i]);
+                       while (--i >= 0)
+                               regulator_unregister(pfuze_chip->regulators[i]);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int pfuze100_regulator_remove(struct i2c_client *client)
+{
+       int i;
+       struct pfuze_chip *pfuze_chip = i2c_get_clientdata(client);
+
+       for (i = 0; i < PFUZE100_MAX_REGULATOR; i++)
+               regulator_unregister(pfuze_chip->regulators[i]);
+
+       return 0;
+}
+
+static struct i2c_driver pfuze_driver = {
+       .id_table = pfuze_device_id,
+       .driver = {
+               .name = "pfuze100-regulator",
+               .owner = THIS_MODULE,
+               .of_match_table = pfuze_dt_ids,
+       },
+       .probe = pfuze100_regulator_probe,
+       .remove = pfuze100_regulator_remove,
+};
+module_i2c_driver(pfuze_driver);
+
+MODULE_AUTHOR("Robin Gong <b38343@freescale.com>");
+MODULE_DESCRIPTION("Regulator Driver for Freescale PFUZE100 PMIC");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("i2c:pfuze100-regulator");
index 2f62564ca9362e06ae8e5479864af5c48f12342e..f047d36f60272c680b0c3a12d03b27b1dd85ab78 100644 (file)
 #include <linux/gpio.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
 #include <linux/mfd/samsung/core.h>
 #include <linux/mfd/samsung/s2mps11.h>
 
+#define S2MPS11_REGULATOR_CNT ARRAY_SIZE(regulators)
+
 struct s2mps11_info {
        struct regulator_dev *rdev[S2MPS11_REGULATOR_MAX];
 
@@ -31,11 +36,6 @@ struct s2mps11_info {
        int ramp_delay16;
        int ramp_delay7810;
        int ramp_delay9;
-
-       bool buck6_ramp;
-       bool buck2_ramp;
-       bool buck3_ramp;
-       bool buck4_ramp;
 };
 
 static int get_ramp_delay(int ramp_delay)
@@ -53,6 +53,164 @@ static int get_ramp_delay(int ramp_delay)
        return cnt;
 }
 
+static int s2mps11_regulator_set_voltage_time_sel(struct regulator_dev *rdev,
+                                  unsigned int old_selector,
+                                  unsigned int new_selector)
+{
+       struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev);
+       unsigned int ramp_delay = 0;
+       int old_volt, new_volt;
+
+       switch (rdev->desc->id) {
+       case S2MPS11_BUCK2:
+               ramp_delay = s2mps11->ramp_delay2;
+               break;
+       case S2MPS11_BUCK3:
+               ramp_delay = s2mps11->ramp_delay34;
+               break;
+       case S2MPS11_BUCK4:
+               ramp_delay = s2mps11->ramp_delay34;
+               break;
+       case S2MPS11_BUCK5:
+               ramp_delay = s2mps11->ramp_delay5;
+               break;
+       case S2MPS11_BUCK6:
+       case S2MPS11_BUCK1:
+               ramp_delay = s2mps11->ramp_delay16;
+               break;
+       case S2MPS11_BUCK7:
+       case S2MPS11_BUCK8:
+       case S2MPS11_BUCK10:
+               ramp_delay = s2mps11->ramp_delay7810;
+               break;
+       case S2MPS11_BUCK9:
+               ramp_delay = s2mps11->ramp_delay9;
+       }
+
+       if (ramp_delay == 0)
+               ramp_delay = rdev->desc->ramp_delay;
+
+       old_volt = rdev->desc->min_uV + (rdev->desc->uV_step * old_selector);
+       new_volt = rdev->desc->min_uV + (rdev->desc->uV_step * new_selector);
+
+       return DIV_ROUND_UP(abs(new_volt - old_volt), ramp_delay);
+}
+
+static int s2mps11_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
+{
+       struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev);
+       unsigned int ramp_val, ramp_shift, ramp_reg = S2MPS11_REG_RAMP_BUCK;
+       unsigned int ramp_enable = 1, enable_shift = 0;
+       int ret;
+
+       switch (rdev->desc->id) {
+       case S2MPS11_BUCK1:
+               if (ramp_delay > s2mps11->ramp_delay16)
+                       s2mps11->ramp_delay16 = ramp_delay;
+               else
+                       ramp_delay = s2mps11->ramp_delay16;
+
+               ramp_shift = S2MPS11_BUCK16_RAMP_SHIFT;
+               break;
+       case S2MPS11_BUCK2:
+               enable_shift = S2MPS11_BUCK2_RAMP_EN_SHIFT;
+               if (!ramp_delay) {
+                       ramp_enable = 0;
+                       break;
+               }
+
+               s2mps11->ramp_delay2 = ramp_delay;
+               ramp_shift = S2MPS11_BUCK2_RAMP_SHIFT;
+               ramp_reg = S2MPS11_REG_RAMP;
+               break;
+       case S2MPS11_BUCK3:
+               enable_shift = S2MPS11_BUCK3_RAMP_EN_SHIFT;
+               if (!ramp_delay) {
+                       ramp_enable = 0;
+                       break;
+               }
+
+               if (ramp_delay > s2mps11->ramp_delay34)
+                       s2mps11->ramp_delay34 = ramp_delay;
+               else
+                       ramp_delay = s2mps11->ramp_delay34;
+
+               ramp_shift = S2MPS11_BUCK34_RAMP_SHIFT;
+               ramp_reg = S2MPS11_REG_RAMP;
+               break;
+       case S2MPS11_BUCK4:
+               enable_shift = S2MPS11_BUCK4_RAMP_EN_SHIFT;
+               if (!ramp_delay) {
+                       ramp_enable = 0;
+                       break;
+               }
+
+               if (ramp_delay > s2mps11->ramp_delay34)
+                       s2mps11->ramp_delay34 = ramp_delay;
+               else
+                       ramp_delay = s2mps11->ramp_delay34;
+
+               ramp_shift = S2MPS11_BUCK34_RAMP_SHIFT;
+               ramp_reg = S2MPS11_REG_RAMP;
+               break;
+       case S2MPS11_BUCK5:
+               s2mps11->ramp_delay5 = ramp_delay;
+               ramp_shift = S2MPS11_BUCK5_RAMP_SHIFT;
+               break;
+       case S2MPS11_BUCK6:
+               enable_shift = S2MPS11_BUCK6_RAMP_EN_SHIFT;
+               if (!ramp_delay) {
+                       ramp_enable = 0;
+                       break;
+               }
+
+               if (ramp_delay > s2mps11->ramp_delay16)
+                       s2mps11->ramp_delay16 = ramp_delay;
+               else
+                       ramp_delay = s2mps11->ramp_delay16;
+
+               ramp_shift = S2MPS11_BUCK16_RAMP_SHIFT;
+               break;
+       case S2MPS11_BUCK7:
+       case S2MPS11_BUCK8:
+       case S2MPS11_BUCK10:
+               if (ramp_delay > s2mps11->ramp_delay7810)
+                       s2mps11->ramp_delay7810 = ramp_delay;
+               else
+                       ramp_delay = s2mps11->ramp_delay7810;
+
+               ramp_shift = S2MPS11_BUCK7810_RAMP_SHIFT;
+               break;
+       case S2MPS11_BUCK9:
+               s2mps11->ramp_delay9 = ramp_delay;
+               ramp_shift = S2MPS11_BUCK9_RAMP_SHIFT;
+               break;
+       default:
+               return 0;
+       }
+
+       if (!ramp_enable)
+               goto ramp_disable;
+
+       if (enable_shift) {
+               ret = regmap_update_bits(rdev->regmap, S2MPS11_REG_RAMP,
+                                       1 << enable_shift, 1 << enable_shift);
+               if (ret) {
+                       dev_err(&rdev->dev, "failed to enable ramp rate\n");
+                       return ret;
+               }
+       }
+
+       ramp_val = get_ramp_delay(ramp_delay);
+
+       return regmap_update_bits(rdev->regmap, ramp_reg,
+                                 ramp_val << ramp_shift, 1 << ramp_shift);
+
+ramp_disable:
+       return regmap_update_bits(rdev->regmap, S2MPS11_REG_RAMP, 0,
+                                 1 << enable_shift);
+}
+
 static struct regulator_ops s2mps11_ldo_ops = {
        .list_voltage           = regulator_list_voltage_linear,
        .map_voltage            = regulator_map_voltage_linear,
@@ -72,7 +230,8 @@ static struct regulator_ops s2mps11_buck_ops = {
        .disable                = regulator_disable_regmap,
        .get_voltage_sel        = regulator_get_voltage_sel_regmap,
        .set_voltage_sel        = regulator_set_voltage_sel_regmap,
-       .set_voltage_time_sel   = regulator_set_voltage_time_sel,
+       .set_voltage_time_sel   = s2mps11_regulator_set_voltage_time_sel,
+       .set_ramp_delay         = s2mps11_set_ramp_delay,
 };
 
 #define regulator_desc_ldo1(num)       {               \
@@ -239,59 +398,51 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
 {
        struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
        struct sec_platform_data *pdata = dev_get_platdata(iodev->dev);
+       struct of_regulator_match rdata[S2MPS11_REGULATOR_MAX];
+       struct device_node *reg_np = NULL;
        struct regulator_config config = { };
        struct s2mps11_info *s2mps11;
        int i, ret;
-       unsigned char ramp_enable, ramp_reg = 0;
-
-       if (!pdata) {
-               dev_err(pdev->dev.parent, "Platform data not supplied\n");
-               return -ENODEV;
-       }
 
        s2mps11 = devm_kzalloc(&pdev->dev, sizeof(struct s2mps11_info),
                                GFP_KERNEL);
        if (!s2mps11)
                return -ENOMEM;
 
-       platform_set_drvdata(pdev, s2mps11);
+       if (!iodev->dev->of_node) {
+               if (pdata) {
+                       goto common_reg;
+               } else {
+                       dev_err(pdev->dev.parent,
+                               "Platform data or DT node not supplied\n");
+                       return -ENODEV;
+               }
+       }
 
-       s2mps11->ramp_delay2 = pdata->buck2_ramp_delay;
-       s2mps11->ramp_delay34 = pdata->buck34_ramp_delay;
-       s2mps11->ramp_delay5 = pdata->buck5_ramp_delay;
-       s2mps11->ramp_delay16 = pdata->buck16_ramp_delay;
-       s2mps11->ramp_delay7810 = pdata->buck7810_ramp_delay;
-       s2mps11->ramp_delay9 = pdata->buck9_ramp_delay;
-
-       s2mps11->buck6_ramp = pdata->buck6_ramp_enable;
-       s2mps11->buck2_ramp = pdata->buck2_ramp_enable;
-       s2mps11->buck3_ramp = pdata->buck3_ramp_enable;
-       s2mps11->buck4_ramp = pdata->buck4_ramp_enable;
-
-       ramp_enable = (s2mps11->buck2_ramp << 3) | (s2mps11->buck3_ramp << 2) |
-               (s2mps11->buck4_ramp << 1) | s2mps11->buck6_ramp ;
-
-       if (ramp_enable) {
-               if (s2mps11->buck2_ramp)
-                       ramp_reg |= get_ramp_delay(s2mps11->ramp_delay2) << 6;
-               if (s2mps11->buck3_ramp || s2mps11->buck4_ramp)
-                       ramp_reg |= get_ramp_delay(s2mps11->ramp_delay34) << 4;
-               sec_reg_write(iodev, S2MPS11_REG_RAMP, ramp_reg | ramp_enable);
+       for (i = 0; i < S2MPS11_REGULATOR_CNT; i++)
+               rdata[i].name = regulators[i].name;
+
+       reg_np = of_find_node_by_name(iodev->dev->of_node, "regulators");
+       if (!reg_np) {
+               dev_err(&pdev->dev, "could not find regulators sub-node\n");
+               return -EINVAL;
        }
 
-       ramp_reg &= 0x00;
-       ramp_reg |= get_ramp_delay(s2mps11->ramp_delay5) << 6;
-       ramp_reg |= get_ramp_delay(s2mps11->ramp_delay16) << 4;
-       ramp_reg |= get_ramp_delay(s2mps11->ramp_delay7810) << 2;
-       ramp_reg |= get_ramp_delay(s2mps11->ramp_delay9);
-       sec_reg_write(iodev, S2MPS11_REG_RAMP_BUCK, ramp_reg);
+       of_regulator_match(&pdev->dev, reg_np, rdata, S2MPS11_REGULATOR_MAX);
 
-       for (i = 0; i < S2MPS11_REGULATOR_MAX; i++) {
+common_reg:
+       platform_set_drvdata(pdev, s2mps11);
 
-               config.dev = &pdev->dev;
-               config.regmap = iodev->regmap;
-               config.init_data = pdata->regulators[i].initdata;
-               config.driver_data = s2mps11;
+       config.dev = &pdev->dev;
+       config.regmap = iodev->regmap;
+       config.driver_data = s2mps11;
+       for (i = 0; i < S2MPS11_REGULATOR_MAX; i++) {
+               if (!reg_np) {
+                       config.init_data = pdata->regulators[i].initdata;
+               } else {
+                       config.init_data = rdata[i].init_data;
+                       config.of_node = rdata[i].of_node;
+               }
 
                s2mps11->rdev[i] = regulator_register(&regulators[i], &config);
                if (IS_ERR(s2mps11->rdev[i])) {
index 6e67be75ea1b5fc63095980fd24d68591d7b5389..9392a7ca3d2dc6df9152cb1aeb13c776b856e253 100644 (file)
@@ -275,7 +275,7 @@ static int tps51632_probe(struct i2c_client *client,
                }
        }
 
-       pdata = client->dev.platform_data;
+       pdata = dev_get_platdata(&client->dev);
        if (!pdata && client->dev.of_node)
                pdata = of_get_tps51632_platform_data(&client->dev);
        if (!pdata) {
index a490d5b749b2c75efffe33c4249fdf06a83c4e33..0b7ebb1ebf859bb5d409c19114b4a89f40a094b1 100644 (file)
@@ -350,7 +350,7 @@ static int tps62360_probe(struct i2c_client *client,
        int i;
        int chip_id;
 
-       pdata = client->dev.platform_data;
+       pdata = dev_get_platdata(&client->dev);
 
        if (client->dev.of_node) {
                const struct of_device_id *match;
index 9d053e23e9ebd188778d4960409ee3c1baffa540..a15263d4bdff8a2fbd433c1315291def0bf66917 100644 (file)
@@ -218,7 +218,7 @@ static int tps_65023_probe(struct i2c_client *client,
         * init_data points to array of regulator_init structures
         * coming from the board-evm file.
         */
-       init_data = client->dev.platform_data;
+       init_data = dev_get_platdata(&client->dev);
        if (!init_data)
                return -EIO;
 
index 1094393155ed17927e3cafd9170cdaf1fb0bb602..62e8d28beabd7cc8ad51b2935e29b7d348e17438 100644 (file)
@@ -601,7 +601,7 @@ static int pmic_probe(struct spi_device *spi)
        struct regulator_config config = { };
        int ret = 0, i;
 
-       init_data = dev->platform_data;
+       init_data = dev_get_platdata(dev);
        if (!init_data) {
                dev_err(dev, "could not find regulator platform data\n");
                return -EINVAL;
index 17e994e47dc139c3117a8affe76eef64b5e092e1..281e52ac64ba0e3caf66c0322bd23ac91455a8a4 100644 (file)
@@ -118,6 +118,15 @@ struct tps65912_reg {
        int eco_reg;
 };
 
+static const struct regulator_linear_range tps65912_ldo_ranges[] = {
+       { .min_uV = 800000, .max_uV = 1600000, .min_sel =  0, .max_sel = 32,
+         .uV_step = 25000 },
+       { .min_uV = 1650000, .max_uV = 3000000, .min_sel = 33, .max_sel = 60,
+         .uV_step = 50000 },
+       { .min_uV = 3100000, .max_uV = 3300000, .min_sel = 61, .max_sel = 63,
+         .uV_step = 100000 },
+};
+
 static int tps65912_get_range(struct tps65912_reg *pmic, int id)
 {
        struct tps65912 *mfd = pmic->mfd;
@@ -184,20 +193,6 @@ static unsigned long tps65912_vsel_to_uv_range3(u8 vsel)
        return uv;
 }
 
-static unsigned long tps65912_vsel_to_uv_ldo(u8 vsel)
-{
-       unsigned long uv = 0;
-
-       if (vsel <= 32)
-               uv = ((vsel * 25000) + 800000);
-       else if (vsel > 32 && vsel <= 60)
-               uv = (((vsel - 32) * 50000) + 1600000);
-       else if (vsel > 60)
-               uv = (((vsel - 60) * 100000) + 3000000);
-
-       return uv;
-}
-
 static int tps65912_get_ctrl_register(int id)
 {
        if (id >= TPS65912_REG_DCDC1 && id <= TPS65912_REG_LDO4)
@@ -376,9 +371,6 @@ static int tps65912_list_voltage(struct regulator_dev *dev, unsigned selector)
        struct tps65912_reg *pmic = rdev_get_drvdata(dev);
        int range, voltage = 0, id = rdev_get_id(dev);
 
-       if (id >= TPS65912_REG_LDO1 && id <= TPS65912_REG_LDO10)
-               return tps65912_vsel_to_uv_ldo(selector);
-
        if (id > TPS65912_REG_DCDC4)
                return -EINVAL;
 
@@ -456,7 +448,8 @@ static struct regulator_ops tps65912_ops_ldo = {
        .disable = tps65912_reg_disable,
        .get_voltage_sel = tps65912_get_voltage_sel,
        .set_voltage_sel = tps65912_set_voltage_sel,
-       .list_voltage = tps65912_list_voltage,
+       .list_voltage = regulator_list_voltage_linear_range,
+       .map_voltage = regulator_map_voltage_linear_range,
 };
 
 static int tps65912_probe(struct platform_device *pdev)
@@ -495,8 +488,14 @@ static int tps65912_probe(struct platform_device *pdev)
                pmic->desc[i].name = info->name;
                pmic->desc[i].id = i;
                pmic->desc[i].n_voltages = 64;
-               pmic->desc[i].ops = (i > TPS65912_REG_DCDC4 ?
-                       &tps65912_ops_ldo : &tps65912_ops_dcdc);
+               if (i > TPS65912_REG_DCDC4) {
+                       pmic->desc[i].ops = &tps65912_ops_ldo;
+                       pmic->desc[i].linear_ranges = tps65912_ldo_ranges;
+                       pmic->desc[i].n_linear_ranges =
+                                       ARRAY_SIZE(tps65912_ldo_ranges);
+               } else {
+                       pmic->desc[i].ops = &tps65912_ops_dcdc;
+               }
                pmic->desc[i].type = REGULATOR_VOLTAGE;
                pmic->desc[i].owner = THIS_MODULE;
                range = tps65912_get_range(pmic, i);
index 93bc4f456da4c2d3d5566427851f5eceaa0082e1..78aae4cbb00424864fbad430fc55379a060065c5 100644 (file)
@@ -1108,7 +1108,7 @@ static int twlreg_probe(struct platform_device *pdev)
                drvdata = NULL;
        } else {
                id = pdev->id;
-               initdata = pdev->dev.platform_data;
+               initdata = dev_get_platdata(&pdev->dev);
                for (i = 0, template = NULL; i < ARRAY_SIZE(twl_of_match); i++) {
                        template = twl_of_match[i].data;
                        if (template && template->desc.id == id)
index a7c8deb5f28fc02f93955f1c2b8f1ddcf2354f9a..765acc11c9c83c151a60f005c770d4639352701c 100644 (file)
@@ -111,7 +111,7 @@ static int regulator_userspace_consumer_probe(struct platform_device *pdev)
        struct userspace_consumer_data *drvdata;
        int ret;
 
-       pdata = pdev->dev.platform_data;
+       pdata = dev_get_platdata(&pdev->dev);
        if (!pdata)
                return -EINVAL;
 
index a9d4284ea007cc83658db17724e976d34dc9aafb..f53e78b9a84eadf1c9b2cded2c1ac00f7b7f055c 100644 (file)
@@ -287,7 +287,7 @@ static const struct attribute_group regulator_virtual_attr_group = {
 
 static int regulator_virtual_probe(struct platform_device *pdev)
 {
-       char *reg_id = pdev->dev.platform_data;
+       char *reg_id = dev_get_platdata(&pdev->dev);
        struct virtual_consumer_data *drvdata;
        int ret;
 
index 46938cf162ad7821403dc97b70b2db3298c86e85..11861cb861df04394ff1de205eb7896c9ab98f89 100644 (file)
@@ -451,7 +451,7 @@ static void wm831x_buckv_dvs_init(struct wm831x_dcdc *dcdc,
 static int wm831x_buckv_probe(struct platform_device *pdev)
 {
        struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
-       struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+       struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
        struct regulator_config config = { };
        int id;
        struct wm831x_dcdc *dcdc;
@@ -624,7 +624,7 @@ static struct regulator_ops wm831x_buckp_ops = {
 static int wm831x_buckp_probe(struct platform_device *pdev)
 {
        struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
-       struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+       struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
        struct regulator_config config = { };
        int id;
        struct wm831x_dcdc *dcdc;
@@ -770,7 +770,7 @@ static struct regulator_ops wm831x_boostp_ops = {
 static int wm831x_boostp_probe(struct platform_device *pdev)
 {
        struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
-       struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+       struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
        struct regulator_config config = { };
        int id = pdev->id % ARRAY_SIZE(pdata->dcdc);
        struct wm831x_dcdc *dcdc;
@@ -880,7 +880,7 @@ static struct regulator_ops wm831x_epe_ops = {
 static int wm831x_epe_probe(struct platform_device *pdev)
 {
        struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
-       struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+       struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
        struct regulator_config config = { };
        int id = pdev->id % ARRAY_SIZE(pdata->epe);
        struct wm831x_dcdc *dcdc;
index 16ebdf94d0a044b6db0111c4d4f9a5c2f8feb5fe..4eb373de1facc63a4041ebc2c2804de358363287 100644 (file)
@@ -151,7 +151,7 @@ static irqreturn_t wm831x_isink_irq(int irq, void *data)
 static int wm831x_isink_probe(struct platform_device *pdev)
 {
        struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
-       struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+       struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
        struct wm831x_isink *isink;
        int id = pdev->id % ARRAY_SIZE(pdata->isink);
        struct regulator_config config = { };
index 9ff883f80878447dc2902de4cae7de8e206b47fd..1432b26ef2e97b0830a2ecf973789ee20b7991cc 100644 (file)
@@ -62,41 +62,12 @@ static irqreturn_t wm831x_ldo_uv_irq(int irq, void *data)
  * General purpose LDOs
  */
 
-#define WM831X_GP_LDO_SELECTOR_LOW 0xe
-#define WM831X_GP_LDO_MAX_SELECTOR 0x1f
-
-static int wm831x_gp_ldo_list_voltage(struct regulator_dev *rdev,
-                                     unsigned int selector)
-{
-       /* 0.9-1.6V in 50mV steps */
-       if (selector <= WM831X_GP_LDO_SELECTOR_LOW)
-               return 900000 + (selector * 50000);
-       /* 1.7-3.3V in 100mV steps */
-       if (selector <= WM831X_GP_LDO_MAX_SELECTOR)
-               return 1600000 + ((selector - WM831X_GP_LDO_SELECTOR_LOW)
-                                 * 100000);
-       return -EINVAL;
-}
-
-static int wm831x_gp_ldo_map_voltage(struct regulator_dev *rdev,
-                                    int min_uV, int max_uV)
-{
-       int volt, vsel;
-
-       if (min_uV < 900000)
-               vsel = 0;
-       else if (min_uV < 1700000)
-               vsel = ((min_uV - 900000) / 50000);
-       else
-               vsel = ((min_uV - 1700000) / 100000)
-                       + WM831X_GP_LDO_SELECTOR_LOW + 1;
-
-       volt = wm831x_gp_ldo_list_voltage(rdev, vsel);
-       if (volt < min_uV || volt > max_uV)
-               return -EINVAL;
-
-       return vsel;
-}
+static const struct regulator_linear_range wm831x_gp_ldo_ranges[] = {
+       { .min_uV =  900000, .max_uV = 1650000, .min_sel =  0, .max_sel = 14,
+         .uV_step =  50000 },
+       { .min_uV = 1700000, .max_uV = 3300000, .min_sel = 15, .max_sel = 31,
+         .uV_step = 100000 },
+};
 
 static int wm831x_gp_ldo_set_suspend_voltage(struct regulator_dev *rdev,
                                             int uV)
@@ -105,7 +76,7 @@ static int wm831x_gp_ldo_set_suspend_voltage(struct regulator_dev *rdev,
        struct wm831x *wm831x = ldo->wm831x;
        int sel, reg = ldo->base + WM831X_LDO_SLEEP_CONTROL;
 
-       sel = wm831x_gp_ldo_map_voltage(rdev, uV, uV);
+       sel = regulator_map_voltage_linear_range(rdev, uV, uV);
        if (sel < 0)
                return sel;
 
@@ -230,8 +201,8 @@ static unsigned int wm831x_gp_ldo_get_optimum_mode(struct regulator_dev *rdev,
 
 
 static struct regulator_ops wm831x_gp_ldo_ops = {
-       .list_voltage = wm831x_gp_ldo_list_voltage,
-       .map_voltage = wm831x_gp_ldo_map_voltage,
+       .list_voltage = regulator_list_voltage_linear_range,
+       .map_voltage = regulator_map_voltage_linear_range,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
        .set_voltage_sel = regulator_set_voltage_sel_regmap,
        .set_suspend_voltage = wm831x_gp_ldo_set_suspend_voltage,
@@ -250,7 +221,7 @@ static struct regulator_ops wm831x_gp_ldo_ops = {
 static int wm831x_gp_ldo_probe(struct platform_device *pdev)
 {
        struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
-       struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+       struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
        struct regulator_config config = { };
        int id;
        struct wm831x_ldo *ldo;
@@ -290,7 +261,7 @@ static int wm831x_gp_ldo_probe(struct platform_device *pdev)
 
        ldo->desc.id = id;
        ldo->desc.type = REGULATOR_VOLTAGE;
-       ldo->desc.n_voltages = WM831X_GP_LDO_MAX_SELECTOR + 1;
+       ldo->desc.n_voltages = 32;
        ldo->desc.ops = &wm831x_gp_ldo_ops;
        ldo->desc.owner = THIS_MODULE;
        ldo->desc.vsel_reg = ldo->base + WM831X_LDO_ON_CONTROL;
@@ -299,6 +270,8 @@ static int wm831x_gp_ldo_probe(struct platform_device *pdev)
        ldo->desc.enable_mask = 1 << id;
        ldo->desc.bypass_reg = ldo->base;
        ldo->desc.bypass_mask = WM831X_LDO1_SWI;
+       ldo->desc.linear_ranges = wm831x_gp_ldo_ranges;
+       ldo->desc.n_linear_ranges = ARRAY_SIZE(wm831x_gp_ldo_ranges);
 
        config.dev = pdev->dev.parent;
        if (pdata)
@@ -358,43 +331,12 @@ static struct platform_driver wm831x_gp_ldo_driver = {
  * Analogue LDOs
  */
 
-
-#define WM831X_ALDO_SELECTOR_LOW 0xc
-#define WM831X_ALDO_MAX_SELECTOR 0x1f
-
-static int wm831x_aldo_list_voltage(struct regulator_dev *rdev,
-                                     unsigned int selector)
-{
-       /* 1-1.6V in 50mV steps */
-       if (selector <= WM831X_ALDO_SELECTOR_LOW)
-               return 1000000 + (selector * 50000);
-       /* 1.7-3.5V in 100mV steps */
-       if (selector <= WM831X_ALDO_MAX_SELECTOR)
-               return 1600000 + ((selector - WM831X_ALDO_SELECTOR_LOW)
-                                 * 100000);
-       return -EINVAL;
-}
-
-static int wm831x_aldo_map_voltage(struct regulator_dev *rdev,
-                                  int min_uV, int max_uV)
-{
-       int volt, vsel;
-
-       if (min_uV < 1000000)
-               vsel = 0;
-       else if (min_uV < 1700000)
-               vsel = ((min_uV - 1000000) / 50000);
-       else
-               vsel = ((min_uV - 1700000) / 100000)
-                       + WM831X_ALDO_SELECTOR_LOW + 1;
-
-       volt = wm831x_aldo_list_voltage(rdev, vsel);
-       if (volt < min_uV || volt > max_uV)
-               return -EINVAL;
-
-       return vsel;
-
-}
+static const struct regulator_linear_range wm831x_aldo_ranges[] = {
+       { .min_uV = 1000000, .max_uV = 1650000, .min_sel =  0, .max_sel = 12,
+         .uV_step =  50000 },
+       { .min_uV = 1700000, .max_uV = 3500000, .min_sel = 13, .max_sel = 31,
+         .uV_step = 100000 },
+};
 
 static int wm831x_aldo_set_suspend_voltage(struct regulator_dev *rdev,
                                             int uV)
@@ -403,7 +345,7 @@ static int wm831x_aldo_set_suspend_voltage(struct regulator_dev *rdev,
        struct wm831x *wm831x = ldo->wm831x;
        int sel, reg = ldo->base + WM831X_LDO_SLEEP_CONTROL;
 
-       sel = wm831x_aldo_map_voltage(rdev, uV, uV);
+       sel = regulator_map_voltage_linear_range(rdev, uV, uV);
        if (sel < 0)
                return sel;
 
@@ -486,8 +428,8 @@ static int wm831x_aldo_get_status(struct regulator_dev *rdev)
 }
 
 static struct regulator_ops wm831x_aldo_ops = {
-       .list_voltage = wm831x_aldo_list_voltage,
-       .map_voltage = wm831x_aldo_map_voltage,
+       .list_voltage = regulator_list_voltage_linear_range,
+       .map_voltage = regulator_map_voltage_linear_range,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
        .set_voltage_sel = regulator_set_voltage_sel_regmap,
        .set_suspend_voltage = wm831x_aldo_set_suspend_voltage,
@@ -505,7 +447,7 @@ static struct regulator_ops wm831x_aldo_ops = {
 static int wm831x_aldo_probe(struct platform_device *pdev)
 {
        struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
-       struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+       struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
        struct regulator_config config = { };
        int id;
        struct wm831x_ldo *ldo;
@@ -545,7 +487,9 @@ static int wm831x_aldo_probe(struct platform_device *pdev)
 
        ldo->desc.id = id;
        ldo->desc.type = REGULATOR_VOLTAGE;
-       ldo->desc.n_voltages = WM831X_ALDO_MAX_SELECTOR + 1;
+       ldo->desc.n_voltages = 32;
+       ldo->desc.linear_ranges = wm831x_aldo_ranges;
+       ldo->desc.n_linear_ranges = ARRAY_SIZE(wm831x_aldo_ranges);
        ldo->desc.ops = &wm831x_aldo_ops;
        ldo->desc.owner = THIS_MODULE;
        ldo->desc.vsel_reg = ldo->base + WM831X_LDO_ON_CONTROL;
@@ -661,7 +605,7 @@ static struct regulator_ops wm831x_alive_ldo_ops = {
 static int wm831x_alive_ldo_probe(struct platform_device *pdev)
 {
        struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
-       struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+       struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
        struct regulator_config config = { };
        int id;
        struct wm831x_ldo *ldo;
index 7f0fa22ef2aab4e85e71693358737ee099b537e2..835b5f0f344ed2537115b1ed486d14860f88434e 100644 (file)
@@ -542,41 +542,12 @@ static int wm8350_dcdc_set_suspend_mode(struct regulator_dev *rdev,
        return 0;
 }
 
-static int wm8350_ldo_list_voltage(struct regulator_dev *rdev,
-                                   unsigned selector)
-{
-       if (selector > WM8350_LDO1_VSEL_MASK)
-               return -EINVAL;
-
-       if (selector < 16)
-               return (selector * 50000) + 900000;
-       else
-               return ((selector - 16) * 100000) + 1800000;
-}
-
-static int wm8350_ldo_map_voltage(struct regulator_dev *rdev, int min_uV,
-                                 int max_uV)
-{
-       int volt, sel;
-       int min_mV = min_uV / 1000;
-       int max_mV = max_uV / 1000;
-
-       if (min_mV < 900 || min_mV > 3300)
-               return -EINVAL;
-       if (max_mV < 900 || max_mV > 3300)
-               return -EINVAL;
-
-       if (min_mV < 1800) /* step size is 50mV < 1800mV */
-               sel = DIV_ROUND_UP(min_uV - 900, 50);
-       else /* step size is 100mV > 1800mV */
-               sel = DIV_ROUND_UP(min_uV - 1800, 100) + 16;
-
-       volt = wm8350_ldo_list_voltage(rdev, sel);
-       if (volt < min_uV || volt > max_uV)
-               return -EINVAL;
-
-       return sel;
-}
+static const struct regulator_linear_range wm8350_ldo_ranges[] = {
+       { .min_uV =  900000, .max_uV = 1750000, .min_sel =  0, .max_sel = 15,
+         .uV_step =  50000 },
+       { .min_uV = 1800000, .max_uV = 3300000, .min_sel = 16, .max_sel = 31,
+         .uV_step = 100000 },
+};
 
 static int wm8350_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV)
 {
@@ -603,7 +574,7 @@ static int wm8350_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV)
                return -EINVAL;
        }
 
-       sel = wm8350_ldo_map_voltage(rdev, uV, uV);
+       sel = regulator_map_voltage_linear_range(rdev, uV, uV);
        if (sel < 0)
                return -EINVAL;
 
@@ -998,10 +969,10 @@ static struct regulator_ops wm8350_dcdc2_5_ops = {
 };
 
 static struct regulator_ops wm8350_ldo_ops = {
-       .map_voltage = wm8350_ldo_map_voltage,
+       .map_voltage = regulator_map_voltage_linear_range,
        .set_voltage_sel = regulator_set_voltage_sel_regmap,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
-       .list_voltage = wm8350_ldo_list_voltage,
+       .list_voltage = regulator_list_voltage_linear_range,
        .enable = regulator_enable_regmap,
        .disable = regulator_disable_regmap,
        .is_enabled = regulator_is_enabled_regmap,
@@ -1108,6 +1079,8 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
                .irq = WM8350_IRQ_UV_LDO1,
                .type = REGULATOR_VOLTAGE,
                .n_voltages = WM8350_LDO1_VSEL_MASK + 1,
+               .linear_ranges = wm8350_ldo_ranges,
+               .n_linear_ranges = ARRAY_SIZE(wm8350_ldo_ranges),
                .vsel_reg = WM8350_LDO1_CONTROL,
                .vsel_mask = WM8350_LDO1_VSEL_MASK,
                .enable_reg = WM8350_DCDC_LDO_REQUESTED,
@@ -1121,6 +1094,8 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
                .irq = WM8350_IRQ_UV_LDO2,
                .type = REGULATOR_VOLTAGE,
                .n_voltages = WM8350_LDO2_VSEL_MASK + 1,
+               .linear_ranges = wm8350_ldo_ranges,
+               .n_linear_ranges = ARRAY_SIZE(wm8350_ldo_ranges),
                .vsel_reg = WM8350_LDO2_CONTROL,
                .vsel_mask = WM8350_LDO2_VSEL_MASK,
                .enable_reg = WM8350_DCDC_LDO_REQUESTED,
@@ -1134,6 +1109,8 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
                .irq = WM8350_IRQ_UV_LDO3,
                .type = REGULATOR_VOLTAGE,
                .n_voltages = WM8350_LDO3_VSEL_MASK + 1,
+               .linear_ranges = wm8350_ldo_ranges,
+               .n_linear_ranges = ARRAY_SIZE(wm8350_ldo_ranges),
                .vsel_reg = WM8350_LDO3_CONTROL,
                .vsel_mask = WM8350_LDO3_VSEL_MASK,
                .enable_reg = WM8350_DCDC_LDO_REQUESTED,
@@ -1147,6 +1124,8 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
                .irq = WM8350_IRQ_UV_LDO4,
                .type = REGULATOR_VOLTAGE,
                .n_voltages = WM8350_LDO4_VSEL_MASK + 1,
+               .linear_ranges = wm8350_ldo_ranges,
+               .n_linear_ranges = ARRAY_SIZE(wm8350_ldo_ranges),
                .vsel_reg = WM8350_LDO4_CONTROL,
                .vsel_mask = WM8350_LDO4_VSEL_MASK,
                .enable_reg = WM8350_DCDC_LDO_REQUESTED,
@@ -1222,7 +1201,7 @@ static int wm8350_regulator_probe(struct platform_device *pdev)
        }
 
        config.dev = &pdev->dev;
-       config.init_data = pdev->dev.platform_data;
+       config.init_data = dev_get_platdata(&pdev->dev);
        config.driver_data = dev_get_drvdata(&pdev->dev);
        config.regmap = wm8350->regmap;
 
index a09f03ee550621503dfbf95d457cc83de1a1cbbd..58f51bec13f25d2f47a488ca53fc1099bb683762 100644 (file)
 #include <linux/regulator/driver.h>
 #include <linux/mfd/wm8400-private.h>
 
-static int wm8400_ldo_list_voltage(struct regulator_dev *dev,
-                                  unsigned selector)
-{
-       if (selector > WM8400_LDO1_VSEL_MASK)
-               return -EINVAL;
-
-       if (selector < 15)
-               return 900000 + (selector * 50000);
-       else
-               return 1700000 + ((selector - 15) * 100000);
-}
-
-static int wm8400_ldo_map_voltage(struct regulator_dev *dev,
-                                 int min_uV, int max_uV)
-{
-       u16 val;
-       int volt;
-
-       if (min_uV < 900000 || min_uV > 3300000)
-               return -EINVAL;
-
-       if (min_uV < 1700000) /* Steps of 50mV from 900mV;  */
-               val = DIV_ROUND_UP(min_uV - 900000, 50000);
-       else /* Steps of 100mV from 1700mV */
-               val = DIV_ROUND_UP(min_uV - 1700000, 100000) + 15;
-
-       volt = wm8400_ldo_list_voltage(dev, val);
-       if (volt < min_uV || volt > max_uV)
-               return -EINVAL;
-
-       return val;
-}
+static const struct regulator_linear_range wm8400_ldo_ranges[] = {
+       { .min_uV =  900000, .max_uV = 1600000, .min_sel = 0, .max_sel = 14,
+         .uV_step =  50000 },
+       { .min_uV = 1700000, .max_uV = 3300000, .min_sel = 15, .max_sel = 31,
+         .uV_step = 100000 },
+};
 
 static struct regulator_ops wm8400_ldo_ops = {
        .is_enabled = regulator_is_enabled_regmap,
        .enable = regulator_enable_regmap,
        .disable = regulator_disable_regmap,
-       .list_voltage = wm8400_ldo_list_voltage,
+       .list_voltage = regulator_list_voltage_linear_range,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
        .set_voltage_sel = regulator_set_voltage_sel_regmap,
-       .map_voltage = wm8400_ldo_map_voltage,
+       .map_voltage = regulator_map_voltage_linear_range,
 };
 
 static unsigned int wm8400_dcdc_get_mode(struct regulator_dev *dev)
@@ -155,6 +129,8 @@ static struct regulator_desc regulators[] = {
                .enable_reg = WM8400_LDO1_CONTROL,
                .enable_mask = WM8400_LDO1_ENA,
                .n_voltages = WM8400_LDO1_VSEL_MASK + 1,
+               .linear_ranges = wm8400_ldo_ranges,
+               .n_linear_ranges = ARRAY_SIZE(wm8400_ldo_ranges),
                .vsel_reg = WM8400_LDO1_CONTROL,
                .vsel_mask = WM8400_LDO1_VSEL_MASK,
                .type = REGULATOR_VOLTAGE,
@@ -167,6 +143,8 @@ static struct regulator_desc regulators[] = {
                .enable_reg = WM8400_LDO2_CONTROL,
                .enable_mask = WM8400_LDO2_ENA,
                .n_voltages = WM8400_LDO2_VSEL_MASK + 1,
+               .linear_ranges = wm8400_ldo_ranges,
+               .n_linear_ranges = ARRAY_SIZE(wm8400_ldo_ranges),
                .type = REGULATOR_VOLTAGE,
                .vsel_reg = WM8400_LDO2_CONTROL,
                .vsel_mask = WM8400_LDO2_VSEL_MASK,
@@ -179,6 +157,8 @@ static struct regulator_desc regulators[] = {
                .enable_reg = WM8400_LDO3_CONTROL,
                .enable_mask = WM8400_LDO3_ENA,
                .n_voltages = WM8400_LDO3_VSEL_MASK + 1,
+               .linear_ranges = wm8400_ldo_ranges,
+               .n_linear_ranges = ARRAY_SIZE(wm8400_ldo_ranges),
                .vsel_reg = WM8400_LDO3_CONTROL,
                .vsel_mask = WM8400_LDO3_VSEL_MASK,
                .type = REGULATOR_VOLTAGE,
@@ -191,6 +171,8 @@ static struct regulator_desc regulators[] = {
                .enable_reg = WM8400_LDO4_CONTROL,
                .enable_mask = WM8400_LDO4_ENA,
                .n_voltages = WM8400_LDO4_VSEL_MASK + 1,
+               .linear_ranges = wm8400_ldo_ranges,
+               .n_linear_ranges = ARRAY_SIZE(wm8400_ldo_ranges),
                .vsel_reg = WM8400_LDO4_CONTROL,
                .vsel_mask = WM8400_LDO4_VSEL_MASK,
                .type = REGULATOR_VOLTAGE,
@@ -233,7 +215,7 @@ static int wm8400_regulator_probe(struct platform_device *pdev)
        struct regulator_dev *rdev;
 
        config.dev = &pdev->dev;
-       config.init_data = pdev->dev.platform_data;
+       config.init_data = dev_get_platdata(&pdev->dev);
        config.driver_data = wm8400;
        config.regmap = wm8400->regmap;
 
index 8f2a8a7a3f997f5475d305b87f508a47a6daf267..5ee2a208457c2b58e46fb1f1d7a79e8b180c4a35 100644 (file)
@@ -125,7 +125,7 @@ static const struct regulator_init_data wm8994_ldo_default[] = {
 static int wm8994_ldo_probe(struct platform_device *pdev)
 {
        struct wm8994 *wm8994 = dev_get_drvdata(pdev->dev.parent);
-       struct wm8994_pdata *pdata = wm8994->dev->platform_data;
+       struct wm8994_pdata *pdata = dev_get_platdata(wm8994->dev);
        int id = pdev->id % ARRAY_SIZE(pdata->ldo);
        struct regulator_config config = { };
        struct wm8994_ldo *ldo;
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 89cbbabaff44c66771efc3f26b18e9b4565a4cc3..9e61107b0e0a19fb3fcf5052e4aa9c2e3029e152 100644 (file)
@@ -70,14 +70,14 @@ config SPI_ATH79
 
 config SPI_ATMEL
        tristate "Atmel SPI Controller"
-       depends on (ARCH_AT91 || AVR32)
+       depends on (ARCH_AT91 || AVR32 || COMPILE_TEST)
        help
          This selects a driver for the Atmel SPI Controller, present on
          many AT32 (AVR32) and AT91 (ARM) chips.
 
 config SPI_BCM2835
        tristate "BCM2835 SPI controller"
-       depends on ARCH_BCM2835
+       depends on ARCH_BCM2835 || COMPILE_TEST
        help
          This selects a driver for the Broadcom BCM2835 SPI master.
 
@@ -88,10 +88,17 @@ config SPI_BCM2835
 
 config SPI_BFIN5XX
        tristate "SPI controller driver for ADI Blackfin5xx"
-       depends on BLACKFIN
+       depends on BLACKFIN && !BF60x
        help
          This is the SPI controller master driver for Blackfin 5xx processor.
 
+config SPI_BFIN_V3
+       tristate "SPI controller v3 for Blackfin"
+       depends on BF60x
+       help
+         This is the SPI controller v3 master driver
+         found on Blackfin 60x processor.
+
 config SPI_BFIN_SPORT
        tristate "SPI bus via Blackfin SPORT"
        depends on BLACKFIN
@@ -151,7 +158,7 @@ config SPI_COLDFIRE_QSPI
 
 config SPI_DAVINCI
        tristate "Texas Instruments DaVinci/DA8x/OMAP-L/AM1x SoC SPI controller"
-       depends on ARCH_DAVINCI
+       depends on ARCH_DAVINCI || ARCH_KEYSTONE
        select SPI_BITBANG
        select TI_EDMA
        help
@@ -159,7 +166,7 @@ config SPI_DAVINCI
 
 config SPI_EP93XX
        tristate "Cirrus Logic EP93xx SPI controller"
-       depends on ARCH_EP93XX
+       depends on ARCH_EP93XX || COMPILE_TEST
        help
          This enables using the Cirrus EP93xx SPI controller in master
          mode.
@@ -191,7 +198,7 @@ config SPI_GPIO
 
 config SPI_IMX
        tristate "Freescale i.MX SPI controllers"
-       depends on ARCH_MXC
+       depends on ARCH_MXC || COMPILE_TEST
        select SPI_BITBANG
        default m if IMX_HAVE_PLATFORM_SPI_IMX
        help
@@ -280,20 +287,20 @@ config SPI_OMAP_UWIRE
 
 config SPI_OMAP24XX
        tristate "McSPI driver for OMAP"
-       depends on ARCH_OMAP2PLUS
+       depends on ARCH_OMAP2PLUS || COMPILE_TEST
        help
          SPI master controller for OMAP24XX and later Multichannel SPI
          (McSPI) modules.
 
 config SPI_OMAP_100K
        tristate "OMAP SPI 100K"
-       depends on ARCH_OMAP850 || ARCH_OMAP730
+       depends on ARCH_OMAP850 || ARCH_OMAP730 || COMPILE_TEST
        help
          OMAP SPI 100K master controller for omap7xx boards.
 
 config SPI_ORION
        tristate "Orion SPI master"
-       depends on PLAT_ORION
+       depends on PLAT_ORION || COMPILE_TEST
        help
          This enables using the SPI master controller on the Orion chips.
 
@@ -341,7 +348,7 @@ config SPI_PXA2XX_PCI
 
 config SPI_RSPI
        tristate "Renesas RSPI controller"
-       depends on SUPERH
+       depends on SUPERH && SH_DMAE_BASE
        help
          SPI driver for Renesas RSPI blocks.
 
@@ -385,7 +392,7 @@ config SPI_SH_MSIOF
 
 config SPI_SH
        tristate "SuperH SPI controller"
-       depends on SUPERH
+       depends on SUPERH || COMPILE_TEST
        help
          SPI driver for SuperH SPI blocks.
 
@@ -398,13 +405,13 @@ config SPI_SH_SCI
 
 config SPI_SH_HSPI
        tristate "SuperH HSPI controller"
-       depends on ARCH_SHMOBILE
+       depends on ARCH_SHMOBILE || COMPILE_TEST
        help
          SPI driver for SuperH HSPI blocks.
 
 config SPI_SIRF
        tristate "CSR SiRFprimaII SPI controller"
-       depends on ARCH_SIRF
+       depends on ARCH_SIRF || COMPILE_TEST
        select SPI_BITBANG
        help
          SPI driver for CSR SiRFprimaII SoCs
@@ -418,7 +425,7 @@ config SPI_MXS
 
 config SPI_TEGRA114
        tristate "NVIDIA Tegra114 SPI Controller"
-       depends on ARCH_TEGRA && TEGRA20_APB_DMA
+       depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST
        help
          SPI driver for NVIDIA Tegra114 SPI Controller interface. This controller
          is different than the older SoCs SPI controller and also register interface
@@ -426,7 +433,7 @@ config SPI_TEGRA114
 
 config SPI_TEGRA20_SFLASH
        tristate "Nvidia Tegra20 Serial flash Controller"
-       depends on ARCH_TEGRA
+       depends on ARCH_TEGRA || COMPILE_TEST
        help
          SPI driver for Nvidia Tegra20 Serial flash Controller interface.
          The main usecase of this controller is to use spi flash as boot
@@ -434,7 +441,7 @@ config SPI_TEGRA20_SFLASH
 
 config SPI_TEGRA20_SLINK
        tristate "Nvidia Tegra20/Tegra30 SLINK Controller"
-       depends on ARCH_TEGRA && TEGRA20_APB_DMA
+       depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST
        help
          SPI driver for Nvidia Tegra20/Tegra30 SLINK Controller interface.
 
@@ -457,7 +464,7 @@ config SPI_TOPCLIFF_PCH
 
 config SPI_TXX9
        tristate "Toshiba TXx9 SPI controller"
-       depends on GPIOLIB && CPU_TX49XX
+       depends on GPIOLIB && (CPU_TX49XX || COMPILE_TEST)
        help
          SPI driver for Toshiba TXx9 MIPS SoCs
 
index 33f9c09561e799051fb257f53f6161961cb734e7..7c4170263cd8db4bcb5bb126b33de16b34cc2cd0 100644 (file)
@@ -17,6 +17,7 @@ obj-$(CONFIG_SPI_AU1550)              += spi-au1550.o
 obj-$(CONFIG_SPI_BCM2835)              += spi-bcm2835.o
 obj-$(CONFIG_SPI_BCM63XX)              += spi-bcm63xx.o
 obj-$(CONFIG_SPI_BFIN5XX)              += spi-bfin5xx.o
+obj-$(CONFIG_SPI_BFIN_V3)               += spi-bfin-v3.o
 obj-$(CONFIG_SPI_BFIN_SPORT)           += spi-bfin-sport.o
 obj-$(CONFIG_SPI_BITBANG)              += spi-bitbang.o
 obj-$(CONFIG_SPI_BUTTERFLY)            += spi-butterfly.o
index ea1ec009f44d3573b96e582dad2608c14c841f3f..4e406930fa52e83fdfec8f11293aff1b5c9a0396 100644 (file)
@@ -360,12 +360,12 @@ static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi)
                gpio_set_value(asd->npcs_pin, !active);
 }
 
-static void atmel_spi_lock(struct atmel_spi *as)
+static void atmel_spi_lock(struct atmel_spi *as) __acquires(&as->lock)
 {
        spin_lock_irqsave(&as->lock, as->flags);
 }
 
-static void atmel_spi_unlock(struct atmel_spi *as)
+static void atmel_spi_unlock(struct atmel_spi *as) __releases(&as->lock)
 {
        spin_unlock_irqrestore(&as->lock, as->flags);
 }
@@ -1579,7 +1579,9 @@ static int atmel_spi_probe(struct platform_device *pdev)
                goto out_unmap_regs;
 
        /* Initialize the hardware */
-       clk_enable(clk);
+       ret = clk_prepare_enable(clk);
+       if (ret)
+               goto out_unmap_regs;
        spi_writel(as, CR, SPI_BIT(SWRST));
        spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
        if (as->caps.has_wdrbt) {
@@ -1609,7 +1611,7 @@ out_free_dma:
 
        spi_writel(as, CR, SPI_BIT(SWRST));
        spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
-       clk_disable(clk);
+       clk_disable_unprepare(clk);
        free_irq(irq, master);
 out_unmap_regs:
        iounmap(as->regs);
@@ -1661,7 +1663,7 @@ static int atmel_spi_remove(struct platform_device *pdev)
        dma_free_coherent(&pdev->dev, BUFFER_SIZE, as->buffer,
                        as->buffer_dma);
 
-       clk_disable(as->clk);
+       clk_disable_unprepare(as->clk);
        clk_put(as->clk);
        free_irq(as->irq, master);
        iounmap(as->regs);
@@ -1678,7 +1680,7 @@ static int atmel_spi_suspend(struct platform_device *pdev, pm_message_t mesg)
        struct spi_master       *master = platform_get_drvdata(pdev);
        struct atmel_spi        *as = spi_master_get_devdata(master);
 
-       clk_disable(as->clk);
+       clk_disable_unprepare(as->clk);
        return 0;
 }
 
@@ -1687,7 +1689,7 @@ static int atmel_spi_resume(struct platform_device *pdev)
        struct spi_master       *master = platform_get_drvdata(pdev);
        struct atmel_spi        *as = spi_master_get_devdata(master);
 
-       clk_enable(as->clk);
+       return clk_prepare_enable(as->clk);
        return 0;
 }
 
index a4185e492321b9261072d98226be0ddd5cd752c0..7604c52048627ecf47740d23ee4919a05fe1d0e6 100644 (file)
@@ -325,12 +325,6 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
        init_completion(&bs->done);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "could not get memory resource\n");
-               err = -ENODEV;
-               goto out_master_put;
-       }
-
        bs->regs = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(bs->regs)) {
                err = PTR_ERR(bs->regs);
index 9fd7a39b8029e2d630161a278879965f5abb9407..4ac028d6b2d840538175fb4aead2f0f4bfb491b1 100644 (file)
@@ -231,24 +231,6 @@ static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *first,
        return 0;
 }
 
-static int bcm63xx_spi_prepare_transfer(struct spi_master *master)
-{
-       struct bcm63xx_spi *bs = spi_master_get_devdata(master);
-
-       pm_runtime_get_sync(&bs->pdev->dev);
-
-       return 0;
-}
-
-static int bcm63xx_spi_unprepare_transfer(struct spi_master *master)
-{
-       struct bcm63xx_spi *bs = spi_master_get_devdata(master);
-
-       pm_runtime_put(&bs->pdev->dev);
-
-       return 0;
-}
-
 static int bcm63xx_spi_transfer_one(struct spi_master *master,
                                        struct spi_message *m)
 {
@@ -412,11 +394,10 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
 
        master->bus_num = pdata->bus_num;
        master->num_chipselect = pdata->num_chipselect;
-       master->prepare_transfer_hardware = bcm63xx_spi_prepare_transfer;
-       master->unprepare_transfer_hardware = bcm63xx_spi_unprepare_transfer;
        master->transfer_one_message = bcm63xx_spi_transfer_one;
        master->mode_bits = MODEBITS;
        master->bits_per_word_mask = SPI_BPW_MASK(8);
+       master->auto_runtime_pm = true;
        bs->msg_type_shift = pdata->msg_type_shift;
        bs->msg_ctl_width = pdata->msg_ctl_width;
        bs->tx_io = (u8 *)(bs->regs + bcm63xx_spireg(SPI_MSG_DATA));
diff --git a/drivers/spi/spi-bfin-v3.c b/drivers/spi/spi-bfin-v3.c
new file mode 100644 (file)
index 0000000..603d7e9
--- /dev/null
@@ -0,0 +1,973 @@
+/*
+ * Analog Devices SPI3 controller driver
+ *
+ * Copyright (c) 2013 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/types.h>
+
+#include <asm/bfin_spi3.h>
+#include <asm/cacheflush.h>
+#include <asm/dma.h>
+#include <asm/portmux.h>
+
+enum bfin_spi_state {
+       START_STATE,
+       RUNNING_STATE,
+       DONE_STATE,
+       ERROR_STATE
+};
+
+struct bfin_spi_master;
+
+struct bfin_spi_transfer_ops {
+       void (*write) (struct bfin_spi_master *);
+       void (*read) (struct bfin_spi_master *);
+       void (*duplex) (struct bfin_spi_master *);
+};
+
+/* runtime info for spi master */
+struct bfin_spi_master {
+       /* SPI framework hookup */
+       struct spi_master *master;
+
+       /* Regs base of SPI controller */
+       struct bfin_spi_regs __iomem *regs;
+
+       /* Pin request list */
+       u16 *pin_req;
+
+       /* Message Transfer pump */
+       struct tasklet_struct pump_transfers;
+
+       /* Current message transfer state info */
+       struct spi_message *cur_msg;
+       struct spi_transfer *cur_transfer;
+       struct bfin_spi_device *cur_chip;
+       unsigned transfer_len;
+
+       /* transfer buffer */
+       void *tx;
+       void *tx_end;
+       void *rx;
+       void *rx_end;
+
+       /* dma info */
+       unsigned int tx_dma;
+       unsigned int rx_dma;
+       dma_addr_t tx_dma_addr;
+       dma_addr_t rx_dma_addr;
+       unsigned long dummy_buffer; /* used in unidirectional transfer */
+       unsigned long tx_dma_size;
+       unsigned long rx_dma_size;
+       int tx_num;
+       int rx_num;
+
+       /* store register value for suspend/resume */
+       u32 control;
+       u32 ssel;
+
+       unsigned long sclk;
+       enum bfin_spi_state state;
+
+       const struct bfin_spi_transfer_ops *ops;
+};
+
+struct bfin_spi_device {
+       u32 control;
+       u32 clock;
+       u32 ssel;
+
+       u8 cs;
+       u16 cs_chg_udelay; /* Some devices require > 255usec delay */
+       u32 cs_gpio;
+       u32 tx_dummy_val; /* tx value for rx only transfer */
+       bool enable_dma;
+       const struct bfin_spi_transfer_ops *ops;
+};
+
+static void bfin_spi_enable(struct bfin_spi_master *drv_data)
+{
+       bfin_write_or(&drv_data->regs->control, SPI_CTL_EN);
+}
+
+static void bfin_spi_disable(struct bfin_spi_master *drv_data)
+{
+       bfin_write_and(&drv_data->regs->control, ~SPI_CTL_EN);
+}
+
+/* Caculate the SPI_CLOCK register value based on input HZ */
+static u32 hz_to_spi_clock(u32 sclk, u32 speed_hz)
+{
+       u32 spi_clock = sclk / speed_hz;
+
+       if (spi_clock)
+               spi_clock--;
+       return spi_clock;
+}
+
+static int bfin_spi_flush(struct bfin_spi_master *drv_data)
+{
+       unsigned long limit = loops_per_jiffy << 1;
+
+       /* wait for stop and clear stat */
+       while (!(bfin_read(&drv_data->regs->status) & SPI_STAT_SPIF) && --limit)
+               cpu_relax();
+
+       bfin_write(&drv_data->regs->status, 0xFFFFFFFF);
+
+       return limit;
+}
+
+/* Chip select operation functions for cs_change flag */
+static void bfin_spi_cs_active(struct bfin_spi_master *drv_data, struct bfin_spi_device *chip)
+{
+       if (likely(chip->cs < MAX_CTRL_CS))
+               bfin_write_and(&drv_data->regs->ssel, ~chip->ssel);
+       else
+               gpio_set_value(chip->cs_gpio, 0);
+}
+
+static void bfin_spi_cs_deactive(struct bfin_spi_master *drv_data,
+                               struct bfin_spi_device *chip)
+{
+       if (likely(chip->cs < MAX_CTRL_CS))
+               bfin_write_or(&drv_data->regs->ssel, chip->ssel);
+       else
+               gpio_set_value(chip->cs_gpio, 1);
+
+       /* Move delay here for consistency */
+       if (chip->cs_chg_udelay)
+               udelay(chip->cs_chg_udelay);
+}
+
+/* enable or disable the pin muxed by GPIO and SPI CS to work as SPI CS */
+static inline void bfin_spi_cs_enable(struct bfin_spi_master *drv_data,
+                                       struct bfin_spi_device *chip)
+{
+       if (chip->cs < MAX_CTRL_CS)
+               bfin_write_or(&drv_data->regs->ssel, chip->ssel >> 8);
+}
+
+static inline void bfin_spi_cs_disable(struct bfin_spi_master *drv_data,
+                                       struct bfin_spi_device *chip)
+{
+       if (chip->cs < MAX_CTRL_CS)
+               bfin_write_and(&drv_data->regs->ssel, ~(chip->ssel >> 8));
+}
+
+/* stop controller and re-config current chip*/
+static void bfin_spi_restore_state(struct bfin_spi_master *drv_data)
+{
+       struct bfin_spi_device *chip = drv_data->cur_chip;
+
+       /* Clear status and disable clock */
+       bfin_write(&drv_data->regs->status, 0xFFFFFFFF);
+       bfin_write(&drv_data->regs->rx_control, 0x0);
+       bfin_write(&drv_data->regs->tx_control, 0x0);
+       bfin_spi_disable(drv_data);
+
+       SSYNC();
+
+       /* Load the registers */
+       bfin_write(&drv_data->regs->control, chip->control);
+       bfin_write(&drv_data->regs->clock, chip->clock);
+
+       bfin_spi_enable(drv_data);
+       drv_data->tx_num = drv_data->rx_num = 0;
+       /* we always choose tx transfer initiate */
+       bfin_write(&drv_data->regs->rx_control, SPI_RXCTL_REN);
+       bfin_write(&drv_data->regs->tx_control,
+                       SPI_TXCTL_TEN | SPI_TXCTL_TTI);
+       bfin_spi_cs_active(drv_data, chip);
+}
+
+/* discard invalid rx data and empty rfifo */
+static inline void dummy_read(struct bfin_spi_master *drv_data)
+{
+       while (!(bfin_read(&drv_data->regs->status) & SPI_STAT_RFE))
+               bfin_read(&drv_data->regs->rfifo);
+}
+
+static void bfin_spi_u8_write(struct bfin_spi_master *drv_data)
+{
+       dummy_read(drv_data);
+       while (drv_data->tx < drv_data->tx_end) {
+               bfin_write(&drv_data->regs->tfifo, (*(u8 *)(drv_data->tx++)));
+               while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE)
+                       cpu_relax();
+               bfin_read(&drv_data->regs->rfifo);
+       }
+}
+
+static void bfin_spi_u8_read(struct bfin_spi_master *drv_data)
+{
+       u32 tx_val = drv_data->cur_chip->tx_dummy_val;
+
+       dummy_read(drv_data);
+       while (drv_data->rx < drv_data->rx_end) {
+               bfin_write(&drv_data->regs->tfifo, tx_val);
+               while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE)
+                       cpu_relax();
+               *(u8 *)(drv_data->rx++) = bfin_read(&drv_data->regs->rfifo);
+       }
+}
+
+static void bfin_spi_u8_duplex(struct bfin_spi_master *drv_data)
+{
+       dummy_read(drv_data);
+       while (drv_data->rx < drv_data->rx_end) {
+               bfin_write(&drv_data->regs->tfifo, (*(u8 *)(drv_data->tx++)));
+               while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE)
+                       cpu_relax();
+               *(u8 *)(drv_data->rx++) = bfin_read(&drv_data->regs->rfifo);
+       }
+}
+
+static const struct bfin_spi_transfer_ops bfin_bfin_spi_transfer_ops_u8 = {
+       .write  = bfin_spi_u8_write,
+       .read   = bfin_spi_u8_read,
+       .duplex = bfin_spi_u8_duplex,
+};
+
+static void bfin_spi_u16_write(struct bfin_spi_master *drv_data)
+{
+       dummy_read(drv_data);
+       while (drv_data->tx < drv_data->tx_end) {
+               bfin_write(&drv_data->regs->tfifo, (*(u16 *)drv_data->tx));
+               drv_data->tx += 2;
+               while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE)
+                       cpu_relax();
+               bfin_read(&drv_data->regs->rfifo);
+       }
+}
+
+static void bfin_spi_u16_read(struct bfin_spi_master *drv_data)
+{
+       u32 tx_val = drv_data->cur_chip->tx_dummy_val;
+
+       dummy_read(drv_data);
+       while (drv_data->rx < drv_data->rx_end) {
+               bfin_write(&drv_data->regs->tfifo, tx_val);
+               while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE)
+                       cpu_relax();
+               *(u16 *)drv_data->rx = bfin_read(&drv_data->regs->rfifo);
+               drv_data->rx += 2;
+       }
+}
+
+static void bfin_spi_u16_duplex(struct bfin_spi_master *drv_data)
+{
+       dummy_read(drv_data);
+       while (drv_data->rx < drv_data->rx_end) {
+               bfin_write(&drv_data->regs->tfifo, (*(u16 *)drv_data->tx));
+               drv_data->tx += 2;
+               while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE)
+                       cpu_relax();
+               *(u16 *)drv_data->rx = bfin_read(&drv_data->regs->rfifo);
+               drv_data->rx += 2;
+       }
+}
+
+static const struct bfin_spi_transfer_ops bfin_bfin_spi_transfer_ops_u16 = {
+       .write  = bfin_spi_u16_write,
+       .read   = bfin_spi_u16_read,
+       .duplex = bfin_spi_u16_duplex,
+};
+
+static void bfin_spi_u32_write(struct bfin_spi_master *drv_data)
+{
+       dummy_read(drv_data);
+       while (drv_data->tx < drv_data->tx_end) {
+               bfin_write(&drv_data->regs->tfifo, (*(u32 *)drv_data->tx));
+               drv_data->tx += 4;
+               while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE)
+                       cpu_relax();
+               bfin_read(&drv_data->regs->rfifo);
+       }
+}
+
+static void bfin_spi_u32_read(struct bfin_spi_master *drv_data)
+{
+       u32 tx_val = drv_data->cur_chip->tx_dummy_val;
+
+       dummy_read(drv_data);
+       while (drv_data->rx < drv_data->rx_end) {
+               bfin_write(&drv_data->regs->tfifo, tx_val);
+               while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE)
+                       cpu_relax();
+               *(u32 *)drv_data->rx = bfin_read(&drv_data->regs->rfifo);
+               drv_data->rx += 4;
+       }
+}
+
+static void bfin_spi_u32_duplex(struct bfin_spi_master *drv_data)
+{
+       dummy_read(drv_data);
+       while (drv_data->rx < drv_data->rx_end) {
+               bfin_write(&drv_data->regs->tfifo, (*(u32 *)drv_data->tx));
+               drv_data->tx += 4;
+               while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE)
+                       cpu_relax();
+               *(u32 *)drv_data->rx = bfin_read(&drv_data->regs->rfifo);
+               drv_data->rx += 4;
+       }
+}
+
+static const struct bfin_spi_transfer_ops bfin_bfin_spi_transfer_ops_u32 = {
+       .write  = bfin_spi_u32_write,
+       .read   = bfin_spi_u32_read,
+       .duplex = bfin_spi_u32_duplex,
+};
+
+
+/* test if there is more transfer to be done */
+static void bfin_spi_next_transfer(struct bfin_spi_master *drv)
+{
+       struct spi_message *msg = drv->cur_msg;
+       struct spi_transfer *t = drv->cur_transfer;
+
+       /* Move to next transfer */
+       if (t->transfer_list.next != &msg->transfers) {
+               drv->cur_transfer = list_entry(t->transfer_list.next,
+                              struct spi_transfer, transfer_list);
+               drv->state = RUNNING_STATE;
+       } else {
+               drv->state = DONE_STATE;
+               drv->cur_transfer = NULL;
+       }
+}
+
+static void bfin_spi_giveback(struct bfin_spi_master *drv_data)
+{
+       struct bfin_spi_device *chip = drv_data->cur_chip;
+
+       bfin_spi_cs_deactive(drv_data, chip);
+       spi_finalize_current_message(drv_data->master);
+}
+
+static int bfin_spi_setup_transfer(struct bfin_spi_master *drv)
+{
+       struct spi_transfer *t = drv->cur_transfer;
+       u32 cr, cr_width;
+
+       if (t->tx_buf) {
+               drv->tx = (void *)t->tx_buf;
+               drv->tx_end = drv->tx + t->len;
+       } else {
+               drv->tx = NULL;
+       }
+
+       if (t->rx_buf) {
+               drv->rx = t->rx_buf;
+               drv->rx_end = drv->rx + t->len;
+       } else {
+               drv->rx = NULL;
+       }
+
+       drv->transfer_len = t->len;
+
+       /* bits per word setup */
+       switch (t->bits_per_word) {
+       case 8:
+               cr_width = SPI_CTL_SIZE08;
+               drv->ops = &bfin_bfin_spi_transfer_ops_u8;
+               break;
+       case 16:
+               cr_width = SPI_CTL_SIZE16;
+               drv->ops = &bfin_bfin_spi_transfer_ops_u16;
+               break;
+       case 32:
+               cr_width = SPI_CTL_SIZE32;
+               drv->ops = &bfin_bfin_spi_transfer_ops_u32;
+               break;
+       default:
+               return -EINVAL;
+       }
+       cr = bfin_read(&drv->regs->control) & ~SPI_CTL_SIZE;
+       cr |= cr_width;
+       bfin_write(&drv->regs->control, cr);
+
+       /* speed setup */
+       bfin_write(&drv->regs->clock,
+                       hz_to_spi_clock(drv->sclk, t->speed_hz));
+       return 0;
+}
+
+static int bfin_spi_dma_xfer(struct bfin_spi_master *drv_data)
+{
+       struct spi_transfer *t = drv_data->cur_transfer;
+       struct spi_message *msg = drv_data->cur_msg;
+       struct bfin_spi_device *chip = drv_data->cur_chip;
+       u32 dma_config;
+       unsigned long word_count, word_size;
+       void *tx_buf, *rx_buf;
+
+       switch (t->bits_per_word) {
+       case 8:
+               dma_config = WDSIZE_8 | PSIZE_8;
+               word_count = drv_data->transfer_len;
+               word_size = 1;
+               break;
+       case 16:
+               dma_config = WDSIZE_16 | PSIZE_16;
+               word_count = drv_data->transfer_len / 2;
+               word_size = 2;
+               break;
+       default:
+               dma_config = WDSIZE_32 | PSIZE_32;
+               word_count = drv_data->transfer_len / 4;
+               word_size = 4;
+               break;
+       }
+
+       if (!drv_data->rx) {
+               tx_buf = drv_data->tx;
+               rx_buf = &drv_data->dummy_buffer;
+               drv_data->tx_dma_size = drv_data->transfer_len;
+               drv_data->rx_dma_size = sizeof(drv_data->dummy_buffer);
+               set_dma_x_modify(drv_data->tx_dma, word_size);
+               set_dma_x_modify(drv_data->rx_dma, 0);
+       } else if (!drv_data->tx) {
+               drv_data->dummy_buffer = chip->tx_dummy_val;
+               tx_buf = &drv_data->dummy_buffer;
+               rx_buf = drv_data->rx;
+               drv_data->tx_dma_size = sizeof(drv_data->dummy_buffer);
+               drv_data->rx_dma_size = drv_data->transfer_len;
+               set_dma_x_modify(drv_data->tx_dma, 0);
+               set_dma_x_modify(drv_data->rx_dma, word_size);
+       } else {
+               tx_buf = drv_data->tx;
+               rx_buf = drv_data->rx;
+               drv_data->tx_dma_size = drv_data->rx_dma_size
+                                       = drv_data->transfer_len;
+               set_dma_x_modify(drv_data->tx_dma, word_size);
+               set_dma_x_modify(drv_data->rx_dma, word_size);
+       }
+
+       drv_data->tx_dma_addr = dma_map_single(&msg->spi->dev,
+                               (void *)tx_buf,
+                               drv_data->tx_dma_size,
+                               DMA_TO_DEVICE);
+       if (dma_mapping_error(&msg->spi->dev,
+                               drv_data->tx_dma_addr))
+               return -ENOMEM;
+
+       drv_data->rx_dma_addr = dma_map_single(&msg->spi->dev,
+                               (void *)rx_buf,
+                               drv_data->rx_dma_size,
+                               DMA_FROM_DEVICE);
+       if (dma_mapping_error(&msg->spi->dev,
+                               drv_data->rx_dma_addr)) {
+               dma_unmap_single(&msg->spi->dev,
+                               drv_data->tx_dma_addr,
+                               drv_data->tx_dma_size,
+                               DMA_TO_DEVICE);
+               return -ENOMEM;
+       }
+
+       dummy_read(drv_data);
+       set_dma_x_count(drv_data->tx_dma, word_count);
+       set_dma_x_count(drv_data->rx_dma, word_count);
+       set_dma_start_addr(drv_data->tx_dma, drv_data->tx_dma_addr);
+       set_dma_start_addr(drv_data->rx_dma, drv_data->rx_dma_addr);
+       dma_config |= DMAFLOW_STOP | RESTART | DI_EN;
+       set_dma_config(drv_data->tx_dma, dma_config);
+       set_dma_config(drv_data->rx_dma, dma_config | WNR);
+       enable_dma(drv_data->tx_dma);
+       enable_dma(drv_data->rx_dma);
+       SSYNC();
+
+       bfin_write(&drv_data->regs->rx_control, SPI_RXCTL_REN | SPI_RXCTL_RDR_NE);
+       SSYNC();
+       bfin_write(&drv_data->regs->tx_control,
+                       SPI_TXCTL_TEN | SPI_TXCTL_TTI | SPI_TXCTL_TDR_NF);
+
+       return 0;
+}
+
+static int bfin_spi_pio_xfer(struct bfin_spi_master *drv_data)
+{
+       struct spi_message *msg = drv_data->cur_msg;
+
+       if (!drv_data->rx) {
+               /* write only half duplex */
+               drv_data->ops->write(drv_data);
+               if (drv_data->tx != drv_data->tx_end)
+                       return -EIO;
+       } else if (!drv_data->tx) {
+               /* read only half duplex */
+               drv_data->ops->read(drv_data);
+               if (drv_data->rx != drv_data->rx_end)
+                       return -EIO;
+       } else {
+               /* full duplex mode */
+               drv_data->ops->duplex(drv_data);
+               if (drv_data->tx != drv_data->tx_end)
+                       return -EIO;
+       }
+
+       if (!bfin_spi_flush(drv_data))
+               return -EIO;
+       msg->actual_length += drv_data->transfer_len;
+       tasklet_schedule(&drv_data->pump_transfers);
+       return 0;
+}
+
+static void bfin_spi_pump_transfers(unsigned long data)
+{
+       struct bfin_spi_master *drv_data = (struct bfin_spi_master *)data;
+       struct spi_message *msg = NULL;
+       struct spi_transfer *t = NULL;
+       struct bfin_spi_device *chip = NULL;
+       int ret;
+
+       /* Get current state information */
+       msg = drv_data->cur_msg;
+       t = drv_data->cur_transfer;
+       chip = drv_data->cur_chip;
+
+       /* Handle for abort */
+       if (drv_data->state == ERROR_STATE) {
+               msg->status = -EIO;
+               bfin_spi_giveback(drv_data);
+               return;
+       }
+
+       if (drv_data->state == RUNNING_STATE) {
+               if (t->delay_usecs)
+                       udelay(t->delay_usecs);
+               if (t->cs_change)
+                       bfin_spi_cs_deactive(drv_data, chip);
+               bfin_spi_next_transfer(drv_data);
+               t = drv_data->cur_transfer;
+       }
+       /* Handle end of message */
+       if (drv_data->state == DONE_STATE) {
+               msg->status = 0;
+               bfin_spi_giveback(drv_data);
+               return;
+       }
+
+       if ((t->len == 0) || (t->tx_buf == NULL && t->rx_buf == NULL)) {
+               /* Schedule next transfer tasklet */
+               tasklet_schedule(&drv_data->pump_transfers);
+               return;
+       }
+
+       ret = bfin_spi_setup_transfer(drv_data);
+       if (ret) {
+               msg->status = ret;
+               bfin_spi_giveback(drv_data);
+       }
+
+       bfin_write(&drv_data->regs->status, 0xFFFFFFFF);
+       bfin_spi_cs_active(drv_data, chip);
+       drv_data->state = RUNNING_STATE;
+
+       if (chip->enable_dma)
+               ret = bfin_spi_dma_xfer(drv_data);
+       else
+               ret = bfin_spi_pio_xfer(drv_data);
+       if (ret) {
+               msg->status = ret;
+               bfin_spi_giveback(drv_data);
+       }
+}
+
+static int bfin_spi_transfer_one_message(struct spi_master *master,
+                                       struct spi_message *m)
+{
+       struct bfin_spi_master *drv_data = spi_master_get_devdata(master);
+
+       drv_data->cur_msg = m;
+       drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi);
+       bfin_spi_restore_state(drv_data);
+
+       drv_data->state = START_STATE;
+       drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next,
+                                           struct spi_transfer, transfer_list);
+
+       tasklet_schedule(&drv_data->pump_transfers);
+       return 0;
+}
+
+#define MAX_SPI_SSEL   7
+
+static const u16 ssel[][MAX_SPI_SSEL] = {
+       {P_SPI0_SSEL1, P_SPI0_SSEL2, P_SPI0_SSEL3,
+       P_SPI0_SSEL4, P_SPI0_SSEL5,
+       P_SPI0_SSEL6, P_SPI0_SSEL7},
+
+       {P_SPI1_SSEL1, P_SPI1_SSEL2, P_SPI1_SSEL3,
+       P_SPI1_SSEL4, P_SPI1_SSEL5,
+       P_SPI1_SSEL6, P_SPI1_SSEL7},
+
+       {P_SPI2_SSEL1, P_SPI2_SSEL2, P_SPI2_SSEL3,
+       P_SPI2_SSEL4, P_SPI2_SSEL5,
+       P_SPI2_SSEL6, P_SPI2_SSEL7},
+};
+
+static int bfin_spi_setup(struct spi_device *spi)
+{
+       struct bfin_spi_master *drv_data = spi_master_get_devdata(spi->master);
+       struct bfin_spi_device *chip = spi_get_ctldata(spi);
+       u32 bfin_ctl_reg = SPI_CTL_ODM | SPI_CTL_PSSE;
+       int ret = -EINVAL;
+
+       if (!chip) {
+               struct bfin_spi3_chip *chip_info = spi->controller_data;
+
+               chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+               if (!chip) {
+                       dev_err(&spi->dev, "can not allocate chip data\n");
+                       return -ENOMEM;
+               }
+               if (chip_info) {
+                       if (chip_info->control & ~bfin_ctl_reg) {
+                               dev_err(&spi->dev,
+                                       "do not set bits that the SPI framework manages\n");
+                               goto error;
+                       }
+                       chip->control = chip_info->control;
+                       chip->cs_chg_udelay = chip_info->cs_chg_udelay;
+                       chip->tx_dummy_val = chip_info->tx_dummy_val;
+                       chip->enable_dma = chip_info->enable_dma;
+               }
+               chip->cs = spi->chip_select;
+               if (chip->cs < MAX_CTRL_CS) {
+                       chip->ssel = (1 << chip->cs) << 8;
+                       ret = peripheral_request(ssel[spi->master->bus_num]
+                                       [chip->cs-1], dev_name(&spi->dev));
+                       if (ret) {
+                               dev_err(&spi->dev, "peripheral_request() error\n");
+                               goto error;
+                       }
+               } else {
+                       chip->cs_gpio = chip->cs - MAX_CTRL_CS;
+                       ret = gpio_request_one(chip->cs_gpio, GPIOF_OUT_INIT_HIGH,
+                                               dev_name(&spi->dev));
+                       if (ret) {
+                               dev_err(&spi->dev, "gpio_request_one() error\n");
+                               goto error;
+                       }
+               }
+               spi_set_ctldata(spi, chip);
+       }
+
+       /* force a default base state */
+       chip->control &= bfin_ctl_reg;
+
+       if (spi->mode & SPI_CPOL)
+               chip->control |= SPI_CTL_CPOL;
+       if (spi->mode & SPI_CPHA)
+               chip->control |= SPI_CTL_CPHA;
+       if (spi->mode & SPI_LSB_FIRST)
+               chip->control |= SPI_CTL_LSBF;
+       chip->control |= SPI_CTL_MSTR;
+       /* we choose software to controll cs */
+       chip->control &= ~SPI_CTL_ASSEL;
+
+       chip->clock = hz_to_spi_clock(drv_data->sclk, spi->max_speed_hz);
+
+       bfin_spi_cs_enable(drv_data, chip);
+       bfin_spi_cs_deactive(drv_data, chip);
+
+       return 0;
+error:
+       if (chip) {
+               kfree(chip);
+               spi_set_ctldata(spi, NULL);
+       }
+
+       return ret;
+}
+
+static void bfin_spi_cleanup(struct spi_device *spi)
+{
+       struct bfin_spi_device *chip = spi_get_ctldata(spi);
+       struct bfin_spi_master *drv_data = spi_master_get_devdata(spi->master);
+
+       if (!chip)
+               return;
+
+       if (chip->cs < MAX_CTRL_CS) {
+               peripheral_free(ssel[spi->master->bus_num]
+                                       [chip->cs-1]);
+               bfin_spi_cs_disable(drv_data, chip);
+       } else {
+               gpio_free(chip->cs_gpio);
+       }
+
+       kfree(chip);
+       spi_set_ctldata(spi, NULL);
+}
+
+static irqreturn_t bfin_spi_tx_dma_isr(int irq, void *dev_id)
+{
+       struct bfin_spi_master *drv_data = dev_id;
+       u32 dma_stat = get_dma_curr_irqstat(drv_data->tx_dma);
+
+       clear_dma_irqstat(drv_data->tx_dma);
+       if (dma_stat & DMA_DONE) {
+               drv_data->tx_num++;
+       } else {
+               dev_err(&drv_data->master->dev,
+                               "spi tx dma error: %d\n", dma_stat);
+               if (drv_data->tx)
+                       drv_data->state = ERROR_STATE;
+       }
+       bfin_write_and(&drv_data->regs->tx_control, ~SPI_TXCTL_TDR_NF);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t bfin_spi_rx_dma_isr(int irq, void *dev_id)
+{
+       struct bfin_spi_master *drv_data = dev_id;
+       struct spi_message *msg = drv_data->cur_msg;
+       u32 dma_stat = get_dma_curr_irqstat(drv_data->rx_dma);
+
+       clear_dma_irqstat(drv_data->rx_dma);
+       if (dma_stat & DMA_DONE) {
+               drv_data->rx_num++;
+               /* we may fail on tx dma */
+               if (drv_data->state != ERROR_STATE)
+                       msg->actual_length += drv_data->transfer_len;
+       } else {
+               drv_data->state = ERROR_STATE;
+               dev_err(&drv_data->master->dev,
+                               "spi rx dma error: %d\n", dma_stat);
+       }
+       bfin_write(&drv_data->regs->tx_control, 0);
+       bfin_write(&drv_data->regs->rx_control, 0);
+       if (drv_data->rx_num != drv_data->tx_num)
+               dev_dbg(&drv_data->master->dev,
+                               "dma interrupt missing: tx=%d,rx=%d\n",
+                               drv_data->tx_num, drv_data->rx_num);
+       tasklet_schedule(&drv_data->pump_transfers);
+       return IRQ_HANDLED;
+}
+
+static int bfin_spi_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct bfin_spi3_master *info = dev->platform_data;
+       struct spi_master *master;
+       struct bfin_spi_master *drv_data;
+       struct resource *mem, *res;
+       unsigned int tx_dma, rx_dma;
+       unsigned long sclk;
+       int ret;
+
+       if (!info) {
+               dev_err(dev, "platform data missing!\n");
+               return -ENODEV;
+       }
+
+       sclk = get_sclk1();
+       if (!sclk) {
+               dev_err(dev, "can not get sclk1\n");
+               return -ENXIO;
+       }
+
+       /* get register base and tx/rx dma */
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem) {
+               dev_err(dev, "can not get register base\n");
+               return -ENXIO;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+       if (!res) {
+               dev_err(dev, "can not get tx dma resource\n");
+               return -ENXIO;
+       }
+       tx_dma = res->start;
+
+       res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+       if (!res) {
+               dev_err(dev, "can not get rx dma resource\n");
+               return -ENXIO;
+       }
+       rx_dma = res->start;
+
+       /* allocate master with space for drv_data */
+       master = spi_alloc_master(dev, sizeof(*drv_data));
+       if (!master) {
+               dev_err(dev, "can not alloc spi_master\n");
+               return -ENOMEM;
+       }
+       platform_set_drvdata(pdev, master);
+
+       /* the mode bits supported by this driver */
+       master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
+
+       master->bus_num = pdev->id;
+       master->num_chipselect = info->num_chipselect;
+       master->cleanup = bfin_spi_cleanup;
+       master->setup = bfin_spi_setup;
+       master->transfer_one_message = bfin_spi_transfer_one_message;
+       master->bits_per_word_mask = BIT(32 - 1) | BIT(16 - 1) | BIT(8 - 1);
+
+       drv_data = spi_master_get_devdata(master);
+       drv_data->master = master;
+       drv_data->tx_dma = tx_dma;
+       drv_data->rx_dma = rx_dma;
+       drv_data->pin_req = info->pin_req;
+       drv_data->sclk = sclk;
+
+       drv_data->regs = devm_ioremap_resource(dev, mem);
+       if (IS_ERR(drv_data->regs)) {
+               ret = PTR_ERR(drv_data->regs);
+               goto err_put_master;
+       }
+
+       /* request tx and rx dma */
+       ret = request_dma(tx_dma, "SPI_TX_DMA");
+       if (ret) {
+               dev_err(dev, "can not request SPI TX DMA channel\n");
+               goto err_put_master;
+       }
+       set_dma_callback(tx_dma, bfin_spi_tx_dma_isr, drv_data);
+
+       ret = request_dma(rx_dma, "SPI_RX_DMA");
+       if (ret) {
+               dev_err(dev, "can not request SPI RX DMA channel\n");
+               goto err_free_tx_dma;
+       }
+       set_dma_callback(drv_data->rx_dma, bfin_spi_rx_dma_isr, drv_data);
+
+       /* request CLK, MOSI and MISO */
+       ret = peripheral_request_list(drv_data->pin_req, "bfin-spi3");
+       if (ret < 0) {
+               dev_err(dev, "can not request spi pins\n");
+               goto err_free_rx_dma;
+       }
+
+       bfin_write(&drv_data->regs->control, SPI_CTL_MSTR | SPI_CTL_CPHA);
+       bfin_write(&drv_data->regs->ssel, 0x0000FE00);
+       bfin_write(&drv_data->regs->delay, 0x0);
+
+       tasklet_init(&drv_data->pump_transfers,
+                       bfin_spi_pump_transfers, (unsigned long)drv_data);
+       /* register with the SPI framework */
+       ret = spi_register_master(master);
+       if (ret) {
+               dev_err(dev, "can not  register spi master\n");
+               goto err_free_peripheral;
+       }
+
+       return ret;
+
+err_free_peripheral:
+       peripheral_free_list(drv_data->pin_req);
+err_free_rx_dma:
+       free_dma(rx_dma);
+err_free_tx_dma:
+       free_dma(tx_dma);
+err_put_master:
+       platform_set_drvdata(pdev, NULL);
+       spi_master_put(master);
+
+       return ret;
+}
+
+static int bfin_spi_remove(struct platform_device *pdev)
+{
+       struct spi_master *master = platform_get_drvdata(pdev);
+       struct bfin_spi_master *drv_data = spi_master_get_devdata(master);
+
+       bfin_spi_disable(drv_data);
+
+       peripheral_free_list(drv_data->pin_req);
+       free_dma(drv_data->rx_dma);
+       free_dma(drv_data->tx_dma);
+
+       platform_set_drvdata(pdev, NULL);
+       spi_unregister_master(drv_data->master);
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int bfin_spi_suspend(struct device *dev)
+{
+       struct spi_master *master = dev_get_drvdata(dev);
+       struct bfin_spi_master *drv_data = spi_master_get_devdata(master);
+
+       spi_master_suspend(master);
+
+       drv_data->control = bfin_read(&drv_data->regs->control);
+       drv_data->ssel = bfin_read(&drv_data->regs->ssel);
+
+       bfin_write(&drv_data->regs->control, SPI_CTL_MSTR | SPI_CTL_CPHA);
+       bfin_write(&drv_data->regs->ssel, 0x0000FE00);
+       dma_disable_irq(drv_data->rx_dma);
+       dma_disable_irq(drv_data->tx_dma);
+
+       return 0;
+}
+
+static int bfin_spi_resume(struct device *dev)
+{
+       struct spi_master *master = dev_get_drvdata(dev);
+       struct bfin_spi_master *drv_data = spi_master_get_devdata(master);
+       int ret = 0;
+
+       /* bootrom may modify spi and dma status when resume in spi boot mode */
+       disable_dma(drv_data->rx_dma);
+
+       dma_enable_irq(drv_data->rx_dma);
+       dma_enable_irq(drv_data->tx_dma);
+       bfin_write(&drv_data->regs->control, drv_data->control);
+       bfin_write(&drv_data->regs->ssel, drv_data->ssel);
+
+       ret = spi_master_resume(master);
+       if (ret) {
+               free_dma(drv_data->rx_dma);
+               free_dma(drv_data->tx_dma);
+       }
+
+       return ret;
+}
+#endif
+static const struct dev_pm_ops bfin_spi_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(bfin_spi_suspend, bfin_spi_resume)
+};
+
+MODULE_ALIAS("platform:bfin-spi3");
+static struct platform_driver bfin_spi_driver = {
+       .driver = {
+               .name   = "bfin-spi3",
+               .owner  = THIS_MODULE,
+               .pm     = &bfin_spi_pm_ops,
+       },
+       .remove         = bfin_spi_remove,
+};
+
+module_platform_driver_probe(bfin_spi_driver, bfin_spi_probe);
+
+MODULE_DESCRIPTION("Analog Devices SPI3 controller driver");
+MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
+MODULE_LICENSE("GPL v2");
index a63d7da3bfe2209bebd921bfc81cdafb5d0a8cfd..a89178dc849802dd052eb3c026978e30c252e7cb 100644 (file)
@@ -255,150 +255,142 @@ static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t)
  * Drivers can provide word-at-a-time i/o primitives, or provide
  * transfer-at-a-time ones to leverage dma or fifo hardware.
  */
-static void bitbang_work(struct work_struct *work)
+
+static int spi_bitbang_prepare_hardware(struct spi_master *spi)
 {
-       struct spi_bitbang      *bitbang =
-               container_of(work, struct spi_bitbang, work);
+       struct spi_bitbang      *bitbang;
        unsigned long           flags;
-       struct spi_message      *m, *_m;
+
+       bitbang = spi_master_get_devdata(spi);
 
        spin_lock_irqsave(&bitbang->lock, flags);
        bitbang->busy = 1;
-       list_for_each_entry_safe(m, _m, &bitbang->queue, queue) {
-               struct spi_device       *spi;
-               unsigned                nsecs;
-               struct spi_transfer     *t = NULL;
-               unsigned                tmp;
-               unsigned                cs_change;
-               int                     status;
-               int                     do_setup = -1;
-
-               list_del(&m->queue);
-               spin_unlock_irqrestore(&bitbang->lock, flags);
-
-               /* FIXME this is made-up ... the correct value is known to
-                * word-at-a-time bitbang code, and presumably chipselect()
-                * should enforce these requirements too?
-                */
-               nsecs = 100;
+       spin_unlock_irqrestore(&bitbang->lock, flags);
 
-               spi = m->spi;
-               tmp = 0;
-               cs_change = 1;
-               status = 0;
+       return 0;
+}
 
-               list_for_each_entry (t, &m->transfers, transfer_list) {
-
-                       /* override speed or wordsize? */
-                       if (t->speed_hz || t->bits_per_word)
-                               do_setup = 1;
-
-                       /* init (-1) or override (1) transfer params */
-                       if (do_setup != 0) {
-                               status = bitbang->setup_transfer(spi, t);
-                               if (status < 0)
-                                       break;
-                               if (do_setup == -1)
-                                       do_setup = 0;
-                       }
-
-                       /* set up default clock polarity, and activate chip;
-                        * this implicitly updates clock and spi modes as
-                        * previously recorded for this device via setup().
-                        * (and also deselects any other chip that might be
-                        * selected ...)
-                        */
-                       if (cs_change) {
-                               bitbang->chipselect(spi, BITBANG_CS_ACTIVE);
-                               ndelay(nsecs);
-                       }
-                       cs_change = t->cs_change;
-                       if (!t->tx_buf && !t->rx_buf && t->len) {
-                               status = -EINVAL;
-                               break;
-                       }
+static int spi_bitbang_transfer_one(struct spi_master *master,
+                                   struct spi_message *m)
+{
+       struct spi_bitbang      *bitbang;
+       unsigned                nsecs;
+       struct spi_transfer     *t = NULL;
+       unsigned                tmp;
+       unsigned                cs_change;
+       int                     status;
+       int                     do_setup = -1;
+       struct spi_device       *spi = m->spi;
+
+       bitbang = spi_master_get_devdata(master);
+
+       /* FIXME this is made-up ... the correct value is known to
+        * word-at-a-time bitbang code, and presumably chipselect()
+        * should enforce these requirements too?
+        */
+       nsecs = 100;
 
-                       /* transfer data.  the lower level code handles any
-                        * new dma mappings it needs. our caller always gave
-                        * us dma-safe buffers.
-                        */
-                       if (t->len) {
-                               /* REVISIT dma API still needs a designated
-                                * DMA_ADDR_INVALID; ~0 might be better.
-                                */
-                               if (!m->is_dma_mapped)
-                                       t->rx_dma = t->tx_dma = 0;
-                               status = bitbang->txrx_bufs(spi, t);
-                       }
-                       if (status > 0)
-                               m->actual_length += status;
-                       if (status != t->len) {
-                               /* always report some kind of error */
-                               if (status >= 0)
-                                       status = -EREMOTEIO;
+       tmp = 0;
+       cs_change = 1;
+       status = 0;
+
+       list_for_each_entry (t, &m->transfers, transfer_list) {
+
+               /* override speed or wordsize? */
+               if (t->speed_hz || t->bits_per_word)
+                       do_setup = 1;
+
+               /* init (-1) or override (1) transfer params */
+               if (do_setup != 0) {
+                       status = bitbang->setup_transfer(spi, t);
+                       if (status < 0)
                                break;
-                       }
-                       status = 0;
-
-                       /* protocol tweaks before next transfer */
-                       if (t->delay_usecs)
-                               udelay(t->delay_usecs);
-
-                       if (cs_change && !list_is_last(&t->transfer_list, &m->transfers)) {
-                               /* sometimes a short mid-message deselect of the chip
-                                * may be needed to terminate a mode or command
-                                */
-                               ndelay(nsecs);
-                               bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
-                               ndelay(nsecs);
-                       }
+                       if (do_setup == -1)
+                               do_setup = 0;
                }
 
-               m->status = status;
-               m->complete(m->context);
+               /* set up default clock polarity, and activate chip;
+                * this implicitly updates clock and spi modes as
+                * previously recorded for this device via setup().
+                * (and also deselects any other chip that might be
+                * selected ...)
+                */
+               if (cs_change) {
+                       bitbang->chipselect(spi, BITBANG_CS_ACTIVE);
+                       ndelay(nsecs);
+               }
+               cs_change = t->cs_change;
+               if (!t->tx_buf && !t->rx_buf && t->len) {
+                       status = -EINVAL;
+                       break;
+               }
 
-               /* normally deactivate chipselect ... unless no error and
-                * cs_change has hinted that the next message will probably
-                * be for this chip too.
+               /* transfer data.  the lower level code handles any
+                * new dma mappings it needs. our caller always gave
+                * us dma-safe buffers.
                 */
-               if (!(status == 0 && cs_change)) {
+               if (t->len) {
+                       /* REVISIT dma API still needs a designated
+                        * DMA_ADDR_INVALID; ~0 might be better.
+                        */
+                       if (!m->is_dma_mapped)
+                               t->rx_dma = t->tx_dma = 0;
+                       status = bitbang->txrx_bufs(spi, t);
+               }
+               if (status > 0)
+                       m->actual_length += status;
+               if (status != t->len) {
+                       /* always report some kind of error */
+                       if (status >= 0)
+                               status = -EREMOTEIO;
+                       break;
+               }
+               status = 0;
+
+               /* protocol tweaks before next transfer */
+               if (t->delay_usecs)
+                       udelay(t->delay_usecs);
+
+               if (cs_change && !list_is_last(&t->transfer_list, &m->transfers)) {
+                       /* sometimes a short mid-message deselect of the chip
+                        * may be needed to terminate a mode or command
+                        */
                        ndelay(nsecs);
                        bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
                        ndelay(nsecs);
                }
+       }
+
+       m->status = status;
 
-               spin_lock_irqsave(&bitbang->lock, flags);
+       /* normally deactivate chipselect ... unless no error and
+        * cs_change has hinted that the next message will probably
+        * be for this chip too.
+        */
+       if (!(status == 0 && cs_change)) {
+               ndelay(nsecs);
+               bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
+               ndelay(nsecs);
        }
-       bitbang->busy = 0;
-       spin_unlock_irqrestore(&bitbang->lock, flags);
+
+       spi_finalize_current_message(master);
+
+       return status;
 }
 
-/**
- * spi_bitbang_transfer - default submit to transfer queue
- */
-int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m)
+static int spi_bitbang_unprepare_hardware(struct spi_master *spi)
 {
-       struct spi_bitbang      *bitbang;
+       struct spi_bitbang      *bitbang;
        unsigned long           flags;
-       int                     status = 0;
 
-       m->actual_length = 0;
-       m->status = -EINPROGRESS;
-
-       bitbang = spi_master_get_devdata(spi->master);
+       bitbang = spi_master_get_devdata(spi);
 
        spin_lock_irqsave(&bitbang->lock, flags);
-       if (!spi->max_speed_hz)
-               status = -ENETDOWN;
-       else {
-               list_add_tail(&m->queue, &bitbang->queue);
-               queue_work(bitbang->workqueue, &bitbang->work);
-       }
+       bitbang->busy = 0;
        spin_unlock_irqrestore(&bitbang->lock, flags);
 
-       return status;
+       return 0;
 }
-EXPORT_SYMBOL_GPL(spi_bitbang_transfer);
 
 /*----------------------------------------------------------------------*/
 
@@ -428,20 +420,22 @@ EXPORT_SYMBOL_GPL(spi_bitbang_transfer);
 int spi_bitbang_start(struct spi_bitbang *bitbang)
 {
        struct spi_master *master = bitbang->master;
-       int status;
 
        if (!master || !bitbang->chipselect)
                return -EINVAL;
 
-       INIT_WORK(&bitbang->work, bitbang_work);
        spin_lock_init(&bitbang->lock);
-       INIT_LIST_HEAD(&bitbang->queue);
 
        if (!master->mode_bits)
                master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags;
 
-       if (!master->transfer)
-               master->transfer = spi_bitbang_transfer;
+       if (master->transfer || master->transfer_one_message)
+               return -EINVAL;
+
+       master->prepare_transfer_hardware = spi_bitbang_prepare_hardware;
+       master->unprepare_transfer_hardware = spi_bitbang_unprepare_hardware;
+       master->transfer_one_message = spi_bitbang_transfer_one;
+
        if (!bitbang->txrx_bufs) {
                bitbang->use_dma = 0;
                bitbang->txrx_bufs = spi_bitbang_bufs;
@@ -454,32 +448,11 @@ int spi_bitbang_start(struct spi_bitbang *bitbang)
                }
        } else if (!master->setup)
                return -EINVAL;
-       if (master->transfer == spi_bitbang_transfer &&
-                       !bitbang->setup_transfer)
-               return -EINVAL;
-
-       /* this task is the only thing to touch the SPI bits */
-       bitbang->busy = 0;
-       bitbang->workqueue = create_singlethread_workqueue(
-                       dev_name(master->dev.parent));
-       if (bitbang->workqueue == NULL) {
-               status = -EBUSY;
-               goto err1;
-       }
 
        /* driver may get busy before register() returns, especially
         * if someone registered boardinfo for devices
         */
-       status = spi_register_master(master);
-       if (status < 0)
-               goto err2;
-
-       return status;
-
-err2:
-       destroy_workqueue(bitbang->workqueue);
-err1:
-       return status;
+       return spi_register_master(master);
 }
 EXPORT_SYMBOL_GPL(spi_bitbang_start);
 
@@ -490,10 +463,6 @@ int spi_bitbang_stop(struct spi_bitbang *bitbang)
 {
        spi_unregister_master(bitbang->master);
 
-       WARN_ON(!list_empty(&bitbang->queue));
-
-       destroy_workqueue(bitbang->workqueue);
-
        return 0;
 }
 EXPORT_SYMBOL_GPL(spi_bitbang_stop);
index 17965fe225ccd4cf50aef85235466468b0de049a..5655acf55bfe35a7d4f0fcb853e56435b4e847c9 100644 (file)
@@ -239,11 +239,8 @@ static int spi_clps711x_probe(struct platform_device *pdev)
        }
 
        dev_err(&pdev->dev, "Failed to register master\n");
-       devm_free_irq(&pdev->dev, IRQ_SSEOTI, hw);
 
 clk_out:
-       devm_clk_put(&pdev->dev, hw->spi_clk);
-
 err_out:
        while (--i >= 0)
                if (gpio_is_valid(hw->chipselect[i]))
@@ -261,13 +258,10 @@ static int spi_clps711x_remove(struct platform_device *pdev)
        struct spi_master *master = platform_get_drvdata(pdev);
        struct spi_clps711x_data *hw = spi_master_get_devdata(master);
 
-       devm_free_irq(&pdev->dev, IRQ_SSEOTI, hw);
-
        for (i = 0; i < master->num_chipselect; i++)
                if (gpio_is_valid(hw->chipselect[i]))
                        gpio_free(hw->chipselect[i]);
 
-       devm_clk_put(&pdev->dev, hw->spi_clk);
        spi_unregister_master(master);
        kfree(master);
 
index 0631b9d4a5de7eb70d9e15fa3f701b9f8bb59c70..e4265eaf054856cc05600d8f4b0ac6c8bdad689f 100644 (file)
@@ -354,24 +354,6 @@ static int mcfqspi_transfer_one_message(struct spi_master *master,
 
 }
 
-static int mcfqspi_prepare_transfer_hw(struct spi_master *master)
-{
-       struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
-
-       pm_runtime_get_sync(mcfqspi->dev);
-
-       return 0;
-}
-
-static int mcfqspi_unprepare_transfer_hw(struct spi_master *master)
-{
-       struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
-
-       pm_runtime_put_sync(mcfqspi->dev);
-
-       return 0;
-}
-
 static int mcfqspi_setup(struct spi_device *spi)
 {
        if (spi->chip_select >= spi->master->num_chipselect) {
@@ -473,8 +455,7 @@ static int mcfqspi_probe(struct platform_device *pdev)
        master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16);
        master->setup = mcfqspi_setup;
        master->transfer_one_message = mcfqspi_transfer_one_message;
-       master->prepare_transfer_hardware = mcfqspi_prepare_transfer_hw;
-       master->unprepare_transfer_hardware = mcfqspi_unprepare_transfer_hw;
+       master->auto_runtime_pm = true;
 
        platform_set_drvdata(pdev, master);
 
index 222d3e37fc283b95dc5932570c1dec874cec78e2..707966bd56103181d31887b53cca01c1d9bd9776 100644 (file)
@@ -609,7 +609,7 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
                else
                        buf = (void *)t->tx_buf;
                t->tx_dma = dma_map_single(&spi->dev, buf,
-                               t->len, DMA_FROM_DEVICE);
+                               t->len, DMA_TO_DEVICE);
                if (!t->tx_dma) {
                        ret = -EFAULT;
                        goto err_tx_map;
index cad30b8a1d71cb7b573879ae21814c49758419a3..4c9a50ce4f6c6274ece881a440f41a1aab01e864 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/workqueue.h>
 #include <linux/sched.h>
 #include <linux/scatterlist.h>
 #include <linux/spi/spi.h>
 
 /**
  * struct ep93xx_spi - EP93xx SPI controller structure
- * @lock: spinlock that protects concurrent accesses to fields @running,
- *        @current_msg and @msg_queue
  * @pdev: pointer to platform device
  * @clk: clock for the controller
  * @regs_base: pointer to ioremap()'d registers
  * @sspdr_phys: physical address of the SSPDR register
  * @min_rate: minimum clock rate (in Hz) supported by the controller
  * @max_rate: maximum clock rate (in Hz) supported by the controller
- * @running: is the queue running
- * @wq: workqueue used by the driver
- * @msg_work: work that is queued for the driver
  * @wait: wait here until given transfer is completed
- * @msg_queue: queue for the messages
  * @current_msg: message that is currently processed (or %NULL if none)
  * @tx: current byte in transfer to transmit
  * @rx: current byte in transfer to receive
  * @tx_sgt: sg table for TX transfers
  * @zeropage: dummy page used as RX buffer when only TX buffer is passed in by
  *            the client
- *
- * This structure holds EP93xx SPI controller specific information. When
- * @running is %true, driver accepts transfer requests from protocol drivers.
- * @current_msg is used to hold pointer to the message that is currently
- * processed. If @current_msg is %NULL, it means that no processing is going
- * on.
- *
- * Most of the fields are only written once and they can be accessed without
- * taking the @lock. Fields that are accessed concurrently are: @current_msg,
- * @running, and @msg_queue.
  */
 struct ep93xx_spi {
-       spinlock_t                      lock;
        const struct platform_device    *pdev;
        struct clk                      *clk;
        void __iomem                    *regs_base;
        unsigned long                   sspdr_phys;
        unsigned long                   min_rate;
        unsigned long                   max_rate;
-       bool                            running;
-       struct workqueue_struct         *wq;
-       struct work_struct              msg_work;
        struct completion               wait;
-       struct list_head                msg_queue;
        struct spi_message              *current_msg;
        size_t                          tx;
        size_t                          rx;
@@ -136,50 +114,36 @@ struct ep93xx_spi {
 /**
  * struct ep93xx_spi_chip - SPI device hardware settings
  * @spi: back pointer to the SPI device
- * @rate: max rate in hz this chip supports
- * @div_cpsr: cpsr (pre-scaler) divider
- * @div_scr: scr divider
- * @dss: bits per word (4 - 16 bits)
  * @ops: private chip operations
- *
- * This structure is used to store hardware register specific settings for each
- * SPI device. Settings are written to hardware by function
- * ep93xx_spi_chip_setup().
  */
 struct ep93xx_spi_chip {
        const struct spi_device         *spi;
-       unsigned long                   rate;
-       u8                              div_cpsr;
-       u8                              div_scr;
-       u8                              dss;
        struct ep93xx_spi_chip_ops      *ops;
 };
 
 /* converts bits per word to CR0.DSS value */
 #define bits_per_word_to_dss(bpw)      ((bpw) - 1)
 
-static inline void
-ep93xx_spi_write_u8(const struct ep93xx_spi *espi, u16 reg, u8 value)
+static void ep93xx_spi_write_u8(const struct ep93xx_spi *espi,
+                               u16 reg, u8 value)
 {
-       __raw_writeb(value, espi->regs_base + reg);
+       writeb(value, espi->regs_base + reg);
 }
 
-static inline u8
-ep93xx_spi_read_u8(const struct ep93xx_spi *spi, u16 reg)
+static u8 ep93xx_spi_read_u8(const struct ep93xx_spi *spi, u16 reg)
 {
-       return __raw_readb(spi->regs_base + reg);
+       return readb(spi->regs_base + reg);
 }
 
-static inline void
-ep93xx_spi_write_u16(const struct ep93xx_spi *espi, u16 reg, u16 value)
+static void ep93xx_spi_write_u16(const struct ep93xx_spi *espi,
+                                u16 reg, u16 value)
 {
-       __raw_writew(value, espi->regs_base + reg);
+       writew(value, espi->regs_base + reg);
 }
 
-static inline u16
-ep93xx_spi_read_u16(const struct ep93xx_spi *spi, u16 reg)
+static u16 ep93xx_spi_read_u16(const struct ep93xx_spi *spi, u16 reg)
 {
-       return __raw_readw(spi->regs_base + reg);
+       return readw(spi->regs_base + reg);
 }
 
 static int ep93xx_spi_enable(const struct ep93xx_spi *espi)
@@ -230,17 +194,13 @@ static void ep93xx_spi_disable_interrupts(const struct ep93xx_spi *espi)
 /**
  * ep93xx_spi_calc_divisors() - calculates SPI clock divisors
  * @espi: ep93xx SPI controller struct
- * @chip: divisors are calculated for this chip
  * @rate: desired SPI output clock rate
- *
- * Function calculates cpsr (clock pre-scaler) and scr divisors based on
- * given @rate and places them to @chip->div_cpsr and @chip->div_scr. If,
- * for some reason, divisors cannot be calculated nothing is stored and
- * %-EINVAL is returned.
+ * @div_cpsr: pointer to return the cpsr (pre-scaler) divider
+ * @div_scr: pointer to return the scr divider
  */
 static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi,
-                                   struct ep93xx_spi_chip *chip,
-                                   unsigned long rate)
+                                   unsigned long rate,
+                                   u8 *div_cpsr, u8 *div_scr)
 {
        unsigned long spi_clk_rate = clk_get_rate(espi->clk);
        int cpsr, scr;
@@ -248,7 +208,7 @@ static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi,
        /*
         * Make sure that max value is between values supported by the
         * controller. Note that minimum value is already checked in
-        * ep93xx_spi_transfer().
+        * ep93xx_spi_transfer_one_message().
         */
        rate = clamp(rate, espi->min_rate, espi->max_rate);
 
@@ -263,8 +223,8 @@ static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi,
        for (cpsr = 2; cpsr <= 254; cpsr += 2) {
                for (scr = 0; scr <= 255; scr++) {
                        if ((spi_clk_rate / (cpsr * (scr + 1))) <= rate) {
-                               chip->div_scr = (u8)scr;
-                               chip->div_cpsr = (u8)cpsr;
+                               *div_scr = (u8)scr;
+                               *div_cpsr = (u8)cpsr;
                                return 0;
                        }
                }
@@ -319,72 +279,10 @@ static int ep93xx_spi_setup(struct spi_device *spi)
                spi_set_ctldata(spi, chip);
        }
 
-       if (spi->max_speed_hz != chip->rate) {
-               int err;
-
-               err = ep93xx_spi_calc_divisors(espi, chip, spi->max_speed_hz);
-               if (err != 0) {
-                       spi_set_ctldata(spi, NULL);
-                       kfree(chip);
-                       return err;
-               }
-               chip->rate = spi->max_speed_hz;
-       }
-
-       chip->dss = bits_per_word_to_dss(spi->bits_per_word);
-
        ep93xx_spi_cs_control(spi, false);
        return 0;
 }
 
-/**
- * ep93xx_spi_transfer() - queue message to be transferred
- * @spi: target SPI device
- * @msg: message to be transferred
- *
- * This function is called by SPI device drivers when they are going to transfer
- * a new message. It simply puts the message in the queue and schedules
- * workqueue to perform the actual transfer later on.
- *
- * Returns %0 on success and negative error in case of failure.
- */
-static int ep93xx_spi_transfer(struct spi_device *spi, struct spi_message *msg)
-{
-       struct ep93xx_spi *espi = spi_master_get_devdata(spi->master);
-       struct spi_transfer *t;
-       unsigned long flags;
-
-       if (!msg || !msg->complete)
-               return -EINVAL;
-
-       /* first validate each transfer */
-       list_for_each_entry(t, &msg->transfers, transfer_list) {
-               if (t->speed_hz && t->speed_hz < espi->min_rate)
-                               return -EINVAL;
-       }
-
-       /*
-        * Now that we own the message, let's initialize it so that it is
-        * suitable for us. We use @msg->status to signal whether there was
-        * error in transfer and @msg->state is used to hold pointer to the
-        * current transfer (or %NULL if no active current transfer).
-        */
-       msg->state = NULL;
-       msg->status = 0;
-       msg->actual_length = 0;
-
-       spin_lock_irqsave(&espi->lock, flags);
-       if (!espi->running) {
-               spin_unlock_irqrestore(&espi->lock, flags);
-               return -ESHUTDOWN;
-       }
-       list_add_tail(&msg->queue, &espi->msg_queue);
-       queue_work(espi->wq, &espi->msg_work);
-       spin_unlock_irqrestore(&espi->lock, flags);
-
-       return 0;
-}
-
 /**
  * ep93xx_spi_cleanup() - cleans up master controller specific state
  * @spi: SPI device to cleanup
@@ -409,39 +307,40 @@ static void ep93xx_spi_cleanup(struct spi_device *spi)
  * ep93xx_spi_chip_setup() - configures hardware according to given @chip
  * @espi: ep93xx SPI controller struct
  * @chip: chip specific settings
- *
- * This function sets up the actual hardware registers with settings given in
- * @chip. Note that no validation is done so make sure that callers validate
- * settings before calling this.
+ * @speed_hz: transfer speed
+ * @bits_per_word: transfer bits_per_word
  */
-static void ep93xx_spi_chip_setup(const struct ep93xx_spi *espi,
-                                 const struct ep93xx_spi_chip *chip)
+static int ep93xx_spi_chip_setup(const struct ep93xx_spi *espi,
+                                const struct ep93xx_spi_chip *chip,
+                                u32 speed_hz, u8 bits_per_word)
 {
+       u8 dss = bits_per_word_to_dss(bits_per_word);
+       u8 div_cpsr = 0;
+       u8 div_scr = 0;
        u16 cr0;
+       int err;
 
-       cr0 = chip->div_scr << SSPCR0_SCR_SHIFT;
+       err = ep93xx_spi_calc_divisors(espi, speed_hz, &div_cpsr, &div_scr);
+       if (err)
+               return err;
+
+       cr0 = div_scr << SSPCR0_SCR_SHIFT;
        cr0 |= (chip->spi->mode & (SPI_CPHA|SPI_CPOL)) << SSPCR0_MODE_SHIFT;
-       cr0 |= chip->dss;
+       cr0 |= dss;
 
        dev_dbg(&espi->pdev->dev, "setup: mode %d, cpsr %d, scr %d, dss %d\n",
-               chip->spi->mode, chip->div_cpsr, chip->div_scr, chip->dss);
+               chip->spi->mode, div_cpsr, div_scr, dss);
        dev_dbg(&espi->pdev->dev, "setup: cr0 %#x", cr0);
 
-       ep93xx_spi_write_u8(espi, SSPCPSR, chip->div_cpsr);
+       ep93xx_spi_write_u8(espi, SSPCPSR, div_cpsr);
        ep93xx_spi_write_u16(espi, SSPCR0, cr0);
-}
-
-static inline int bits_per_word(const struct ep93xx_spi *espi)
-{
-       struct spi_message *msg = espi->current_msg;
-       struct spi_transfer *t = msg->state;
 
-       return t->bits_per_word;
+       return 0;
 }
 
 static void ep93xx_do_write(struct ep93xx_spi *espi, struct spi_transfer *t)
 {
-       if (bits_per_word(espi) > 8) {
+       if (t->bits_per_word > 8) {
                u16 tx_val = 0;
 
                if (t->tx_buf)
@@ -460,7 +359,7 @@ static void ep93xx_do_write(struct ep93xx_spi *espi, struct spi_transfer *t)
 
 static void ep93xx_do_read(struct ep93xx_spi *espi, struct spi_transfer *t)
 {
-       if (bits_per_word(espi) > 8) {
+       if (t->bits_per_word > 8) {
                u16 rx_val;
 
                rx_val = ep93xx_spi_read_u16(espi, SSPDR);
@@ -546,7 +445,7 @@ ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_transfer_direction dir)
        size_t len = t->len;
        int i, ret, nents;
 
-       if (bits_per_word(espi) > 8)
+       if (t->bits_per_word > 8)
                buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
        else
                buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
@@ -708,37 +607,16 @@ static void ep93xx_spi_process_transfer(struct ep93xx_spi *espi,
                                        struct spi_transfer *t)
 {
        struct ep93xx_spi_chip *chip = spi_get_ctldata(msg->spi);
+       int err;
 
        msg->state = t;
 
-       /*
-        * Handle any transfer specific settings if needed. We use
-        * temporary chip settings here and restore original later when
-        * the transfer is finished.
-        */
-       if (t->speed_hz || t->bits_per_word) {
-               struct ep93xx_spi_chip tmp_chip = *chip;
-
-               if (t->speed_hz) {
-                       int err;
-
-                       err = ep93xx_spi_calc_divisors(espi, &tmp_chip,
-                                                      t->speed_hz);
-                       if (err) {
-                               dev_err(&espi->pdev->dev,
-                                       "failed to adjust speed\n");
-                               msg->status = err;
-                               return;
-                       }
-               }
-
-               if (t->bits_per_word)
-                       tmp_chip.dss = bits_per_word_to_dss(t->bits_per_word);
-
-               /*
-                * Set up temporary new hw settings for this transfer.
-                */
-               ep93xx_spi_chip_setup(espi, &tmp_chip);
+       err = ep93xx_spi_chip_setup(espi, chip, t->speed_hz, t->bits_per_word);
+       if (err) {
+               dev_err(&espi->pdev->dev,
+                       "failed to setup chip for transfer\n");
+               msg->status = err;
+               return;
        }
 
        espi->rx = 0;
@@ -783,9 +661,6 @@ static void ep93xx_spi_process_transfer(struct ep93xx_spi *espi,
                        ep93xx_spi_cs_control(msg->spi, true);
                }
        }
-
-       if (t->speed_hz || t->bits_per_word)
-               ep93xx_spi_chip_setup(espi, chip);
 }
 
 /*
@@ -838,10 +713,8 @@ static void ep93xx_spi_process_message(struct ep93xx_spi *espi,
        espi->fifo_level = 0;
 
        /*
-        * Update SPI controller registers according to spi device and assert
-        * the chipselect.
+        * Assert the chipselect.
         */
-       ep93xx_spi_chip_setup(espi, spi_get_ctldata(msg->spi));
        ep93xx_spi_cs_control(msg->spi, true);
 
        list_for_each_entry(t, &msg->transfers, transfer_list) {
@@ -858,50 +731,29 @@ static void ep93xx_spi_process_message(struct ep93xx_spi *espi,
        ep93xx_spi_disable(espi);
 }
 
-#define work_to_espi(work) (container_of((work), struct ep93xx_spi, msg_work))
-
-/**
- * ep93xx_spi_work() - EP93xx SPI workqueue worker function
- * @work: work struct
- *
- * Workqueue worker function. This function is called when there are new
- * SPI messages to be processed. Message is taken out from the queue and then
- * passed to ep93xx_spi_process_message().
- *
- * After message is transferred, protocol driver is notified by calling
- * @msg->complete(). In case of error, @msg->status is set to negative error
- * number, otherwise it contains zero (and @msg->actual_length is updated).
- */
-static void ep93xx_spi_work(struct work_struct *work)
+static int ep93xx_spi_transfer_one_message(struct spi_master *master,
+                                          struct spi_message *msg)
 {
-       struct ep93xx_spi *espi = work_to_espi(work);
-       struct spi_message *msg;
+       struct ep93xx_spi *espi = spi_master_get_devdata(master);
+       struct spi_transfer *t;
 
-       spin_lock_irq(&espi->lock);
-       if (!espi->running || espi->current_msg ||
-               list_empty(&espi->msg_queue)) {
-               spin_unlock_irq(&espi->lock);
-               return;
+       /* first validate each transfer */
+       list_for_each_entry(t, &msg->transfers, transfer_list) {
+               if (t->speed_hz < espi->min_rate)
+                       return -EINVAL;
        }
-       msg = list_first_entry(&espi->msg_queue, struct spi_message, queue);
-       list_del_init(&msg->queue);
-       espi->current_msg = msg;
-       spin_unlock_irq(&espi->lock);
 
-       ep93xx_spi_process_message(espi, msg);
+       msg->state = NULL;
+       msg->status = 0;
+       msg->actual_length = 0;
 
-       /*
-        * Update the current message and re-schedule ourselves if there are
-        * more messages in the queue.
-        */
-       spin_lock_irq(&espi->lock);
+       espi->current_msg = msg;
+       ep93xx_spi_process_message(espi, msg);
        espi->current_msg = NULL;
-       if (espi->running && !list_empty(&espi->msg_queue))
-               queue_work(espi->wq, &espi->msg_work);
-       spin_unlock_irq(&espi->lock);
 
-       /* notify the protocol driver that we are done with this message */
-       msg->complete(msg->context);
+       spi_finalize_current_message(master);
+
+       return 0;
 }
 
 static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
@@ -1024,14 +876,24 @@ static int ep93xx_spi_probe(struct platform_device *pdev)
 
        info = pdev->dev.platform_data;
 
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "failed to get irq resources\n");
+               return -EBUSY;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "unable to get iomem resource\n");
+               return -ENODEV;
+       }
+
        master = spi_alloc_master(&pdev->dev, sizeof(*espi));
-       if (!master) {
-               dev_err(&pdev->dev, "failed to allocate spi master\n");
+       if (!master)
                return -ENOMEM;
-       }
 
        master->setup = ep93xx_spi_setup;
-       master->transfer = ep93xx_spi_transfer;
+       master->transfer_one_message = ep93xx_spi_transfer_one_message;
        master->cleanup = ep93xx_spi_cleanup;
        master->bus_num = pdev->id;
        master->num_chipselect = info->num_chipselect;
@@ -1042,14 +904,13 @@ static int ep93xx_spi_probe(struct platform_device *pdev)
 
        espi = spi_master_get_devdata(master);
 
-       espi->clk = clk_get(&pdev->dev, NULL);
+       espi->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(espi->clk)) {
                dev_err(&pdev->dev, "unable to get spi clock\n");
                error = PTR_ERR(espi->clk);
                goto fail_release_master;
        }
 
-       spin_lock_init(&espi->lock);
        init_completion(&espi->wait);
 
        /*
@@ -1060,55 +921,31 @@ static int ep93xx_spi_probe(struct platform_device *pdev)
        espi->min_rate = clk_get_rate(espi->clk) / (254 * 256);
        espi->pdev = pdev;
 
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
-               error = -EBUSY;
-               dev_err(&pdev->dev, "failed to get irq resources\n");
-               goto fail_put_clock;
-       }
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "unable to get iomem resource\n");
-               error = -ENODEV;
-               goto fail_put_clock;
-       }
-
        espi->sspdr_phys = res->start + SSPDR;
 
        espi->regs_base = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(espi->regs_base)) {
                error = PTR_ERR(espi->regs_base);
-               goto fail_put_clock;
+               goto fail_release_master;
        }
 
        error = devm_request_irq(&pdev->dev, irq, ep93xx_spi_interrupt,
                                0, "ep93xx-spi", espi);
        if (error) {
                dev_err(&pdev->dev, "failed to request irq\n");
-               goto fail_put_clock;
+               goto fail_release_master;
        }
 
        if (info->use_dma && ep93xx_spi_setup_dma(espi))
                dev_warn(&pdev->dev, "DMA setup failed. Falling back to PIO\n");
 
-       espi->wq = create_singlethread_workqueue("ep93xx_spid");
-       if (!espi->wq) {
-               dev_err(&pdev->dev, "unable to create workqueue\n");
-               error = -ENOMEM;
-               goto fail_free_dma;
-       }
-       INIT_WORK(&espi->msg_work, ep93xx_spi_work);
-       INIT_LIST_HEAD(&espi->msg_queue);
-       espi->running = true;
-
        /* make sure that the hardware is disabled */
        ep93xx_spi_write_u8(espi, SSPCR1, 0);
 
        error = spi_register_master(master);
        if (error) {
                dev_err(&pdev->dev, "failed to register SPI master\n");
-               goto fail_free_queue;
+               goto fail_free_dma;
        }
 
        dev_info(&pdev->dev, "EP93xx SPI Controller at 0x%08lx irq %d\n",
@@ -1116,12 +953,8 @@ static int ep93xx_spi_probe(struct platform_device *pdev)
 
        return 0;
 
-fail_free_queue:
-       destroy_workqueue(espi->wq);
 fail_free_dma:
        ep93xx_spi_release_dma(espi);
-fail_put_clock:
-       clk_put(espi->clk);
 fail_release_master:
        spi_master_put(master);
 
@@ -1133,31 +966,7 @@ static int ep93xx_spi_remove(struct platform_device *pdev)
        struct spi_master *master = platform_get_drvdata(pdev);
        struct ep93xx_spi *espi = spi_master_get_devdata(master);
 
-       spin_lock_irq(&espi->lock);
-       espi->running = false;
-       spin_unlock_irq(&espi->lock);
-
-       destroy_workqueue(espi->wq);
-
-       /*
-        * Complete remaining messages with %-ESHUTDOWN status.
-        */
-       spin_lock_irq(&espi->lock);
-       while (!list_empty(&espi->msg_queue)) {
-               struct spi_message *msg;
-
-               msg = list_first_entry(&espi->msg_queue,
-                                      struct spi_message, queue);
-               list_del_init(&msg->queue);
-               msg->status = -ESHUTDOWN;
-               spin_unlock_irq(&espi->lock);
-               msg->complete(msg->context);
-               spin_lock_irq(&espi->lock);
-       }
-       spin_unlock_irq(&espi->lock);
-
        ep93xx_spi_release_dma(espi);
-       clk_put(espi->clk);
 
        spi_unregister_master(master);
        return 0;
index 7db4f43ee4d840c30514fe322cc871556071236c..15323d8bd9cfa4237c34069a76e3700dd6873c15 100644 (file)
@@ -619,6 +619,7 @@ static const struct of_device_id spi_imx_dt_ids[] = {
        { .compatible = "fsl,imx51-ecspi", .data = &imx51_ecspi_devtype_data, },
        { /* sentinel */ }
 };
+MODULE_DEVICE_TABLE(of, spi_imx_dt_ids);
 
 static void spi_imx_chipselect(struct spi_device *spi, int is_active)
 {
@@ -796,10 +797,11 @@ static int spi_imx_probe(struct platform_device *pdev)
                if (!gpio_is_valid(cs_gpio))
                        continue;
 
-               ret = gpio_request(spi_imx->chipselect[i], DRIVER_NAME);
+               ret = devm_gpio_request(&pdev->dev, spi_imx->chipselect[i],
+                                       DRIVER_NAME);
                if (ret) {
                        dev_err(&pdev->dev, "can't get cs gpios\n");
-                       goto out_gpio_free;
+                       goto out_master_put;
                }
        }
 
@@ -816,50 +818,44 @@ static int spi_imx_probe(struct platform_device *pdev)
                (struct spi_imx_devtype_data *) pdev->id_entry->driver_data;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "can't get platform resource\n");
-               ret = -ENOMEM;
-               goto out_gpio_free;
-       }
-
-       if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
-               dev_err(&pdev->dev, "request_mem_region failed\n");
-               ret = -EBUSY;
-               goto out_gpio_free;
-       }
-
-       spi_imx->base = ioremap(res->start, resource_size(res));
-       if (!spi_imx->base) {
-               ret = -EINVAL;
-               goto out_release_mem;
+       spi_imx->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(spi_imx->base)) {
+               ret = PTR_ERR(spi_imx->base);
+               goto out_master_put;
        }
 
        spi_imx->irq = platform_get_irq(pdev, 0);
        if (spi_imx->irq < 0) {
                ret = -EINVAL;
-               goto out_iounmap;
+               goto out_master_put;
        }
 
-       ret = request_irq(spi_imx->irq, spi_imx_isr, 0, DRIVER_NAME, spi_imx);
+       ret = devm_request_irq(&pdev->dev, spi_imx->irq, spi_imx_isr, 0,
+                              DRIVER_NAME, spi_imx);
        if (ret) {
                dev_err(&pdev->dev, "can't get irq%d: %d\n", spi_imx->irq, ret);
-               goto out_iounmap;
+               goto out_master_put;
        }
 
        spi_imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
        if (IS_ERR(spi_imx->clk_ipg)) {
                ret = PTR_ERR(spi_imx->clk_ipg);
-               goto out_free_irq;
+               goto out_master_put;
        }
 
        spi_imx->clk_per = devm_clk_get(&pdev->dev, "per");
        if (IS_ERR(spi_imx->clk_per)) {
                ret = PTR_ERR(spi_imx->clk_per);
-               goto out_free_irq;
+               goto out_master_put;
        }
 
-       clk_prepare_enable(spi_imx->clk_per);
-       clk_prepare_enable(spi_imx->clk_ipg);
+       ret = clk_prepare_enable(spi_imx->clk_per);
+       if (ret)
+               goto out_master_put;
+
+       ret = clk_prepare_enable(spi_imx->clk_ipg);
+       if (ret)
+               goto out_put_per;
 
        spi_imx->spi_clk = clk_get_rate(spi_imx->clk_per);
 
@@ -879,47 +875,27 @@ static int spi_imx_probe(struct platform_device *pdev)
        return ret;
 
 out_clk_put:
-       clk_disable_unprepare(spi_imx->clk_per);
        clk_disable_unprepare(spi_imx->clk_ipg);
-out_free_irq:
-       free_irq(spi_imx->irq, spi_imx);
-out_iounmap:
-       iounmap(spi_imx->base);
-out_release_mem:
-       release_mem_region(res->start, resource_size(res));
-out_gpio_free:
-       while (--i >= 0) {
-               if (gpio_is_valid(spi_imx->chipselect[i]))
-                       gpio_free(spi_imx->chipselect[i]);
-       }
+out_put_per:
+       clk_disable_unprepare(spi_imx->clk_per);
+out_master_put:
        spi_master_put(master);
-       kfree(master);
+
        return ret;
 }
 
 static int spi_imx_remove(struct platform_device *pdev)
 {
        struct spi_master *master = platform_get_drvdata(pdev);
-       struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
-       int i;
 
        spi_bitbang_stop(&spi_imx->bitbang);
 
        writel(0, spi_imx->base + MXC_CSPICTRL);
-       clk_disable_unprepare(spi_imx->clk_per);
        clk_disable_unprepare(spi_imx->clk_ipg);
-       free_irq(spi_imx->irq, spi_imx);
-       iounmap(spi_imx->base);
-
-       for (i = 0; i < master->num_chipselect; i++)
-               if (gpio_is_valid(spi_imx->chipselect[i]))
-                       gpio_free(spi_imx->chipselect[i]);
-
+       clk_disable_unprepare(spi_imx->clk_per);
        spi_master_put(master);
 
-       release_mem_region(res->start, resource_size(res));
-
        return 0;
 }
 
index 424d38e59421db2c621e1a14c1950f3777b7de75..d7b3e4311f72fdf1bcac02848cb43f3f80cf9f6d 100644 (file)
@@ -513,7 +513,7 @@ static int mxs_spi_probe(struct platform_device *pdev)
 
        iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        irq_err = platform_get_irq(pdev, 0);
-       if (!iores || irq_err < 0)
+       if (irq_err < 0)
                return -EINVAL;
 
        base = devm_ioremap_resource(&pdev->dev, iores);
@@ -563,25 +563,31 @@ static int mxs_spi_probe(struct platform_device *pdev)
                goto out_master_free;
        }
 
-       clk_prepare_enable(ssp->clk);
+       ret = clk_prepare_enable(ssp->clk);
+       if (ret)
+               goto out_dma_release;
+
        clk_set_rate(ssp->clk, clk_freq);
        ssp->clk_rate = clk_get_rate(ssp->clk) / 1000;
 
-       stmp_reset_block(ssp->base);
+       ret = stmp_reset_block(ssp->base);
+       if (ret)
+               goto out_disable_clk;
 
        platform_set_drvdata(pdev, master);
 
        ret = spi_register_master(master);
        if (ret) {
                dev_err(&pdev->dev, "Cannot register SPI master, %d\n", ret);
-               goto out_free_dma;
+               goto out_disable_clk;
        }
 
        return 0;
 
-out_free_dma:
-       dma_release_channel(ssp->dmach);
+out_disable_clk:
        clk_disable_unprepare(ssp->clk);
+out_dma_release:
+       dma_release_channel(ssp->dmach);
 out_master_free:
        spi_master_put(master);
        return ret;
@@ -598,11 +604,8 @@ static int mxs_spi_remove(struct platform_device *pdev)
        ssp = &spi->ssp;
 
        spi_unregister_master(master);
-
-       dma_release_channel(ssp->dmach);
-
        clk_disable_unprepare(ssp->clk);
-
+       dma_release_channel(ssp->dmach);
        spi_master_put(master);
 
        return 0;
index ee25670f8cfd127341fff7ddc16562a7e512507d..cdcc72c5d380b3364936d377ddcc2f7f866829c6 100644 (file)
 #define SPI_SHUTDOWN   1
 
 struct omap1_spi100k {
-       struct work_struct      work;
-
-       /* lock protects queue and registers */
-       spinlock_t              lock;
-       struct list_head        msg_queue;
        struct spi_master       *master;
        struct clk              *ick;
        struct clk              *fck;
@@ -104,8 +99,6 @@ struct omap1_spi100k_cs {
        int                     word_len;
 };
 
-static struct workqueue_struct *omap1_spi100k_wq;
-
 #define MOD_REG_BIT(val, mask, set) do { \
        if (set) \
                val |= mask; \
@@ -310,170 +303,102 @@ static int omap1_spi100k_setup(struct spi_device *spi)
 
        spi100k_open(spi->master);
 
-       clk_enable(spi100k->ick);
-       clk_enable(spi100k->fck);
+       clk_prepare_enable(spi100k->ick);
+       clk_prepare_enable(spi100k->fck);
 
        ret = omap1_spi100k_setup_transfer(spi, NULL);
 
-       clk_disable(spi100k->ick);
-       clk_disable(spi100k->fck);
+       clk_disable_unprepare(spi100k->ick);
+       clk_disable_unprepare(spi100k->fck);
 
        return ret;
 }
 
-static void omap1_spi100k_work(struct work_struct *work)
+static int omap1_spi100k_prepare_hardware(struct spi_master *master)
 {
-       struct omap1_spi100k    *spi100k;
-       int status = 0;
+       struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
 
-       spi100k = container_of(work, struct omap1_spi100k, work);
-       spin_lock_irq(&spi100k->lock);
+       clk_prepare_enable(spi100k->ick);
+       clk_prepare_enable(spi100k->fck);
 
-       clk_enable(spi100k->ick);
-       clk_enable(spi100k->fck);
+       return 0;
+}
 
-       /* We only enable one channel at a time -- the one whose message is
-        * at the head of the queue -- although this controller would gladly
-        * arbitrate among multiple channels.  This corresponds to "single
-        * channel" master mode.  As a side effect, we need to manage the
-        * chipselect with the FORCE bit ... CS != channel enable.
-        */
-        while (!list_empty(&spi100k->msg_queue)) {
-               struct spi_message              *m;
-               struct spi_device               *spi;
-               struct spi_transfer             *t = NULL;
-               int                             cs_active = 0;
-               struct omap1_spi100k_cs         *cs;
-               int                             par_override = 0;
-
-               m = container_of(spi100k->msg_queue.next, struct spi_message,
-                                queue);
-
-               list_del_init(&m->queue);
-               spin_unlock_irq(&spi100k->lock);
-
-               spi = m->spi;
-               cs = spi->controller_state;
-
-               list_for_each_entry(t, &m->transfers, transfer_list) {
-                       if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
-                               status = -EINVAL;
+static int omap1_spi100k_transfer_one_message(struct spi_master *master,
+                                             struct spi_message *m)
+{
+       struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
+       struct spi_device *spi = m->spi;
+       struct spi_transfer *t = NULL;
+       int cs_active = 0;
+       int par_override = 0;
+       int status = 0;
+
+       list_for_each_entry(t, &m->transfers, transfer_list) {
+               if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
+                       status = -EINVAL;
+                       break;
+               }
+               if (par_override || t->speed_hz || t->bits_per_word) {
+                       par_override = 1;
+                       status = omap1_spi100k_setup_transfer(spi, t);
+                       if (status < 0)
                                break;
-                       }
-                       if (par_override || t->speed_hz || t->bits_per_word) {
-                               par_override = 1;
-                               status = omap1_spi100k_setup_transfer(spi, t);
-                               if (status < 0)
-                                       break;
-                               if (!t->speed_hz && !t->bits_per_word)
-                                       par_override = 0;
-                       }
+                       if (!t->speed_hz && !t->bits_per_word)
+                               par_override = 0;
+               }
 
-                       if (!cs_active) {
-                               omap1_spi100k_force_cs(spi100k, 1);
-                               cs_active = 1;
-                       }
+               if (!cs_active) {
+                       omap1_spi100k_force_cs(spi100k, 1);
+                       cs_active = 1;
+               }
 
-                       if (t->len) {
-                               unsigned count;
+               if (t->len) {
+                       unsigned count;
 
-                               count = omap1_spi100k_txrx_pio(spi, t);
-                               m->actual_length += count;
+                       count = omap1_spi100k_txrx_pio(spi, t);
+                       m->actual_length += count;
 
-                               if (count != t->len) {
-                                       status = -EIO;
-                                       break;
-                               }
+                       if (count != t->len) {
+                               status = -EIO;
+                               break;
                        }
+               }
 
-                       if (t->delay_usecs)
-                               udelay(t->delay_usecs);
+               if (t->delay_usecs)
+                       udelay(t->delay_usecs);
 
-                       /* ignore the "leave it on after last xfer" hint */
+               /* ignore the "leave it on after last xfer" hint */
 
-                       if (t->cs_change) {
-                               omap1_spi100k_force_cs(spi100k, 0);
-                               cs_active = 0;
-                       }
-               }
-
-               /* Restore defaults if they were overriden */
-               if (par_override) {
-                       par_override = 0;
-                       status = omap1_spi100k_setup_transfer(spi, NULL);
+               if (t->cs_change) {
+                       omap1_spi100k_force_cs(spi100k, 0);
+                       cs_active = 0;
                }
+       }
 
-               if (cs_active)
-                       omap1_spi100k_force_cs(spi100k, 0);
+       /* Restore defaults if they were overriden */
+       if (par_override) {
+               par_override = 0;
+               status = omap1_spi100k_setup_transfer(spi, NULL);
+       }
 
-               m->status = status;
-               m->complete(m->context);
+       if (cs_active)
+               omap1_spi100k_force_cs(spi100k, 0);
 
-               spin_lock_irq(&spi100k->lock);
-       }
+       m->status = status;
 
-       clk_disable(spi100k->ick);
-       clk_disable(spi100k->fck);
-       spin_unlock_irq(&spi100k->lock);
+       spi_finalize_current_message(master);
 
-       if (status < 0)
-               printk(KERN_WARNING "spi transfer failed with %d\n", status);
+       return status;
 }
 
-static int omap1_spi100k_transfer(struct spi_device *spi, struct spi_message *m)
+static int omap1_spi100k_unprepare_hardware(struct spi_master *master)
 {
-       struct omap1_spi100k    *spi100k;
-       unsigned long           flags;
-       struct spi_transfer     *t;
-
-       m->actual_length = 0;
-       m->status = -EINPROGRESS;
-
-       spi100k = spi_master_get_devdata(spi->master);
-
-       /* Don't accept new work if we're shutting down */
-       if (spi100k->state == SPI_SHUTDOWN)
-               return -ESHUTDOWN;
-
-       /* reject invalid messages and transfers */
-       if (list_empty(&m->transfers) || !m->complete)
-               return -EINVAL;
-
-       list_for_each_entry(t, &m->transfers, transfer_list) {
-               const void      *tx_buf = t->tx_buf;
-               void            *rx_buf = t->rx_buf;
-               unsigned        len = t->len;
-
-               if (t->speed_hz > OMAP1_SPI100K_MAX_FREQ
-                               || (len && !(rx_buf || tx_buf))) {
-                       dev_dbg(&spi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
-                                       t->speed_hz,
-                                       len,
-                                       tx_buf ? "tx" : "",
-                                       rx_buf ? "rx" : "",
-                                       t->bits_per_word);
-                       return -EINVAL;
-               }
-
-               if (t->speed_hz && t->speed_hz < OMAP1_SPI100K_MAX_FREQ/(1<<16)) {
-                       dev_dbg(&spi->dev, "%d Hz max exceeds %d\n",
-                                       t->speed_hz,
-                                       OMAP1_SPI100K_MAX_FREQ/(1<<16));
-                       return -EINVAL;
-               }
-
-       }
-
-       spin_lock_irqsave(&spi100k->lock, flags);
-       list_add_tail(&m->queue, &spi100k->msg_queue);
-       queue_work(omap1_spi100k_wq, &spi100k->work);
-       spin_unlock_irqrestore(&spi100k->lock, flags);
+       struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
 
-       return 0;
-}
+       clk_disable_unprepare(spi100k->ick);
+       clk_disable_unprepare(spi100k->fck);
 
-static int omap1_spi100k_reset(struct omap1_spi100k *spi100k)
-{
        return 0;
 }
 
@@ -496,11 +421,15 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
               master->bus_num = pdev->id;
 
        master->setup = omap1_spi100k_setup;
-       master->transfer = omap1_spi100k_transfer;
+       master->transfer_one_message = omap1_spi100k_transfer_one_message;
+       master->prepare_transfer_hardware = omap1_spi100k_prepare_hardware;
+       master->unprepare_transfer_hardware = omap1_spi100k_unprepare_hardware;
        master->cleanup = NULL;
        master->num_chipselect = 2;
        master->mode_bits = MODEBITS;
        master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
+       master->min_speed_hz = OMAP1_SPI100K_MAX_FREQ/(1<<16);
+       master->max_speed_hz = OMAP1_SPI100K_MAX_FREQ;
 
        platform_set_drvdata(pdev, master);
 
@@ -514,40 +443,29 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
         */
        spi100k->base = (void __iomem *) pdev->dev.platform_data;
 
-       INIT_WORK(&spi100k->work, omap1_spi100k_work);
-
-       spin_lock_init(&spi100k->lock);
-       INIT_LIST_HEAD(&spi100k->msg_queue);
-       spi100k->ick = clk_get(&pdev->dev, "ick");
+       spi100k->ick = devm_clk_get(&pdev->dev, "ick");
        if (IS_ERR(spi100k->ick)) {
                dev_dbg(&pdev->dev, "can't get spi100k_ick\n");
                status = PTR_ERR(spi100k->ick);
-               goto err1;
+               goto err;
        }
 
-       spi100k->fck = clk_get(&pdev->dev, "fck");
+       spi100k->fck = devm_clk_get(&pdev->dev, "fck");
        if (IS_ERR(spi100k->fck)) {
                dev_dbg(&pdev->dev, "can't get spi100k_fck\n");
                status = PTR_ERR(spi100k->fck);
-               goto err2;
+               goto err;
        }
 
-       if (omap1_spi100k_reset(spi100k) < 0)
-               goto err3;
-
        status = spi_register_master(master);
        if (status < 0)
-               goto err3;
+               goto err;
 
        spi100k->state = SPI_RUNNING;
 
        return status;
 
-err3:
-       clk_put(spi100k->fck);
-err2:
-       clk_put(spi100k->ick);
-err1:
+err:
        spi_master_put(master);
        return status;
 }
@@ -557,33 +475,14 @@ static int omap1_spi100k_remove(struct platform_device *pdev)
        struct spi_master       *master;
        struct omap1_spi100k    *spi100k;
        struct resource         *r;
-       unsigned                limit = 500;
-       unsigned long           flags;
        int                     status = 0;
 
        master = platform_get_drvdata(pdev);
        spi100k = spi_master_get_devdata(master);
 
-       spin_lock_irqsave(&spi100k->lock, flags);
-
-       spi100k->state = SPI_SHUTDOWN;
-       while (!list_empty(&spi100k->msg_queue) && limit--) {
-               spin_unlock_irqrestore(&spi100k->lock, flags);
-               msleep(10);
-               spin_lock_irqsave(&spi100k->lock, flags);
-       }
-
-       if (!list_empty(&spi100k->msg_queue))
-               status = -EBUSY;
-
-       spin_unlock_irqrestore(&spi100k->lock, flags);
-
        if (status != 0)
                return status;
 
-       clk_put(spi100k->fck);
-       clk_put(spi100k->ick);
-
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
        spi_unregister_master(master);
@@ -596,30 +495,11 @@ static struct platform_driver omap1_spi100k_driver = {
                .name           = "omap1_spi100k",
                .owner          = THIS_MODULE,
        },
+       .probe          = omap1_spi100k_probe,
        .remove         = omap1_spi100k_remove,
 };
 
-
-static int __init omap1_spi100k_init(void)
-{
-       omap1_spi100k_wq = create_singlethread_workqueue(
-                       omap1_spi100k_driver.driver.name);
-
-       if (omap1_spi100k_wq == NULL)
-               return -1;
-
-       return platform_driver_probe(&omap1_spi100k_driver, omap1_spi100k_probe);
-}
-
-static void __exit omap1_spi100k_exit(void)
-{
-       platform_driver_unregister(&omap1_spi100k_driver);
-
-       destroy_workqueue(omap1_spi100k_wq);
-}
-
-module_init(omap1_spi100k_init);
-module_exit(omap1_spi100k_exit);
+module_platform_driver(omap1_spi100k_driver);
 
 MODULE_DESCRIPTION("OMAP7xx SPI 100k controller driver");
 MODULE_AUTHOR("Fabrice Crohas <fcrohas@gmail.com>");
index 5994039758debd91acd7fa1bd238cf3e85a8b790..973c1cb42c9c67d6b1a8e1fd070602e0f05e11fb 100644 (file)
@@ -335,23 +335,6 @@ static void omap2_mcspi_restore_ctx(struct omap2_mcspi *mcspi)
                __raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0);
 }
 
-static int omap2_prepare_transfer(struct spi_master *master)
-{
-       struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
-
-       pm_runtime_get_sync(mcspi->dev);
-       return 0;
-}
-
-static int omap2_unprepare_transfer(struct spi_master *master)
-{
-       struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
-
-       pm_runtime_mark_last_busy(mcspi->dev);
-       pm_runtime_put_autosuspend(mcspi->dev);
-       return 0;
-}
-
 static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit)
 {
        unsigned long timeout;
@@ -1318,8 +1301,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
        master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
        master->setup = omap2_mcspi_setup;
-       master->prepare_transfer_hardware = omap2_prepare_transfer;
-       master->unprepare_transfer_hardware = omap2_unprepare_transfer;
+       master->auto_runtime_pm = true;
        master->transfer_one_message = omap2_mcspi_transfer_one_message;
        master->cleanup = omap2_mcspi_cleanup;
        master->dev.of_node = node;
index 5d90bebaa0fa3692da2591087f138281de5402c6..1d1d321d90c458b9e3b6afe7f61172453a25d627 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/clk.h>
+#include <linux/sizes.h>
 #include <asm/unaligned.h>
 
 #define DRIVER_NAME                    "orion_spi"
@@ -446,30 +447,22 @@ static int orion_spi_probe(struct platform_device *pdev)
        spi->min_speed = DIV_ROUND_UP(tclk_hz, 30);
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (r == NULL) {
-               status = -ENODEV;
+       spi->base = devm_ioremap_resource(&pdev->dev, r);
+       if (IS_ERR(spi->base)) {
+               status = PTR_ERR(spi->base);
                goto out_rel_clk;
        }
 
-       if (!request_mem_region(r->start, resource_size(r),
-                               dev_name(&pdev->dev))) {
-               status = -EBUSY;
-               goto out_rel_clk;
-       }
-       spi->base = ioremap(r->start, SZ_1K);
-
        if (orion_spi_reset(spi) < 0)
-               goto out_rel_mem;
+               goto out_rel_clk;
 
        master->dev.of_node = pdev->dev.of_node;
        status = spi_register_master(master);
        if (status < 0)
-               goto out_rel_mem;
+               goto out_rel_clk;
 
        return status;
 
-out_rel_mem:
-       release_mem_region(r->start, resource_size(r));
 out_rel_clk:
        clk_disable_unprepare(spi->clk);
        clk_put(spi->clk);
@@ -482,7 +475,6 @@ out:
 static int orion_spi_remove(struct platform_device *pdev)
 {
        struct spi_master *master;
-       struct resource *r;
        struct orion_spi *spi;
 
        master = platform_get_drvdata(pdev);
@@ -491,9 +483,6 @@ static int orion_spi_remove(struct platform_device *pdev)
        clk_disable_unprepare(spi->clk);
        clk_put(spi->clk);
 
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(r->start, resource_size(r));
-
        spi_unregister_master(master);
 
        return 0;
index abef061fb84af1537afde292373604be6d1e85b1..07e6db6c810fb5bcb8b2e1201ff18f74b9d4c3cc 100644 (file)
@@ -1555,18 +1555,6 @@ static int pl022_transfer_one_message(struct spi_master *master,
        return 0;
 }
 
-static int pl022_prepare_transfer_hardware(struct spi_master *master)
-{
-       struct pl022 *pl022 = spi_master_get_devdata(master);
-
-       /*
-        * Just make sure we have all we need to run the transfer by syncing
-        * with the runtime PM framework.
-        */
-       pm_runtime_get_sync(&pl022->adev->dev);
-       return 0;
-}
-
 static int pl022_unprepare_transfer_hardware(struct spi_master *master)
 {
        struct pl022 *pl022 = spi_master_get_devdata(master);
@@ -1575,13 +1563,6 @@ static int pl022_unprepare_transfer_hardware(struct spi_master *master)
        writew((readw(SSP_CR1(pl022->virtbase)) &
                (~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase));
 
-       if (pl022->master_info->autosuspend_delay > 0) {
-               pm_runtime_mark_last_busy(&pl022->adev->dev);
-               pm_runtime_put_autosuspend(&pl022->adev->dev);
-       } else {
-               pm_runtime_put(&pl022->adev->dev);
-       }
-
        return 0;
 }
 
@@ -2139,7 +2120,7 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
        master->num_chipselect = num_cs;
        master->cleanup = pl022_cleanup;
        master->setup = pl022_setup;
-       master->prepare_transfer_hardware = pl022_prepare_transfer_hardware;
+       master->auto_runtime_pm = true;
        master->transfer_one_message = pl022_transfer_one_message;
        master->unprepare_transfer_hardware = pl022_unprepare_transfer_hardware;
        master->rt = platform_info->rt;
index f440dcee852b582a2eb3369c5effd94c83fa3737..2eb06ee0b3264020d040c2b1ea8bd6745656c372 100644 (file)
@@ -69,6 +69,8 @@ MODULE_ALIAS("platform:pxa2xx-spi");
 #define LPSS_TX_HITHRESH_DFLT  224
 
 /* Offset from drv_data->lpss_base */
+#define GENERAL_REG            0x08
+#define GENERAL_REG_RXTO_HOLDOFF_DISABLE BIT(24)
 #define SSP_REG                        0x0c
 #define SPI_CS_CONTROL         0x18
 #define SPI_CS_CONTROL_SW_MODE BIT(0)
@@ -142,8 +144,13 @@ detection_done:
        __lpss_ssp_write_priv(drv_data, SPI_CS_CONTROL, value);
 
        /* Enable multiblock DMA transfers */
-       if (drv_data->master_info->enable_dma)
+       if (drv_data->master_info->enable_dma) {
                __lpss_ssp_write_priv(drv_data, SSP_REG, 1);
+
+               value = __lpss_ssp_read_priv(drv_data, GENERAL_REG);
+               value |= GENERAL_REG_RXTO_HOLDOFF_DISABLE;
+               __lpss_ssp_write_priv(drv_data, GENERAL_REG, value);
+       }
 }
 
 static void lpss_ssp_cs_control(struct driver_data *drv_data, bool enable)
@@ -804,14 +811,6 @@ static int pxa2xx_spi_transfer_one_message(struct spi_master *master,
        return 0;
 }
 
-static int pxa2xx_spi_prepare_transfer(struct spi_master *master)
-{
-       struct driver_data *drv_data = spi_master_get_devdata(master);
-
-       pm_runtime_get_sync(&drv_data->pdev->dev);
-       return 0;
-}
-
 static int pxa2xx_spi_unprepare_transfer(struct spi_master *master)
 {
        struct driver_data *drv_data = spi_master_get_devdata(master);
@@ -820,8 +819,6 @@ static int pxa2xx_spi_unprepare_transfer(struct spi_master *master)
        write_SSCR0(read_SSCR0(drv_data->ioaddr) & ~SSCR0_SSE,
                    drv_data->ioaddr);
 
-       pm_runtime_mark_last_busy(&drv_data->pdev->dev);
-       pm_runtime_put_autosuspend(&drv_data->pdev->dev);
        return 0;
 }
 
@@ -1134,8 +1131,8 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
        master->cleanup = cleanup;
        master->setup = setup;
        master->transfer_one_message = pxa2xx_spi_transfer_one_message;
-       master->prepare_transfer_hardware = pxa2xx_spi_prepare_transfer;
        master->unprepare_transfer_hardware = pxa2xx_spi_unprepare_transfer;
+       master->auto_runtime_pm = true;
 
        drv_data->ssp_type = ssp->type;
        drv_data->null_dma_buf = (u32 *)PTR_ALIGN(&drv_data[1], DMA_ALIGNMENT);
index 63e2070c6c14aa8e39a64a850248e07a38546708..62f32c4babbb3a64c783cd26644fcad4897393d0 100644 (file)
@@ -172,7 +172,6 @@ struct s3c64xx_spi_port_config {
  * @master: Pointer to the SPI Protocol master.
  * @cntrlr_info: Platform specific data for the controller this driver manages.
  * @tgl_spi: Pointer to the last CS left untoggled by the cs_change hint.
- * @queue: To log SPI xfer requests.
  * @lock: Controller specific lock.
  * @state: Set of FLAGS to indicate status.
  * @rx_dmach: Controller's DMA channel for Rx.
@@ -193,7 +192,6 @@ struct s3c64xx_spi_driver_data {
        struct spi_master               *master;
        struct s3c64xx_spi_info  *cntrlr_info;
        struct spi_device               *tgl_spi;
-       struct list_head                queue;
        spinlock_t                      lock;
        unsigned long                   sfr_start;
        struct completion               xfer_completion;
@@ -338,8 +336,10 @@ static int acquire_dma(struct s3c64xx_spi_driver_data *sdd)
        req.cap = DMA_SLAVE;
        req.client = &s3c64xx_spi_dma_client;
 
-       sdd->rx_dma.ch = (void *)sdd->ops->request(sdd->rx_dma.dmach, &req, dev, "rx");
-       sdd->tx_dma.ch = (void *)sdd->ops->request(sdd->tx_dma.dmach, &req, dev, "tx");
+       sdd->rx_dma.ch = (struct dma_chan *)(unsigned long)sdd->ops->request(
+                                       sdd->rx_dma.dmach, &req, dev, "rx");
+       sdd->tx_dma.ch = (struct dma_chan *)(unsigned long)sdd->ops->request(
+                                       sdd->tx_dma.dmach, &req, dev, "tx");
 
        return 1;
 }
@@ -356,8 +356,6 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
        while (!is_polling(sdd) && !acquire_dma(sdd))
                usleep_range(10000, 11000);
 
-       pm_runtime_get_sync(&sdd->pdev->dev);
-
        return 0;
 }
 
@@ -372,7 +370,6 @@ static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
                sdd->ops->release((enum dma_ch)sdd->tx_dma.ch,
                                        &s3c64xx_spi_dma_client);
        }
-       pm_runtime_put(&sdd->pdev->dev);
 
        return 0;
 }
@@ -442,7 +439,7 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
 
        /* Acquire DMA channels */
        sdd->rx_dma.ch = dma_request_slave_channel_compat(mask, filter,
-                               (void*)sdd->rx_dma.dmach, dev, "rx");
+                               (void *)sdd->rx_dma.dmach, dev, "rx");
        if (!sdd->rx_dma.ch) {
                dev_err(dev, "Failed to get RX DMA channel\n");
                ret = -EBUSY;
@@ -450,7 +447,7 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
        }
 
        sdd->tx_dma.ch = dma_request_slave_channel_compat(mask, filter,
-                               (void*)sdd->tx_dma.dmach, dev, "tx");
+                               (void *)sdd->tx_dma.dmach, dev, "tx");
        if (!sdd->tx_dma.ch) {
                dev_err(dev, "Failed to get TX DMA channel\n");
                ret = -EBUSY;
@@ -1056,8 +1053,6 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
        struct s3c64xx_spi_csinfo *cs = spi->controller_data;
        struct s3c64xx_spi_driver_data *sdd;
        struct s3c64xx_spi_info *sci;
-       struct spi_message *msg;
-       unsigned long flags;
        int err;
 
        sdd = spi_master_get_devdata(spi->master);
@@ -1088,21 +1083,6 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
 
        sci = sdd->cntrlr_info;
 
-       spin_lock_irqsave(&sdd->lock, flags);
-
-       list_for_each_entry(msg, &sdd->queue, queue) {
-               /* Is some mssg is already queued for this device */
-               if (msg->spi == spi) {
-                       dev_err(&spi->dev,
-                               "setup: attempt while mssg in queue!\n");
-                       spin_unlock_irqrestore(&sdd->lock, flags);
-                       err = -EBUSY;
-                       goto err_msgq;
-               }
-       }
-
-       spin_unlock_irqrestore(&sdd->lock, flags);
-
        pm_runtime_get_sync(&sdd->pdev->dev);
 
        /* Check if we can provide the requested rate */
@@ -1149,7 +1129,6 @@ setup_exit:
        /* setup() returns with device de-selected */
        disable_cs(sdd, spi);
 
-err_msgq:
        gpio_free(cs->line);
        spi_set_ctldata(spi, NULL);
 
@@ -1364,16 +1343,14 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
        if (!sdd->pdev->dev.of_node) {
                res = platform_get_resource(pdev, IORESOURCE_DMA,  0);
                if (!res) {
-                       dev_warn(&pdev->dev, "Unable to get SPI tx dma "
-                                       "resource. Switching to poll mode\n");
+                       dev_warn(&pdev->dev, "Unable to get SPI tx dma resource. Switching to poll mode\n");
                        sdd->port_conf->quirks = S3C64XX_SPI_QUIRK_POLL;
                } else
                        sdd->tx_dma.dmach = res->start;
 
                res = platform_get_resource(pdev, IORESOURCE_DMA,  1);
                if (!res) {
-                       dev_warn(&pdev->dev, "Unable to get SPI rx dma "
-                                       "resource. Switching to poll mode\n");
+                       dev_warn(&pdev->dev, "Unable to get SPI rx dma resource. Switching to poll mode\n");
                        sdd->port_conf->quirks = S3C64XX_SPI_QUIRK_POLL;
                } else
                        sdd->rx_dma.dmach = res->start;
@@ -1395,6 +1372,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
                                        SPI_BPW_MASK(8);
        /* the spi->mode bits understood by this driver: */
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+       master->auto_runtime_pm = true;
 
        sdd->regs = devm_ioremap_resource(&pdev->dev, mem_res);
        if (IS_ERR(sdd->regs)) {
@@ -1442,7 +1420,6 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
 
        spin_lock_init(&sdd->lock);
        init_completion(&sdd->xfer_completion);
-       INIT_LIST_HEAD(&sdd->queue);
 
        ret = devm_request_irq(&pdev->dev, irq, s3c64xx_spi_irq, 0,
                                "spi-s3c64xx", sdd);
@@ -1464,8 +1441,8 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
 
        dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d with %d Slaves attached\n",
                                        sdd->port_id, master->num_chipselect);
-       dev_dbg(&pdev->dev, "\tIOmem=[0x%x-0x%x]\tDMA=[Rx-%d, Tx-%d]\n",
-                                       mem_res->end, mem_res->start,
+       dev_dbg(&pdev->dev, "\tIOmem=[%pR]\tDMA=[Rx-%d, Tx-%d]\n",
+                                       mem_res,
                                        sdd->rx_dma.dmach, sdd->tx_dma.dmach);
 
        pm_runtime_enable(&pdev->dev);
index 716edf999538ac78a3c38d85d39917e83785a6e8..0b68cb592fa4d022bb6d3b3bc70296bcb224284b 100644 (file)
@@ -99,21 +99,6 @@ static int hspi_status_check_timeout(struct hspi_priv *hspi, u32 mask, u32 val)
 /*
  *             spi master function
  */
-static int hspi_prepare_transfer(struct spi_master *master)
-{
-       struct hspi_priv *hspi = spi_master_get_devdata(master);
-
-       pm_runtime_get_sync(hspi->dev);
-       return 0;
-}
-
-static int hspi_unprepare_transfer(struct spi_master *master)
-{
-       struct hspi_priv *hspi = spi_master_get_devdata(master);
-
-       pm_runtime_put_sync(hspi->dev);
-       return 0;
-}
 
 #define hspi_hw_cs_enable(hspi)                hspi_hw_cs_ctrl(hspi, 0)
 #define hspi_hw_cs_disable(hspi)       hspi_hw_cs_ctrl(hspi, 1)
@@ -316,9 +301,8 @@ static int hspi_probe(struct platform_device *pdev)
        master->setup           = hspi_setup;
        master->cleanup         = hspi_cleanup;
        master->mode_bits       = SPI_CPOL | SPI_CPHA;
-       master->prepare_transfer_hardware       = hspi_prepare_transfer;
+       master->auto_runtime_pm = true;
        master->transfer_one_message            = hspi_transfer_one_message;
-       master->unprepare_transfer_hardware     = hspi_unprepare_transfer;
        ret = spi_register_master(master);
        if (ret < 0) {
                dev_err(&pdev->dev, "spi_register_master error.\n");
@@ -327,8 +311,6 @@ static int hspi_probe(struct platform_device *pdev)
 
        pm_runtime_enable(&pdev->dev);
 
-       dev_info(&pdev->dev, "probed\n");
-
        return 0;
 
  error1:
index 2bc5a6b86300bfdd2896332832a8a1058cd28e8d..6688ce78df78ce837f94ec6608336c433f79db9e 100644 (file)
@@ -745,18 +745,6 @@ static int sh_msiof_spi_remove(struct platform_device *pdev)
        return ret;
 }
 
-static int sh_msiof_spi_runtime_nop(struct device *dev)
-{
-       /* Runtime PM callback shared between ->runtime_suspend()
-        * and ->runtime_resume(). Simply returns success.
-        *
-        * This driver re-initializes all registers after
-        * pm_runtime_get_sync() anyway so there is no need
-        * to save and restore registers here.
-        */
-       return 0;
-}
-
 #ifdef CONFIG_OF
 static const struct of_device_id sh_msiof_match[] = {
        { .compatible = "renesas,sh-msiof", },
@@ -766,18 +754,12 @@ static const struct of_device_id sh_msiof_match[] = {
 MODULE_DEVICE_TABLE(of, sh_msiof_match);
 #endif
 
-static struct dev_pm_ops sh_msiof_spi_dev_pm_ops = {
-       .runtime_suspend = sh_msiof_spi_runtime_nop,
-       .runtime_resume = sh_msiof_spi_runtime_nop,
-};
-
 static struct platform_driver sh_msiof_spi_drv = {
        .probe          = sh_msiof_spi_probe,
        .remove         = sh_msiof_spi_remove,
        .driver         = {
                .name           = "spi_sh_msiof",
                .owner          = THIS_MODULE,
-               .pm             = &sh_msiof_spi_dev_pm_ops,
                .of_match_table = of_match_ptr(sh_msiof_match),
        },
 };
index fc20bcfd90c30dd7bf90faa9eb4cd8785822b38e..96087169296e5b4af4c07a9eb9f74f78db0016ee 100644 (file)
@@ -538,6 +538,7 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
        sspi->bitbang.txrx_bufs = spi_sirfsoc_transfer;
        sspi->bitbang.master->setup = spi_sirfsoc_setup;
        master->bus_num = pdev->id;
+       master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_CS_HIGH;
        master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(12) |
                                        SPI_BPW_MASK(16) | SPI_BPW_MASK(32);
        sspi->bitbang.master->dev.of_node = pdev->dev.of_node;
index e8f542ab89351963480a44112fb3ddbc673f1076..2e208dc3709a210f61f06e0f1385626ed88c39f2 100644 (file)
@@ -816,14 +816,6 @@ static int tegra_spi_transfer_one_message(struct spi_master *master,
        msg->status = 0;
        msg->actual_length = 0;
 
-       ret = pm_runtime_get_sync(tspi->dev);
-       if (ret < 0) {
-               dev_err(tspi->dev, "runtime PM get failed: %d\n", ret);
-               msg->status = ret;
-               spi_finalize_current_message(master);
-               return ret;
-       }
-
        single_xfer = list_is_singular(&msg->transfers);
        list_for_each_entry(xfer, &msg->transfers, transfer_list) {
                INIT_COMPLETION(tspi->xfer_completion);
@@ -859,7 +851,6 @@ static int tegra_spi_transfer_one_message(struct spi_master *master,
        ret = 0;
 exit:
        tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1);
-       pm_runtime_put(tspi->dev);
        msg->status = ret;
        spi_finalize_current_message(master);
        return ret;
@@ -1053,6 +1044,7 @@ static int tegra_spi_probe(struct platform_device *pdev)
        master->transfer_one_message = tegra_spi_transfer_one_message;
        master->num_chipselect = MAX_CHIP_SELECT;
        master->bus_num = -1;
+       master->auto_runtime_pm = true;
 
        tspi->master = master;
        tspi->dev = &pdev->dev;
@@ -1068,7 +1060,6 @@ static int tegra_spi_probe(struct platform_device *pdev)
        tspi->base = devm_ioremap_resource(&pdev->dev, r);
        if (IS_ERR(tspi->base)) {
                ret = PTR_ERR(tspi->base);
-               dev_err(&pdev->dev, "ioremap failed: err = %d\n", ret);
                goto exit_free_master;
        }
 
index c1d5d95e70ea33f13402b01e2736d7df95c7c8ba..1d814dc6e0000c7743b6844db332f46a6516389c 100644 (file)
@@ -335,12 +335,6 @@ static int tegra_sflash_transfer_one_message(struct spi_master *master,
        struct spi_device *spi = msg->spi;
        int ret;
 
-       ret = pm_runtime_get_sync(tsd->dev);
-       if (ret < 0) {
-               dev_err(tsd->dev, "pm_runtime_get() failed, err = %d\n", ret);
-               return ret;
-       }
-
        msg->status = 0;
        msg->actual_length = 0;
        single_xfer = list_is_singular(&msg->transfers);
@@ -380,7 +374,6 @@ exit:
        tegra_sflash_writel(tsd, tsd->def_command_reg, SPI_COMMAND);
        msg->status = ret;
        spi_finalize_current_message(master);
-       pm_runtime_put(tsd->dev);
        return ret;
 }
 
@@ -477,6 +470,7 @@ static int tegra_sflash_probe(struct platform_device *pdev)
        master->mode_bits = SPI_CPOL | SPI_CPHA;
        master->setup = tegra_sflash_setup;
        master->transfer_one_message = tegra_sflash_transfer_one_message;
+       master->auto_runtime_pm = true;
        master->num_chipselect = MAX_CHIP_SELECT;
        master->bus_num = -1;
 
index 80490cc11ce53e72794a1546103b90df42c07fc5..c70353672a23df85234c5089c28af6a155d33a99 100644 (file)
@@ -836,11 +836,6 @@ static int tegra_slink_transfer_one_message(struct spi_master *master,
 
        msg->status = 0;
        msg->actual_length = 0;
-       ret = pm_runtime_get_sync(tspi->dev);
-       if (ret < 0) {
-               dev_err(tspi->dev, "runtime get failed: %d\n", ret);
-               goto done;
-       }
 
        single_xfer = list_is_singular(&msg->transfers);
        list_for_each_entry(xfer, &msg->transfers, transfer_list) {
@@ -878,8 +873,6 @@ static int tegra_slink_transfer_one_message(struct spi_master *master,
 exit:
        tegra_slink_writel(tspi, tspi->def_command_reg, SLINK_COMMAND);
        tegra_slink_writel(tspi, tspi->def_command2_reg, SLINK_COMMAND2);
-       pm_runtime_put(tspi->dev);
-done:
        msg->status = ret;
        spi_finalize_current_message(master);
        return ret;
@@ -1086,6 +1079,7 @@ static int tegra_slink_probe(struct platform_device *pdev)
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
        master->setup = tegra_slink_setup;
        master->transfer_one_message = tegra_slink_transfer_one_message;
+       master->auto_runtime_pm = true;
        master->num_chipselect = MAX_CHIP_SELECT;
        master->bus_num = -1;
 
index 6b0874d782ed7aa1c9cd569637500e12a1d74dd1..3e528c0396e797aba34716bb0fa8a4cde889e575 100644 (file)
@@ -52,8 +52,7 @@ static inline int tle62x0_write(struct tle62x0_state *st)
                buff[1] = gpio_state;
        }
 
-       dev_dbg(&st->us->dev, "buff %02x,%02x,%02x\n",
-               buff[0], buff[1], buff[2]);
+       dev_dbg(&st->us->dev, "buff %3ph\n", buff);
 
        return spi_write(st->us, buff, (st->nr_gpio == 16) ? 3 : 2);
 }
index e9b7681ff6ac6c65f53812d7562f9d2babc3a090..7c6d15766c72539f9561cecddfd886666218b8d6 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/module.h>
-#include <asm/gpio.h>
+#include <linux/gpio.h>
 
 
 #define SPI_FIFO_SIZE 4
index 09a9428525934e2e56732e89202680102295dd9b..0f4a093ca8d5e421dc971a192aac9aa720b2e382 100644 (file)
@@ -80,10 +80,9 @@ struct xilinx_spi {
        /* bitbang has to be first */
        struct spi_bitbang bitbang;
        struct completion done;
-       struct resource mem; /* phys mem */
        void __iomem    *regs;  /* virt. address of the control registers */
 
-       u32             irq;
+       int             irq;
 
        u8 *rx_ptr;             /* pointer in the Tx buffer */
        const u8 *tx_ptr;       /* pointer in the Rx buffer */
@@ -355,17 +354,34 @@ static const struct of_device_id xilinx_spi_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
 
-struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
-       u32 irq, s16 bus_num, int num_cs, int bits_per_word)
+static int xilinx_spi_probe(struct platform_device *pdev)
 {
-       struct spi_master *master;
        struct xilinx_spi *xspi;
-       int ret;
+       struct xspi_platform_data *pdata;
+       struct resource *res;
+       int ret, num_cs = 0, bits_per_word = 8;
+       struct spi_master *master;
        u32 tmp;
+       u8 i;
+
+       pdata = pdev->dev.platform_data;
+       if (pdata) {
+               num_cs = pdata->num_chipselect;
+               bits_per_word = pdata->bits_per_word;
+       } else {
+               of_property_read_u32(pdev->dev.of_node, "xlnx,num-ss-bits",
+                                         &num_cs);
+       }
 
-       master = spi_alloc_master(dev, sizeof(struct xilinx_spi));
+       if (!num_cs) {
+               dev_err(&pdev->dev,
+                       "Missing slave select configuration data\n");
+               return -EINVAL;
+       }
+
+       master = spi_alloc_master(&pdev->dev, sizeof(struct xilinx_spi));
        if (!master)
-               return NULL;
+               return -ENODEV;
 
        /* the spi->mode bits understood by this driver: */
        master->mode_bits = SPI_CPOL | SPI_CPHA;
@@ -378,22 +394,16 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
        xspi->bitbang.master->setup = xilinx_spi_setup;
        init_completion(&xspi->done);
 
-       if (!request_mem_region(mem->start, resource_size(mem),
-               XILINX_SPI_NAME))
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       xspi->regs = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(xspi->regs)) {
+               ret = PTR_ERR(xspi->regs);
                goto put_master;
-
-       xspi->regs = ioremap(mem->start, resource_size(mem));
-       if (xspi->regs == NULL) {
-               dev_warn(dev, "ioremap failure\n");
-               goto map_failed;
        }
 
-       master->bus_num = bus_num;
+       master->bus_num = pdev->dev.id;
        master->num_chipselect = num_cs;
-       master->dev.of_node = dev->of_node;
-
-       xspi->mem = *mem;
-       xspi->irq = irq;
+       master->dev.of_node = pdev->dev.of_node;
 
        /*
         * Detect endianess on the IP via loop bit in CR. Detection
@@ -423,113 +433,63 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
        } else if (xspi->bits_per_word == 32) {
                xspi->tx_fn = xspi_tx32;
                xspi->rx_fn = xspi_rx32;
-       } else
-               goto unmap_io;
-
+       } else {
+               ret = -EINVAL;
+               goto put_master;
+       }
 
        /* SPI controller initializations */
        xspi_init_hw(xspi);
 
+       xspi->irq = platform_get_irq(pdev, 0);
+       if (xspi->irq < 0) {
+               ret = xspi->irq;
+               goto put_master;
+       }
+
        /* Register for SPI Interrupt */
-       ret = request_irq(xspi->irq, xilinx_spi_irq, 0, XILINX_SPI_NAME, xspi);
+       ret = devm_request_irq(&pdev->dev, xspi->irq, xilinx_spi_irq, 0,
+                              dev_name(&pdev->dev), xspi);
        if (ret)
-               goto unmap_io;
+               goto put_master;
 
        ret = spi_bitbang_start(&xspi->bitbang);
        if (ret) {
-               dev_err(dev, "spi_bitbang_start FAILED\n");
-               goto free_irq;
-       }
-
-       dev_info(dev, "at 0x%08llX mapped to 0x%p, irq=%d\n",
-               (unsigned long long)mem->start, xspi->regs, xspi->irq);
-       return master;
-
-free_irq:
-       free_irq(xspi->irq, xspi);
-unmap_io:
-       iounmap(xspi->regs);
-map_failed:
-       release_mem_region(mem->start, resource_size(mem));
-put_master:
-       spi_master_put(master);
-       return NULL;
-}
-EXPORT_SYMBOL(xilinx_spi_init);
-
-void xilinx_spi_deinit(struct spi_master *master)
-{
-       struct xilinx_spi *xspi;
-
-       xspi = spi_master_get_devdata(master);
-
-       spi_bitbang_stop(&xspi->bitbang);
-       free_irq(xspi->irq, xspi);
-       iounmap(xspi->regs);
-
-       release_mem_region(xspi->mem.start, resource_size(&xspi->mem));
-       spi_master_put(xspi->bitbang.master);
-}
-EXPORT_SYMBOL(xilinx_spi_deinit);
-
-static int xilinx_spi_probe(struct platform_device *dev)
-{
-       struct xspi_platform_data *pdata;
-       struct resource *r;
-       int irq, num_cs = 0, bits_per_word = 8;
-       struct spi_master *master;
-       u8 i;
-
-       pdata = dev->dev.platform_data;
-       if (pdata) {
-               num_cs = pdata->num_chipselect;
-               bits_per_word = pdata->bits_per_word;
-       }
-
-#ifdef CONFIG_OF
-       if (dev->dev.of_node) {
-               const __be32 *prop;
-               int len;
-
-               /* number of slave select bits is required */
-               prop = of_get_property(dev->dev.of_node, "xlnx,num-ss-bits",
-                                      &len);
-               if (prop && len >= sizeof(*prop))
-                       num_cs = __be32_to_cpup(prop);
-       }
-#endif
-
-       if (!num_cs) {
-               dev_err(&dev->dev, "Missing slave select configuration data\n");
-               return -EINVAL;
+               dev_err(&pdev->dev, "spi_bitbang_start FAILED\n");
+               goto put_master;
        }
 
-
-       r = platform_get_resource(dev, IORESOURCE_MEM, 0);
-       if (!r)
-               return -ENODEV;
-
-       irq = platform_get_irq(dev, 0);
-       if (irq < 0)
-               return -ENXIO;
-
-       master = xilinx_spi_init(&dev->dev, r, irq, dev->id, num_cs,
-                                bits_per_word);
-       if (!master)
-               return -ENODEV;
+       dev_info(&pdev->dev, "at 0x%08llX mapped to 0x%p, irq=%d\n",
+               (unsigned long long)res->start, xspi->regs, xspi->irq);
 
        if (pdata) {
                for (i = 0; i < pdata->num_devices; i++)
                        spi_new_device(master, pdata->devices + i);
        }
 
-       platform_set_drvdata(dev, master);
+       platform_set_drvdata(pdev, master);
        return 0;
+
+put_master:
+       spi_master_put(master);
+
+       return ret;
 }
 
-static int xilinx_spi_remove(struct platform_device *dev)
+static int xilinx_spi_remove(struct platform_device *pdev)
 {
-       xilinx_spi_deinit(platform_get_drvdata(dev));
+       struct spi_master *master = platform_get_drvdata(pdev);
+       struct xilinx_spi *xspi = spi_master_get_devdata(master);
+       void __iomem *regs_base = xspi->regs;
+
+       spi_bitbang_stop(&xspi->bitbang);
+
+       /* Disable all the interrupts just in case */
+       xspi->write_fn(0, regs_base + XIPIF_V123B_IIER_OFFSET);
+       /* Disable the global IPIF interrupt */
+       xspi->write_fn(0, regs_base + XIPIF_V123B_DGIER_OFFSET);
+
+       spi_master_put(xspi->bitbang.master);
 
        return 0;
 }
index 978dda2c523982f62c676573feb1955da0ca82da..61f71b95bfa111b83360990b9d851f6ae99c43af 100644 (file)
@@ -553,6 +553,10 @@ static void spi_pump_messages(struct kthread_work *work)
                    master->unprepare_transfer_hardware(master))
                        dev_err(&master->dev,
                                "failed to unprepare transfer hardware\n");
+               if (master->auto_runtime_pm) {
+                       pm_runtime_mark_last_busy(master->dev.parent);
+                       pm_runtime_put_autosuspend(master->dev.parent);
+               }
                return;
        }
 
@@ -572,11 +576,23 @@ static void spi_pump_messages(struct kthread_work *work)
                master->busy = true;
        spin_unlock_irqrestore(&master->queue_lock, flags);
 
+       if (!was_busy && master->auto_runtime_pm) {
+               ret = pm_runtime_get_sync(master->dev.parent);
+               if (ret < 0) {
+                       dev_err(&master->dev, "Failed to power device: %d\n",
+                               ret);
+                       return;
+               }
+       }
+
        if (!was_busy && master->prepare_transfer_hardware) {
                ret = master->prepare_transfer_hardware(master);
                if (ret) {
                        dev_err(&master->dev,
                                "failed to prepare transfer hardware\n");
+
+                       if (master->auto_runtime_pm)
+                               pm_runtime_put(master->dev.parent);
                        return;
                }
        }
@@ -1351,6 +1367,11 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message)
        struct spi_master *master = spi->master;
        struct spi_transfer *xfer;
 
+       if (list_empty(&message->transfers))
+               return -EINVAL;
+       if (!message->complete)
+               return -EINVAL;
+
        /* Half-duplex links include original MicroWire, and ones with
         * only one data pin like SPI_3WIRE (switches direction) or where
         * either MOSI or MISO is missing.  They can also be caused by
@@ -1375,6 +1396,7 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message)
         * it is not set for this transfer.
         */
        list_for_each_entry(xfer, &message->transfers, transfer_list) {
+               message->frame_length += xfer->len;
                if (!xfer->bits_per_word)
                        xfer->bits_per_word = spi->bits_per_word;
                if (!xfer->speed_hz)
@@ -1387,6 +1409,13 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message)
                                        BIT(xfer->bits_per_word - 1)))
                                return -EINVAL;
                }
+
+               if (xfer->speed_hz && master->min_speed_hz &&
+                   xfer->speed_hz < master->min_speed_hz)
+                       return -EINVAL;
+               if (xfer->speed_hz && master->max_speed_hz &&
+                   xfer->speed_hz > master->max_speed_hz)
+                       return -EINVAL;
        }
 
        message->spi = spi;
index dcceed29d31ae415818d1fceecc6518cbc017845..81972fa47bebab17ad635a4d855d5cd691f5daad 100644 (file)
@@ -1811,10 +1811,12 @@ static int zcache_comp_init(void)
 #else
        if (*zcache_comp_name != '\0') {
                ret = crypto_has_comp(zcache_comp_name, 0, 0);
-               if (!ret)
+               if (!ret) {
                        pr_info("zcache: %s not supported\n",
                                        zcache_comp_name);
-               goto out;
+                       ret = 1;
+                       goto out;
+               }
        }
        if (!ret)
                strcpy(zcache_comp_name, "lzo");
index bb91b4713ebdb8c7ba8849cba643d046c5bc9973..2e3ea1a70d7b90768f33f26a39f098eed7df2c12 100644 (file)
@@ -31,9 +31,8 @@ static int __init serial_init_chip(struct parisc_device *dev)
        int err;
 
 #ifdef CONFIG_64BIT
-       extern int iosapic_serial_irq(int cellnum);
        if (!dev->irq && (dev->id.sversion == 0xad))
-               dev->irq = iosapic_serial_irq(dev->mod_index-1);
+               dev->irq = iosapic_serial_irq(dev);
 #endif
 
        if (!dev->irq) {
index cbf1d155b7b2a8c80ef782443edbf77c0e7f5595..22f280aa4f2c521b5829a6ea5e72b8c05f2265d9 100644 (file)
@@ -773,6 +773,6 @@ module_init(arc_serial_init);
 module_exit(arc_serial_exit);
 
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("plat-arcfpga/uart");
+MODULE_ALIAS("platform:" DRIVER_NAME);
 MODULE_AUTHOR("Vineet Gupta");
 MODULE_DESCRIPTION("ARC(Synopsys) On-Chip(fpga) serial driver");
index 4f5f161896a139852e46f93f30239be979838bda..f85b8e6d0346fc472fbc835b0451a706ce46aab3 100644 (file)
@@ -678,11 +678,18 @@ static void mxs_auart_settermios(struct uart_port *u,
 
 static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
 {
-       u32 istatus, istat;
+       u32 istat;
        struct mxs_auart_port *s = context;
        u32 stat = readl(s->port.membase + AUART_STAT);
 
-       istatus = istat = readl(s->port.membase + AUART_INTR);
+       istat = readl(s->port.membase + AUART_INTR);
+
+       /* ack irq */
+       writel(istat & (AUART_INTR_RTIS
+               | AUART_INTR_TXIS
+               | AUART_INTR_RXIS
+               | AUART_INTR_CTSMIS),
+                       s->port.membase + AUART_INTR_CLR);
 
        if (istat & AUART_INTR_CTSMIS) {
                uart_handle_cts_change(&s->port, stat & AUART_STAT_CTS);
@@ -702,12 +709,6 @@ static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
                istat &= ~AUART_INTR_TXIS;
        }
 
-       writel(istatus & (AUART_INTR_RTIS
-               | AUART_INTR_TXIS
-               | AUART_INTR_RXIS
-               | AUART_INTR_CTSMIS),
-                       s->port.membase + AUART_INTR_CLR);
-
        return IRQ_HANDLED;
 }
 
@@ -850,7 +851,7 @@ auart_console_write(struct console *co, const char *str, unsigned int count)
        struct mxs_auart_port *s;
        struct uart_port *port;
        unsigned int old_ctrl0, old_ctrl2;
-       unsigned int to = 1000;
+       unsigned int to = 20000;
 
        if (co->index >= MXS_AUART_PORTS || co->index < 0)
                return;
@@ -871,18 +872,23 @@ auart_console_write(struct console *co, const char *str, unsigned int count)
 
        uart_console_write(port, str, count, mxs_auart_console_putchar);
 
-       /*
-        * Finally, wait for transmitter to become empty
-        * and restore the TCR
-        */
+       /* Finally, wait for transmitter to become empty ... */
        while (readl(port->membase + AUART_STAT) & AUART_STAT_BUSY) {
+               udelay(1);
                if (!to--)
                        break;
-               udelay(1);
        }
 
-       writel(old_ctrl0, port->membase + AUART_CTRL0);
-       writel(old_ctrl2, port->membase + AUART_CTRL2);
+       /*
+        * ... and restore the TCR if we waited long enough for the transmitter
+        * to be idle. This might keep the transmitter enabled although it is
+        * unused, but that is better than to disable it while it is still
+        * transmitting.
+        */
+       if (!(readl(port->membase + AUART_STAT) & AUART_STAT_BUSY)) {
+               writel(old_ctrl0, port->membase + AUART_CTRL0);
+               writel(old_ctrl2, port->membase + AUART_CTRL2);
+       }
 
        clk_disable(s->clk);
 }
index 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 4cf1e1dd562169e52426577534333e5669508c24..46544d069d7c50365b0e0b1d3410825e0656a888 100644 (file)
@@ -996,6 +996,8 @@ config FB_ATMEL
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
+       select FB_MODE_HELPERS
+       select VIDEOMODE_HELPERS
        help
          This enables support for the AT91/AT32 LCD Controller.
 
index effdb373b8db0ffd55d4f56523c8c379f50e4cbc..ece49d53145a575cebd058c0a0259c7f57614d9f 100644 (file)
 #include <linux/gfp.h>
 #include <linux/module.h>
 #include <linux/platform_data/atmel.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <video/of_display_timing.h>
+#include <video/videomode.h>
 
 #include <mach/cpu.h>
 #include <asm/gpio.h>
 
 #include <video/atmel_lcdc.h>
 
+struct atmel_lcdfb_config {
+       bool have_alt_pixclock;
+       bool have_hozval;
+       bool have_intensity_bit;
+};
+
+ /* LCD Controller info data structure, stored in device platform_data */
+struct atmel_lcdfb_info {
+       spinlock_t              lock;
+       struct fb_info          *info;
+       void __iomem            *mmio;
+       int                     irq_base;
+       struct work_struct      task;
+
+       unsigned int            smem_len;
+       struct platform_device  *pdev;
+       struct clk              *bus_clk;
+       struct clk              *lcdc_clk;
+
+       struct backlight_device *backlight;
+       u8                      bl_power;
+       u8                      saved_lcdcon;
+
+       u32                     pseudo_palette[16];
+       bool                    have_intensity_bit;
+
+       struct atmel_lcdfb_pdata pdata;
+
+       struct atmel_lcdfb_config *config;
+};
+
+struct atmel_lcdfb_power_ctrl_gpio {
+       int gpio;
+       int active_low;
+
+       struct list_head list;
+};
+
 #define lcdc_readl(sinfo, reg)         __raw_readl((sinfo)->mmio+(reg))
 #define lcdc_writel(sinfo, reg, val)   __raw_writel((val), (sinfo)->mmio+(reg))
 
 #define ATMEL_LCDC_DMA_BURST_LEN       8       /* words */
 #define ATMEL_LCDC_FIFO_SIZE           512     /* words */
 
-struct atmel_lcdfb_config {
-       bool have_alt_pixclock;
-       bool have_hozval;
-       bool have_intensity_bit;
-};
-
 static struct atmel_lcdfb_config at91sam9261_config = {
        .have_hozval            = true,
        .have_intensity_bit     = true,
@@ -248,18 +285,27 @@ static void exit_backlight(struct atmel_lcdfb_info *sinfo)
 
 static void init_contrast(struct atmel_lcdfb_info *sinfo)
 {
+       struct atmel_lcdfb_pdata *pdata = &sinfo->pdata;
+
        /* contrast pwm can be 'inverted' */
-       if (sinfo->lcdcon_pol_negative)
+       if (pdata->lcdcon_pol_negative)
                        contrast_ctr &= ~(ATMEL_LCDC_POL_POSITIVE);
 
        /* have some default contrast/backlight settings */
        lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
        lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
 
-       if (sinfo->lcdcon_is_backlight)
+       if (pdata->lcdcon_is_backlight)
                init_backlight(sinfo);
 }
 
+static inline void atmel_lcdfb_power_control(struct atmel_lcdfb_info *sinfo, int on)
+{
+       struct atmel_lcdfb_pdata *pdata = &sinfo->pdata;
+
+       if (pdata->atmel_lcdfb_power_control)
+               pdata->atmel_lcdfb_power_control(pdata, on);
+}
 
 static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = {
        .type           = FB_TYPE_PACKED_PIXELS,
@@ -299,9 +345,11 @@ static unsigned long compute_hozval(struct atmel_lcdfb_info *sinfo,
 
 static void atmel_lcdfb_stop_nowait(struct atmel_lcdfb_info *sinfo)
 {
+       struct atmel_lcdfb_pdata *pdata = &sinfo->pdata;
+
        /* Turn off the LCD controller and the DMA controller */
        lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
-                       sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
+                       pdata->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
 
        /* Wait for the LCDC core to become idle */
        while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY)
@@ -321,9 +369,11 @@ static void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo)
 
 static void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo)
 {
-       lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
+       struct atmel_lcdfb_pdata *pdata = &sinfo->pdata;
+
+       lcdc_writel(sinfo, ATMEL_LCDC_DMACON, pdata->default_dmacon);
        lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
-               (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET)
+               (pdata->guard_time << ATMEL_LCDC_GUARDT_OFFSET)
                | ATMEL_LCDC_PWR);
 }
 
@@ -424,6 +474,7 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
 {
        struct device *dev = info->device;
        struct atmel_lcdfb_info *sinfo = info->par;
+       struct atmel_lcdfb_pdata *pdata = &sinfo->pdata;
        unsigned long clk_value_khz;
 
        clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
@@ -510,7 +561,7 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
                else
                        var->green.length = 6;
 
-               if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) {
+               if (pdata->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) {
                        /* RGB:5X5 mode */
                        var->red.offset = var->green.length + 5;
                        var->blue.offset = 0;
@@ -527,7 +578,7 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
                var->transp.length = 8;
                /* fall through */
        case 24:
-               if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) {
+               if (pdata->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) {
                        /* RGB:888 mode */
                        var->red.offset = 16;
                        var->blue.offset = 0;
@@ -576,6 +627,7 @@ static void atmel_lcdfb_reset(struct atmel_lcdfb_info *sinfo)
 static int atmel_lcdfb_set_par(struct fb_info *info)
 {
        struct atmel_lcdfb_info *sinfo = info->par;
+       struct atmel_lcdfb_pdata *pdata = &sinfo->pdata;
        unsigned long hozval_linesz;
        unsigned long value;
        unsigned long clk_value_khz;
@@ -637,7 +689,7 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
 
 
        /* Initialize control register 2 */
-       value = sinfo->default_lcdcon2;
+       value = pdata->default_lcdcon2;
 
        if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
                value |= ATMEL_LCDC_INVLINE_INVERTED;
@@ -741,6 +793,7 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
                             unsigned int transp, struct fb_info *info)
 {
        struct atmel_lcdfb_info *sinfo = info->par;
+       struct atmel_lcdfb_pdata *pdata = &sinfo->pdata;
        unsigned int val;
        u32 *pal;
        int ret = 1;
@@ -777,8 +830,7 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
                                 */
                        } else {
                                /* new style BGR:565 / RGB:565 */
-                               if (sinfo->lcd_wiring_mode ==
-                                   ATMEL_LCDC_WIRING_RGB) {
+                               if (pdata->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) {
                                        val  = ((blue >> 11) & 0x001f);
                                        val |= ((red  >>  0) & 0xf800);
                                } else {
@@ -912,16 +964,187 @@ static void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo)
        clk_disable(sinfo->lcdc_clk);
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id atmel_lcdfb_dt_ids[] = {
+       { .compatible = "atmel,at91sam9261-lcdc" , .data = &at91sam9261_config, },
+       { .compatible = "atmel,at91sam9263-lcdc" , .data = &at91sam9263_config, },
+       { .compatible = "atmel,at91sam9g10-lcdc" , .data = &at91sam9g10_config, },
+       { .compatible = "atmel,at91sam9g45-lcdc" , .data = &at91sam9g45_config, },
+       { .compatible = "atmel,at91sam9g45es-lcdc" , .data = &at91sam9g45es_config, },
+       { .compatible = "atmel,at91sam9rl-lcdc" , .data = &at91sam9rl_config, },
+       { .compatible = "atmel,at32ap-lcdc" , .data = &at32ap_config, },
+       { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, atmel_lcdfb_dt_ids);
+
+static const char *atmel_lcdfb_wiring_modes[] = {
+       [ATMEL_LCDC_WIRING_BGR] = "BRG",
+       [ATMEL_LCDC_WIRING_RGB] = "RGB",
+};
+
+const int atmel_lcdfb_get_of_wiring_modes(struct device_node *np)
+{
+       const char *mode;
+       int err, i;
+
+       err = of_property_read_string(np, "atmel,lcd-wiring-mode", &mode);
+       if (err < 0)
+               return ATMEL_LCDC_WIRING_BGR;
+
+       for (i = 0; i < ARRAY_SIZE(atmel_lcdfb_wiring_modes); i++)
+               if (!strcasecmp(mode, atmel_lcdfb_wiring_modes[i]))
+                       return i;
+
+       return -ENODEV;
+}
+
+static void atmel_lcdfb_power_control_gpio(struct atmel_lcdfb_pdata *pdata, int on)
+{
+       struct atmel_lcdfb_power_ctrl_gpio *og;
+
+       list_for_each_entry(og, &pdata->pwr_gpios, list)
+               gpio_set_value(og->gpio, on);
+}
+
+static int atmel_lcdfb_of_init(struct atmel_lcdfb_info *sinfo)
+{
+       struct fb_info *info = sinfo->info;
+       struct atmel_lcdfb_pdata *pdata = &sinfo->pdata;
+       struct fb_var_screeninfo *var = &info->var;
+       struct device *dev = &sinfo->pdev->dev;
+       struct device_node *np =dev->of_node;
+       struct device_node *display_np;
+       struct device_node *timings_np;
+       struct display_timings *timings;
+       enum of_gpio_flags flags;
+       struct atmel_lcdfb_power_ctrl_gpio *og;
+       bool is_gpio_power = false;
+       int ret = -ENOENT;
+       int i, gpio;
+
+       sinfo->config = (struct atmel_lcdfb_config*)
+               of_match_device(atmel_lcdfb_dt_ids, dev)->data;
+
+       display_np = of_parse_phandle(np, "display", 0);
+       if (!display_np) {
+               dev_err(dev, "failed to find display phandle\n");
+               return -ENOENT;
+       }
+
+       ret = of_property_read_u32(display_np, "bits-per-pixel", &var->bits_per_pixel);
+       if (ret < 0) {
+               dev_err(dev, "failed to get property bits-per-pixel\n");
+               goto put_display_node;
+       }
+
+       ret = of_property_read_u32(display_np, "atmel,guard-time", &pdata->guard_time);
+       if (ret < 0) {
+               dev_err(dev, "failed to get property atmel,guard-time\n");
+               goto put_display_node;
+       }
+
+       ret = of_property_read_u32(display_np, "atmel,lcdcon2", &pdata->default_lcdcon2);
+       if (ret < 0) {
+               dev_err(dev, "failed to get property atmel,lcdcon2\n");
+               goto put_display_node;
+       }
+
+       ret = of_property_read_u32(display_np, "atmel,dmacon", &pdata->default_dmacon);
+       if (ret < 0) {
+               dev_err(dev, "failed to get property bits-per-pixel\n");
+               goto put_display_node;
+       }
+
+       ret = -ENOMEM;
+       for (i = 0; i < of_gpio_named_count(display_np, "atmel,power-control-gpio"); i++) {
+               gpio = of_get_named_gpio_flags(display_np, "atmel,power-control-gpio",
+                                              i, &flags);
+               if (gpio < 0)
+                       continue;
+
+               og = devm_kzalloc(dev, sizeof(*og), GFP_KERNEL);
+               if (!og)
+                       goto put_display_node;
+
+               og->gpio = gpio;
+               og->active_low = flags & OF_GPIO_ACTIVE_LOW;
+               is_gpio_power = true;
+               ret = devm_gpio_request(dev, gpio, "lcd-power-control-gpio");
+               if (ret) {
+                       dev_err(dev, "request gpio %d failed\n", gpio);
+                       goto put_display_node;
+               }
+
+               ret = gpio_direction_output(gpio, og->active_low);
+               if (ret) {
+                       dev_err(dev, "set direction output gpio %d failed\n", gpio);
+                       goto put_display_node;
+               }
+       }
+
+       if (is_gpio_power)
+               pdata->atmel_lcdfb_power_control = atmel_lcdfb_power_control_gpio;
+
+       ret = atmel_lcdfb_get_of_wiring_modes(display_np);
+       if (ret < 0) {
+               dev_err(dev, "invalid atmel,lcd-wiring-mode\n");
+               goto put_display_node;
+       }
+       pdata->lcd_wiring_mode = ret;
+
+       pdata->lcdcon_is_backlight = of_property_read_bool(display_np, "atmel,lcdcon-backlight");
+
+       timings = of_get_display_timings(display_np);
+       if (!timings) {
+               dev_err(dev, "failed to get display timings\n");
+               goto put_display_node;
+       }
+
+       timings_np = of_find_node_by_name(display_np, "display-timings");
+       if (!timings_np) {
+               dev_err(dev, "failed to find display-timings node\n");
+               goto put_display_node;
+       }
+
+       for (i = 0; i < of_get_child_count(timings_np); i++) {
+               struct videomode vm;
+               struct fb_videomode fb_vm;
+
+               ret = videomode_from_timings(timings, &vm, i);
+               if (ret < 0)
+                       goto put_timings_node;
+               ret = fb_videomode_from_videomode(&vm, &fb_vm);
+               if (ret < 0)
+                       goto put_timings_node;
+
+               fb_add_videomode(&fb_vm, &info->modelist);
+       }
+
+       return 0;
+
+put_timings_node:
+       of_node_put(timings_np);
+put_display_node:
+       of_node_put(display_np);
+       return ret;
+}
+#else
+static int atmel_lcdfb_of_init(struct atmel_lcdfb_info *sinfo)
+{
+       return 0;
+}
+#endif
 
 static int __init atmel_lcdfb_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct fb_info *info;
        struct atmel_lcdfb_info *sinfo;
-       struct atmel_lcdfb_info *pdata_sinfo;
-       struct fb_videomode fbmode;
+       struct atmel_lcdfb_pdata *pdata = NULL;
        struct resource *regs = NULL;
        struct resource *map = NULL;
+       struct fb_modelist *modelist;
        int ret;
 
        dev_dbg(dev, "%s BEGIN\n", __func__);
@@ -934,26 +1157,35 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
        }
 
        sinfo = info->par;
+       sinfo->pdev = pdev;
+       sinfo->info = info;
 
-       if (dev->platform_data) {
-               pdata_sinfo = (struct atmel_lcdfb_info *)dev->platform_data;
-               sinfo->default_bpp = pdata_sinfo->default_bpp;
-               sinfo->default_dmacon = pdata_sinfo->default_dmacon;
-               sinfo->default_lcdcon2 = pdata_sinfo->default_lcdcon2;
-               sinfo->default_monspecs = pdata_sinfo->default_monspecs;
-               sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control;
-               sinfo->guard_time = pdata_sinfo->guard_time;
-               sinfo->smem_len = pdata_sinfo->smem_len;
-               sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight;
-               sinfo->lcdcon_pol_negative = pdata_sinfo->lcdcon_pol_negative;
-               sinfo->lcd_wiring_mode = pdata_sinfo->lcd_wiring_mode;
+       INIT_LIST_HEAD(&info->modelist);
+
+       if (pdev->dev.of_node) {
+               ret = atmel_lcdfb_of_init(sinfo);
+               if (ret)
+                       goto free_info;
+       } else if (dev->platform_data) {
+               struct fb_monspecs *monspecs;
+               int i;
+
+               pdata = dev->platform_data;
+               monspecs = pdata->default_monspecs;
+               sinfo->pdata = *pdata;
+
+               for (i = 0; i < monspecs->modedb_len; i++)
+                       fb_add_videomode(&monspecs->modedb[i], &info->modelist);
+
+               sinfo->config = atmel_lcdfb_get_config(pdev);
+
+               info->var.bits_per_pixel = pdata->default_bpp ? pdata->default_bpp : 16;
+               memcpy(&info->monspecs, pdata->default_monspecs, sizeof(info->monspecs));
        } else {
                dev_err(dev, "cannot get default configuration\n");
                goto free_info;
        }
-       sinfo->info = info;
-       sinfo->pdev = pdev;
-       sinfo->config = atmel_lcdfb_get_config(pdev);
+
        if (!sinfo->config)
                goto free_info;
 
@@ -962,7 +1194,6 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
        info->pseudo_palette = sinfo->pseudo_palette;
        info->fbops = &atmel_lcdfb_ops;
 
-       memcpy(&info->monspecs, sinfo->default_monspecs, sizeof(info->monspecs));
        info->fix = atmel_lcdfb_fix;
 
        /* Enable LCDC Clocks */
@@ -978,14 +1209,11 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
        }
        atmel_lcdfb_start_clock(sinfo);
 
-       ret = fb_find_mode(&info->var, info, NULL, info->monspecs.modedb,
-                       info->monspecs.modedb_len, info->monspecs.modedb,
-                       sinfo->default_bpp);
-       if (!ret) {
-               dev_err(dev, "no suitable video mode found\n");
-               goto stop_clk;
-       }
+       modelist = list_first_entry(&info->modelist,
+                       struct fb_modelist, list);
+       fb_videomode_to_var(&info->var, &modelist->mode);
 
+       atmel_lcdfb_check_var(&info->var, info);
 
        regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!regs) {
@@ -1069,18 +1297,6 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
                goto unregister_irqs;
        }
 
-       /*
-        * This makes sure that our colour bitfield
-        * descriptors are correctly initialised.
-        */
-       atmel_lcdfb_check_var(&info->var, info);
-
-       ret = fb_set_var(info, &info->var);
-       if (ret) {
-               dev_warn(dev, "unable to set display parameters\n");
-               goto free_cmap;
-       }
-
        dev_set_drvdata(dev, info);
 
        /*
@@ -1092,13 +1308,8 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
                goto reset_drvdata;
        }
 
-       /* add selected videomode to modelist */
-       fb_var_to_videomode(&fbmode, &info->var);
-       fb_add_videomode(&fbmode, &info->modelist);
-
        /* Power up the LCDC screen */
-       if (sinfo->atmel_lcdfb_power_control)
-               sinfo->atmel_lcdfb_power_control(1);
+       atmel_lcdfb_power_control(sinfo, 1);
 
        dev_info(dev, "fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %d\n",
                       info->node, info->fix.mmio_start, sinfo->mmio, sinfo->irq_base);
@@ -1107,7 +1318,6 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
 
 reset_drvdata:
        dev_set_drvdata(dev, NULL);
-free_cmap:
        fb_dealloc_cmap(&info->cmap);
 unregister_irqs:
        cancel_work_sync(&sinfo->task);
@@ -1143,15 +1353,16 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct fb_info *info = dev_get_drvdata(dev);
        struct atmel_lcdfb_info *sinfo;
+       struct atmel_lcdfb_pdata *pdata;
 
        if (!info || !info->par)
                return 0;
        sinfo = info->par;
+       pdata = &sinfo->pdata;
 
        cancel_work_sync(&sinfo->task);
        exit_backlight(sinfo);
-       if (sinfo->atmel_lcdfb_power_control)
-               sinfo->atmel_lcdfb_power_control(0);
+       atmel_lcdfb_power_control(sinfo, 0);
        unregister_framebuffer(info);
        atmel_lcdfb_stop_clock(sinfo);
        clk_put(sinfo->lcdc_clk);
@@ -1188,9 +1399,7 @@ static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg)
 
        sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_CTR);
        lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0);
-       if (sinfo->atmel_lcdfb_power_control)
-               sinfo->atmel_lcdfb_power_control(0);
-
+       atmel_lcdfb_power_control(sinfo, 0);
        atmel_lcdfb_stop(sinfo);
        atmel_lcdfb_stop_clock(sinfo);
 
@@ -1204,8 +1413,7 @@ static int atmel_lcdfb_resume(struct platform_device *pdev)
 
        atmel_lcdfb_start_clock(sinfo);
        atmel_lcdfb_start(sinfo);
-       if (sinfo->atmel_lcdfb_power_control)
-               sinfo->atmel_lcdfb_power_control(1);
+       atmel_lcdfb_power_control(sinfo, 1);
        lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, sinfo->saved_lcdcon);
 
        /* Enable FIFO & DMA errors */
@@ -1228,6 +1436,7 @@ static struct platform_driver atmel_lcdfb_driver = {
        .driver         = {
                .name   = "atmel_lcdfb",
                .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(atmel_lcdfb_dt_ids),
        },
 };
 
index eabd0ee1c2bc2f298d0938515e204b42430e9852..14fe79d8634abfe2307d53e65e151f403c86bcad 100644 (file)
@@ -1,9 +1,8 @@
-ifneq ($(CONFIG_ARM),y)
-obj-y  += manage.o
+ifeq ($(filter y, $(CONFIG_ARM) $(CONFIG_ARM64)),)
 obj-$(CONFIG_HOTPLUG_CPU)              += cpu_hotplug.o
 endif
 obj-$(CONFIG_X86)                      += fallback.o
-obj-y  += grant-table.o features.o events.o balloon.o
+obj-y  += grant-table.o features.o events.o balloon.o manage.o
 obj-y  += xenbus/
 
 nostackp := $(call cc-option, -fno-stack-protector)
index 8feecf01d55c95c9241080cf36823f197b3b2d5c..b6165e047f48083c5a254dc66a6f4bc3e6e9ddb9 100644 (file)
@@ -379,18 +379,12 @@ static long evtchn_ioctl(struct file *file,
                if (unbind.port >= NR_EVENT_CHANNELS)
                        break;
 
-               spin_lock_irq(&port_user_lock);
-
                rc = -ENOTCONN;
-               if (get_port_user(unbind.port) != u) {
-                       spin_unlock_irq(&port_user_lock);
+               if (get_port_user(unbind.port) != u)
                        break;
-               }
 
                disable_irq(irq_from_evtchn(unbind.port));
 
-               spin_unlock_irq(&port_user_lock);
-
                evtchn_unbind_from_user(u, unbind.port);
 
                rc = 0;
@@ -490,26 +484,15 @@ static int evtchn_release(struct inode *inode, struct file *filp)
        int i;
        struct per_user_data *u = filp->private_data;
 
-       spin_lock_irq(&port_user_lock);
-
-       free_page((unsigned long)u->ring);
-
        for (i = 0; i < NR_EVENT_CHANNELS; i++) {
                if (get_port_user(i) != u)
                        continue;
 
                disable_irq(irq_from_evtchn(i));
-       }
-
-       spin_unlock_irq(&port_user_lock);
-
-       for (i = 0; i < NR_EVENT_CHANNELS; i++) {
-               if (get_port_user(i) != u)
-                       continue;
-
                evtchn_unbind_from_user(get_port_user(i), i);
        }
 
+       free_page((unsigned long)u->ring);
        kfree(u->name);
        kfree(u);
 
index 6ed8a9df4472edc36b91b70ca3a0f463f237108d..34b20bfa4e8c3cf813194a45c4545e01c1d88eb1 100644 (file)
@@ -115,7 +115,6 @@ static int xenbus_frontend_dev_resume(struct device *dev)
                        return -EFAULT;
                }
 
-               INIT_WORK(&xdev->work, xenbus_frontend_delayed_resume);
                queue_work(xenbus_frontend_wq, &xdev->work);
 
                return 0;
@@ -124,6 +123,16 @@ static int xenbus_frontend_dev_resume(struct device *dev)
        return xenbus_dev_resume(dev);
 }
 
+static int xenbus_frontend_dev_probe(struct device *dev)
+{
+       if (xen_store_domain_type == XS_LOCAL) {
+               struct xenbus_device *xdev = to_xenbus_device(dev);
+               INIT_WORK(&xdev->work, xenbus_frontend_delayed_resume);
+       }
+
+       return xenbus_dev_probe(dev);
+}
+
 static const struct dev_pm_ops xenbus_pm_ops = {
        .suspend        = xenbus_dev_suspend,
        .resume         = xenbus_frontend_dev_resume,
@@ -142,7 +151,7 @@ static struct xen_bus_type xenbus_frontend = {
                .name           = "xen",
                .match          = xenbus_match,
                .uevent         = xenbus_uevent_frontend,
-               .probe          = xenbus_dev_probe,
+               .probe          = xenbus_frontend_dev_probe,
                .remove         = xenbus_dev_remove,
                .shutdown       = xenbus_dev_shutdown,
                .dev_attrs      = xenbus_dev_attrs,
@@ -474,7 +483,11 @@ static int __init xenbus_probe_frontend_init(void)
 
        register_xenstore_notifier(&xenstore_notifier);
 
-       xenbus_frontend_wq = create_workqueue("xenbus_frontend");
+       if (xen_store_domain_type == XS_LOCAL) {
+               xenbus_frontend_wq = create_workqueue("xenbus_frontend");
+               if (!xenbus_frontend_wq)
+                       pr_warn("create xenbus frontend workqueue failed, S3 resume is likely to fail\n");
+       }
 
        return 0;
 }
index 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..bb84d7c7a1929f0b1da1026fefd70fe129339114 100644 (file)
@@ -421,7 +421,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 >= MAX_DOMAINNAME_SIZE)
                                break;
                        if (!ses->domainName) {
                                ses->domainName =
index 1fdc370410576e1a3f5a36a133245468160ae4b4..64bb4c5917c24eceb8d523ba1599a971c7bad450 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 MAX_DOMAINNAME_SIZE 256        /* maximum fully qualified domain name (FQDN) */
 #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..3f9dcf7f2662433af215992ad49e15aa9798ce34 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, MAX_DOMAINNAME_SIZE)
+                                       == MAX_DOMAINNAME_SIZE) {
                                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:") + MAX_DOMAINNAME_SIZE + 1 */
+#define CIFSCREDS_DESC_SIZE (7 + MAX_DOMAINNAME_SIZE + 1)
 
 /* Populate username and pw fields from keyring if possible */
 static int
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..57b153782eb4917041d643ca5833b199cbd54353 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);
+                                           MAX_DOMAINNAME_SIZE, 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, MAX_DOMAINNAME_SIZE);
+               bcc_ptr += strnlen(ses->domainName, MAX_DOMAINNAME_SIZE);
        } /* 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 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 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 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 e5c7f15465b49c2b744fe4fca30e107fa1d1ddae..19f134e896a9a8bdd69a387015819e4ebc3c2705 100644 (file)
@@ -32,7 +32,7 @@ enum ocfs2_xattr_type {
 
 struct ocfs2_security_xattr_info {
        int enable;
-       char *name;
+       const char *name;
        void *value;
        size_t value_len;
 };
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..a2c2fbbe7ce0eb6a4069765ca08804e323110c93 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,8 +366,6 @@ 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
  */
@@ -383,15 +391,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);
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 4d06edb56d5fbb74480d0ffc4b24297870f8149e..b87d05e17d466179dd9c48b6a56c852012c24f16 100644 (file)
@@ -138,10 +138,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 +152,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 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 cff544f81105ecf83dac7cc0e75ea8ee26954592..d30209b9cef81773b26e62f79b67de402e56ff68 100644 (file)
@@ -60,7 +60,6 @@ Mellon the rights to redistribute these changes without encumbrance.
 
 #if defined(__linux__)
 typedef unsigned long long u_quad_t;
-#else
 #endif
 #include <uapi/linux/coda.h>
 #endif 
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 0e5f5785d9f2df3c524099142da6202b54f0ff47..98ffcbd4888ea0d088f2d4e8c4b41757b0e472c2 100644 (file)
@@ -63,7 +63,7 @@ struct debug_obj_descr {
 extern void debug_object_init      (void *addr, struct debug_obj_descr *descr);
 extern void
 debug_object_init_on_stack(void *addr, struct debug_obj_descr *descr);
-extern void debug_object_activate  (void *addr, struct debug_obj_descr *descr);
+extern int debug_object_activate  (void *addr, struct debug_obj_descr *descr);
 extern void debug_object_deactivate(void *addr, struct debug_obj_descr *descr);
 extern void debug_object_destroy   (void *addr, struct debug_obj_descr *descr);
 extern void debug_object_free      (void *addr, struct debug_obj_descr *descr);
@@ -85,8 +85,8 @@ static inline void
 debug_object_init      (void *addr, struct debug_obj_descr *descr) { }
 static inline void
 debug_object_init_on_stack(void *addr, struct debug_obj_descr *descr) { }
-static inline void
-debug_object_activate  (void *addr, struct debug_obj_descr *descr) { }
+static inline int
+debug_object_activate  (void *addr, struct debug_obj_descr *descr) { return 0; }
 static inline void
 debug_object_deactivate(void *addr, struct debug_obj_descr *descr) { }
 static inline void
index 01b5c84be8284fef2f721e26c1b3fb3d95a72bbf..00141d3325fe2dbe0f0c649f3580d9ec473b7f0c 100644 (file)
@@ -57,7 +57,7 @@ struct cma;
 struct page;
 struct device;
 
-#ifdef CONFIG_CMA
+#ifdef CONFIG_DMA_CMA
 
 /*
  * There is always at least global CMA area and a few optional device
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..acccdf4eb48598240064e00011594cd54a5254a8 100644 (file)
@@ -744,6 +744,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);
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 debf208b7611ea004537ae284b8436eccd9e7aa2..31c0cd1c941a6c122506cc3158be203391617460 100644 (file)
@@ -69,7 +69,7 @@ typedef union ktime ktime_t;          /* Kill this */
  * @secs:      seconds to set
  * @nsecs:     nanoseconds to set
  *
- * Return the ktime_t representation of the value
+ * Return: The ktime_t representation of the value.
  */
 static inline ktime_t ktime_set(const long secs, const unsigned long nsecs)
 {
@@ -151,7 +151,7 @@ static inline ktime_t ktime_set(const long secs, const unsigned long nsecs)
  * @lhs:       minuend
  * @rhs:       subtrahend
  *
- * Returns the remainder of the subtraction
+ * Return: The remainder of the subtraction.
  */
 static inline ktime_t ktime_sub(const ktime_t lhs, const ktime_t rhs)
 {
@@ -169,7 +169,7 @@ static inline ktime_t ktime_sub(const ktime_t lhs, const ktime_t rhs)
  * @add1:      addend1
  * @add2:      addend2
  *
- * Returns the sum of @add1 and @add2.
+ * Return: The sum of @add1 and @add2.
  */
 static inline ktime_t ktime_add(const ktime_t add1, const ktime_t add2)
 {
@@ -195,7 +195,7 @@ static inline ktime_t ktime_add(const ktime_t add1, const ktime_t add2)
  * @kt:                addend
  * @nsec:      the scalar nsec value to add
  *
- * Returns the sum of @kt and @nsec in ktime_t format
+ * Return: The sum of @kt and @nsec in ktime_t format.
  */
 extern ktime_t ktime_add_ns(const ktime_t kt, u64 nsec);
 
@@ -204,7 +204,7 @@ extern ktime_t ktime_add_ns(const ktime_t kt, u64 nsec);
  * @kt:                minuend
  * @nsec:      the scalar nsec value to subtract
  *
- * Returns the subtraction of @nsec from @kt in ktime_t format
+ * Return: The subtraction of @nsec from @kt in ktime_t format.
  */
 extern ktime_t ktime_sub_ns(const ktime_t kt, u64 nsec);
 
@@ -212,7 +212,7 @@ extern ktime_t ktime_sub_ns(const ktime_t kt, u64 nsec);
  * timespec_to_ktime - convert a timespec to ktime_t format
  * @ts:                the timespec variable to convert
  *
- * Returns a ktime_t variable with the converted timespec value
+ * Return: A ktime_t variable with the converted timespec value.
  */
 static inline ktime_t timespec_to_ktime(const struct timespec ts)
 {
@@ -224,7 +224,7 @@ static inline ktime_t timespec_to_ktime(const struct timespec ts)
  * timeval_to_ktime - convert a timeval to ktime_t format
  * @tv:                the timeval variable to convert
  *
- * Returns a ktime_t variable with the converted timeval value
+ * Return: A ktime_t variable with the converted timeval value.
  */
 static inline ktime_t timeval_to_ktime(const struct timeval tv)
 {
@@ -237,7 +237,7 @@ static inline ktime_t timeval_to_ktime(const struct timeval tv)
  * ktime_to_timespec - convert a ktime_t variable to timespec format
  * @kt:                the ktime_t variable to convert
  *
- * Returns the timespec representation of the ktime value
+ * Return: The timespec representation of the ktime value.
  */
 static inline struct timespec ktime_to_timespec(const ktime_t kt)
 {
@@ -249,7 +249,7 @@ static inline struct timespec ktime_to_timespec(const ktime_t kt)
  * ktime_to_timeval - convert a ktime_t variable to timeval format
  * @kt:                the ktime_t variable to convert
  *
- * Returns the timeval representation of the ktime value
+ * Return: The timeval representation of the ktime value.
  */
 static inline struct timeval ktime_to_timeval(const ktime_t kt)
 {
@@ -262,7 +262,7 @@ static inline struct timeval ktime_to_timeval(const ktime_t kt)
  * ktime_to_ns - convert a ktime_t variable to scalar nanoseconds
  * @kt:                the ktime_t variable to convert
  *
- * Returns the scalar nanoseconds representation of @kt
+ * Return: The scalar nanoseconds representation of @kt.
  */
 static inline s64 ktime_to_ns(const ktime_t kt)
 {
@@ -276,7 +276,9 @@ static inline s64 ktime_to_ns(const ktime_t kt)
  * @cmp1:      comparable1
  * @cmp2:      comparable2
  *
- * Compare two ktime_t variables, returns 1 if equal
+ * Compare two ktime_t variables.
+ *
+ * Return: 1 if equal.
  */
 static inline int ktime_equal(const ktime_t cmp1, const ktime_t cmp2)
 {
@@ -288,7 +290,7 @@ static inline int ktime_equal(const ktime_t cmp1, const ktime_t cmp2)
  * @cmp1:      comparable1
  * @cmp2:      comparable2
  *
- * Returns ...
+ * Return: ...
  *   cmp1  < cmp2: return <0
  *   cmp1 == cmp2: return 0
  *   cmp1  > cmp2: return >0
@@ -342,7 +344,7 @@ extern ktime_t ktime_add_safe(const ktime_t lhs, const ktime_t rhs);
  * @kt:                the ktime_t variable to convert
  * @ts:                the timespec variable to store the result in
  *
- * Returns true if there was a successful conversion, false if kt was 0.
+ * Return: %true if there was a successful conversion, %false if kt was 0.
  */
 static inline __must_check bool ktime_to_timespec_cond(const ktime_t kt,
                                                       struct timespec *ts)
index a63d83ebd151918b84fa6bb6ddc594e4dcd0c907..ca645a01d37a79767baccfd12a8871b79af7b624 100644 (file)
@@ -85,6 +85,12 @@ static inline bool is_noslot_pfn(pfn_t pfn)
        return pfn == KVM_PFN_NOSLOT;
 }
 
+/*
+ * architectures with KVM_HVA_ERR_BAD other than PAGE_OFFSET (e.g. s390)
+ * provide own defines and kvm_is_error_hva
+ */
+#ifndef KVM_HVA_ERR_BAD
+
 #define KVM_HVA_ERR_BAD                (PAGE_OFFSET)
 #define KVM_HVA_ERR_RO_BAD     (PAGE_OFFSET + PAGE_SIZE)
 
@@ -93,6 +99,8 @@ static inline bool kvm_is_error_hva(unsigned long addr)
        return addr >= PAGE_OFFSET;
 }
 
+#endif
+
 #define KVM_ERR_PTR_BAD_PAGE   (ERR_PTR(-ENOENT))
 
 static inline bool is_error_page(struct page *page)
@@ -160,8 +168,12 @@ enum kvm_bus {
 
 int kvm_io_bus_write(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
                     int len, const void *val);
+int kvm_io_bus_write_cookie(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
+                           int len, const void *val, long cookie);
 int kvm_io_bus_read(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr, int len,
                    void *val);
+int kvm_io_bus_read_cookie(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
+                          int len, void *val, long cookie);
 int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
                            int len, struct kvm_io_device *dev);
 int kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx,
@@ -499,6 +511,7 @@ int __kvm_set_memory_region(struct kvm *kvm,
 void kvm_arch_free_memslot(struct kvm_memory_slot *free,
                           struct kvm_memory_slot *dont);
 int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages);
+void kvm_arch_memslots_updated(struct kvm *kvm);
 int kvm_arch_prepare_memory_region(struct kvm *kvm,
                                struct kvm_memory_slot *memslot,
                                struct kvm_userspace_memory_region *mem,
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)
 {
index f1e877b79ed8c1f078db76daa94c207172abba22..cfc2f119779ab6a202082b42ba58d0fb6290f676 100644 (file)
@@ -365,7 +365,7 @@ extern void lockdep_trace_alloc(gfp_t mask);
 
 #define lockdep_recursing(tsk) ((tsk)->lockdep_recursion)
 
-#else /* !LOCKDEP */
+#else /* !CONFIG_LOCKDEP */
 
 static inline void lockdep_off(void)
 {
@@ -479,82 +479,36 @@ static inline void print_irqtrace_events(struct task_struct *curr)
  * on the per lock-class debug mode:
  */
 
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-# ifdef CONFIG_PROVE_LOCKING
-#  define spin_acquire(l, s, t, i)             lock_acquire(l, s, t, 0, 2, NULL, i)
-#  define spin_acquire_nest(l, s, t, n, i)     lock_acquire(l, s, t, 0, 2, n, i)
-# else
-#  define spin_acquire(l, s, t, i)             lock_acquire(l, s, t, 0, 1, NULL, i)
-#  define spin_acquire_nest(l, s, t, n, i)     lock_acquire(l, s, t, 0, 1, NULL, i)
-# endif
-# define spin_release(l, n, i)                 lock_release(l, n, i)
+#ifdef CONFIG_PROVE_LOCKING
+ #define lock_acquire_exclusive(l, s, t, n, i)         lock_acquire(l, s, t, 0, 2, n, i)
+ #define lock_acquire_shared(l, s, t, n, i)            lock_acquire(l, s, t, 1, 2, n, i)
+ #define lock_acquire_shared_recursive(l, s, t, n, i)  lock_acquire(l, s, t, 2, 2, n, i)
 #else
-# define spin_acquire(l, s, t, i)              do { } while (0)
-# define spin_release(l, n, i)                 do { } while (0)
+ #define lock_acquire_exclusive(l, s, t, n, i)         lock_acquire(l, s, t, 0, 1, n, i)
+ #define lock_acquire_shared(l, s, t, n, i)            lock_acquire(l, s, t, 1, 1, n, i)
+ #define lock_acquire_shared_recursive(l, s, t, n, i)  lock_acquire(l, s, t, 2, 1, n, i)
 #endif
 
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-# ifdef CONFIG_PROVE_LOCKING
-#  define rwlock_acquire(l, s, t, i)           lock_acquire(l, s, t, 0, 2, NULL, i)
-#  define rwlock_acquire_read(l, s, t, i)      lock_acquire(l, s, t, 2, 2, NULL, i)
-# else
-#  define rwlock_acquire(l, s, t, i)           lock_acquire(l, s, t, 0, 1, NULL, i)
-#  define rwlock_acquire_read(l, s, t, i)      lock_acquire(l, s, t, 2, 1, NULL, i)
-# endif
-# define rwlock_release(l, n, i)               lock_release(l, n, i)
-#else
-# define rwlock_acquire(l, s, t, i)            do { } while (0)
-# define rwlock_acquire_read(l, s, t, i)       do { } while (0)
-# define rwlock_release(l, n, i)               do { } while (0)
-#endif
+#define spin_acquire(l, s, t, i)               lock_acquire_exclusive(l, s, t, NULL, i)
+#define spin_acquire_nest(l, s, t, n, i)       lock_acquire_exclusive(l, s, t, n, i)
+#define spin_release(l, n, i)                  lock_release(l, n, i)
 
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-# ifdef CONFIG_PROVE_LOCKING
-#  define mutex_acquire(l, s, t, i)            lock_acquire(l, s, t, 0, 2, NULL, i)
-#  define mutex_acquire_nest(l, s, t, n, i)    lock_acquire(l, s, t, 0, 2, n, i)
-# else
-#  define mutex_acquire(l, s, t, i)            lock_acquire(l, s, t, 0, 1, NULL, i)
-#  define mutex_acquire_nest(l, s, t, n, i)    lock_acquire(l, s, t, 0, 1, n, i)
-# endif
-# define mutex_release(l, n, i)                        lock_release(l, n, i)
-#else
-# define mutex_acquire(l, s, t, i)             do { } while (0)
-# define mutex_acquire_nest(l, s, t, n, i)     do { } while (0)
-# define mutex_release(l, n, i)                        do { } while (0)
-#endif
+#define rwlock_acquire(l, s, t, i)             lock_acquire_exclusive(l, s, t, NULL, i)
+#define rwlock_acquire_read(l, s, t, i)                lock_acquire_shared_recursive(l, s, t, NULL, i)
+#define rwlock_release(l, n, i)                        lock_release(l, n, i)
 
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-# ifdef CONFIG_PROVE_LOCKING
-#  define rwsem_acquire(l, s, t, i)            lock_acquire(l, s, t, 0, 2, NULL, i)
-#  define rwsem_acquire_nest(l, s, t, n, i)    lock_acquire(l, s, t, 0, 2, n, i)
-#  define rwsem_acquire_read(l, s, t, i)       lock_acquire(l, s, t, 1, 2, NULL, i)
-# else
-#  define rwsem_acquire(l, s, t, i)            lock_acquire(l, s, t, 0, 1, NULL, i)
-#  define rwsem_acquire_nest(l, s, t, n, i)    lock_acquire(l, s, t, 0, 1, n, i)
-#  define rwsem_acquire_read(l, s, t, i)       lock_acquire(l, s, t, 1, 1, NULL, i)
-# endif
+#define mutex_acquire(l, s, t, i)              lock_acquire_exclusive(l, s, t, NULL, i)
+#define mutex_acquire_nest(l, s, t, n, i)      lock_acquire_exclusive(l, s, t, n, i)
+#define mutex_release(l, n, i)                 lock_release(l, n, i)
+
+#define rwsem_acquire(l, s, t, i)              lock_acquire_exclusive(l, s, t, NULL, i)
+#define rwsem_acquire_nest(l, s, t, n, i)      lock_acquire_exclusive(l, s, t, n, i)
+#define rwsem_acquire_read(l, s, t, i)         lock_acquire_shared(l, s, t, NULL, i)
 # define rwsem_release(l, n, i)                        lock_release(l, n, i)
-#else
-# define rwsem_acquire(l, s, t, i)             do { } while (0)
-# define rwsem_acquire_nest(l, s, t, n, i)     do { } while (0)
-# define rwsem_acquire_read(l, s, t, i)                do { } while (0)
-# define rwsem_release(l, n, i)                        do { } while (0)
-#endif
 
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-# ifdef CONFIG_PROVE_LOCKING
-#  define lock_map_acquire(l)          lock_acquire(l, 0, 0, 0, 2, NULL, _THIS_IP_)
-#  define lock_map_acquire_read(l)     lock_acquire(l, 0, 0, 2, 2, NULL, _THIS_IP_)
-# else
-#  define lock_map_acquire(l)          lock_acquire(l, 0, 0, 0, 1, NULL, _THIS_IP_)
-#  define lock_map_acquire_read(l)     lock_acquire(l, 0, 0, 2, 1, NULL, _THIS_IP_)
-# endif
+#define lock_map_acquire(l)                    lock_acquire_exclusive(l, 0, 0, NULL, _THIS_IP_)
+#define lock_map_acquire_read(l)               lock_acquire_shared_recursive(l, 0, 0, NULL, _THIS_IP_)
 # define lock_map_release(l)                   lock_release(l, 1, _THIS_IP_)
-#else
-# define lock_map_acquire(l)                   do { } while (0)
-# define lock_map_acquire_read(l)              do { } while (0)
-# define lock_map_release(l)                   do { } while (0)
-#endif
 
 #ifdef CONFIG_PROVE_LOCKING
 # define might_lock(lock)                                              \
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 4e94dc65f987f2b9185ac18b4be67c3ffbb53f58..d0d52ea6007439c18c3cf17bb71961187da72026 100644 (file)
@@ -191,6 +191,17 @@ enum s2mps11_regulators {
 #define S2MPS11_BUCK_N_VOLTAGES (S2MPS11_BUCK_VSEL_MASK + 1)
 #define S2MPS11_RAMP_DELAY     25000           /* uV/us */
 
+
+#define S2MPS11_BUCK2_RAMP_SHIFT       6
+#define S2MPS11_BUCK34_RAMP_SHIFT      4
+#define S2MPS11_BUCK5_RAMP_SHIFT       6
+#define S2MPS11_BUCK16_RAMP_SHIFT      4
+#define S2MPS11_BUCK7810_RAMP_SHIFT    2
+#define S2MPS11_BUCK9_RAMP_SHIFT       0
+#define S2MPS11_BUCK2_RAMP_EN_SHIFT    3
+#define S2MPS11_BUCK3_RAMP_EN_SHIFT    2
+#define S2MPS11_BUCK4_RAMP_EN_SHIFT    1
+#define S2MPS11_BUCK6_RAMP_EN_SHIFT    0
 #define S2MPS11_PMIC_EN_SHIFT  6
 #define S2MPS11_REGULATOR_MAX (S2MPS11_REG_MAX - 3)
 
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 f0224608d15ed9f226e52dd89f30971c5da2bb56..d2d59b4149d06536d552d402cc872186f6f5ac74 100644 (file)
@@ -1798,6 +1798,7 @@ enum mf_flags {
        MF_COUNT_INCREASED = 1 << 0,
        MF_ACTION_REQUIRED = 1 << 1,
        MF_MUST_KILL = 1 << 2,
+       MF_SOFT_OFFLINE = 1 << 3,
 };
 extern int memory_failure(unsigned long pfn, int trapno, int flags);
 extern void memory_failure_queue(unsigned long pfn, int trapno, int flags);
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 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..3ca60b070ef0647c8d8f5871ba1b7a15825973da 100644 (file)
@@ -1633,6 +1633,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 +1666,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)        \
index 4e2cbfa640b7241d0ddf803a68010e20b5991115..58b9a02c38d29b118d98d7bbd22ac82dde9ec342 100644 (file)
 typedef struct { DECLARE_BITMAP(bits, MAX_NUMNODES); } nodemask_t;
 extern nodemask_t _unused_nodemask_arg_;
 
+/*
+ * The inline keyword gives the compiler room to decide to inline, or
+ * not inline a function as it sees best.  However, as these functions
+ * are called in both __init and non-__init functions, if they are not
+ * inlined we will end up with a section mis-match error (of the type of
+ * freeable items not being freed).  So we must use __always_inline here
+ * to fix the problem.  If other functions in the future also end up in
+ * this situation they will also need to be annotated as __always_inline
+ */
 #define node_set(node, dst) __node_set((node), &(dst))
-static inline void __node_set(int node, volatile nodemask_t *dstp)
+static __always_inline void __node_set(int node, volatile nodemask_t *dstp)
 {
        set_bit(node, dstp->bits);
 }
index 1fd08ca23106df836678989d96e2a16824b1a932..90a8811e9e480285fe417e6c4e4b6c9c4425166a 100644 (file)
@@ -323,12 +323,6 @@ extern int of_detach_node(struct device_node *);
  */
 const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur,
                               u32 *pu);
-#define of_property_for_each_u32(np, propname, prop, p, u)     \
-       for (prop = of_find_property(np, propname, NULL),       \
-               p = of_prop_next_u32(prop, NULL, &u);           \
-               p;                                              \
-               p = of_prop_next_u32(prop, p, &u))
-
 /*
  * struct property *prop;
  * const char *s;
@@ -337,11 +331,6 @@ const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur,
  *         printk("String value: %s\n", s);
  */
 const char *of_prop_next_string(struct property *prop, const char *cur);
-#define of_property_for_each_string(np, propname, prop, s)     \
-       for (prop = of_find_property(np, propname, NULL),       \
-               s = of_prop_next_string(prop, NULL);            \
-               s;                                              \
-               s = of_prop_next_string(prop, s))
 
 #else /* CONFIG_OF */
 
@@ -505,12 +494,20 @@ static inline int of_machine_is_compatible(const char *compat)
        return 0;
 }
 
+static inline const __be32 *of_prop_next_u32(struct property *prop,
+               const __be32 *cur, u32 *pu)
+{
+       return NULL;
+}
+
+static inline const char *of_prop_next_string(struct property *prop,
+               const char *cur)
+{
+       return NULL;
+}
+
 #define of_match_ptr(_ptr)     NULL
 #define of_match_node(_matches, _node) NULL
-#define of_property_for_each_u32(np, propname, prop, p, u) \
-       while (0)
-#define of_property_for_each_string(np, propname, prop, s) \
-       while (0)
 #endif /* CONFIG_OF */
 
 #ifndef of_node_to_nid
@@ -559,6 +556,18 @@ static inline int of_property_read_u32(const struct device_node *np,
        return of_property_read_u32_array(np, propname, out_value, 1);
 }
 
+#define of_property_for_each_u32(np, propname, prop, p, u)     \
+       for (prop = of_find_property(np, propname, NULL),       \
+               p = of_prop_next_u32(prop, NULL, &u);           \
+               p;                                              \
+               p = of_prop_next_u32(prop, p, &u))
+
+#define of_property_for_each_string(np, propname, prop, s)     \
+       for (prop = of_find_property(np, propname, NULL),       \
+               s = of_prop_next_string(prop, NULL);            \
+               s;                                              \
+               s = of_prop_next_string(prop, s))
+
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_PROC_DEVICETREE)
 extern void proc_device_tree_add_node(struct device_node *, struct proc_dir_entry *);
 extern void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop);
index ed136ad698ce622e4d150d7fda337a99c78d5a4e..4a17939b95cc100ff09e63135aa4543ad3f3e72a 100644 (file)
@@ -106,8 +106,7 @@ extern u64 dt_mem_next_cell(int s, __be32 **cellp);
  * physical addresses.
  */
 #ifdef CONFIG_BLK_DEV_INITRD
-extern void early_init_dt_setup_initrd_arch(unsigned long start,
-                                           unsigned long end);
+extern void early_init_dt_setup_initrd_arch(u64 start, u64 end);
 #endif
 
 /* Early flat tree scan hooks */
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 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
 
index 202e290faea877effcc153f0a8bc21e35f2cb697..51a2ff579d60d1763ddd465ac5bf4457272bfb19 100644 (file)
@@ -36,6 +36,13 @@ struct lp55xx_predef_pattern {
        u8 size_b;
 };
 
+enum lp8501_pwr_sel {
+       LP8501_ALL_VDD,         /* D1~9 are connected to VDD */
+       LP8501_6VDD_3VOUT,      /* D1~6 with VDD, D7~9 with VOUT */
+       LP8501_3VDD_6VOUT,      /* D1~6 with VOUT, D7~9 with VDD */
+       LP8501_ALL_VOUT,        /* D1~9 are connected to VOUT */
+};
+
 /*
  * struct lp55xx_platform_data
  * @led_config        : Configurable led class device
@@ -67,6 +74,9 @@ struct lp55xx_platform_data {
        /* Predefined pattern data */
        struct lp55xx_predef_pattern *patterns;
        unsigned int num_patterns;
+
+       /* LP8501 specific */
+       enum lp8501_pwr_sel pwr_sel;
 };
 
 #endif /* _LEDS_LP55XX_H */
index c5bf29b6fa7f8c1eddafb23508bb6030509dd7ae..3c1037a81d34e18650628752a709dea3efd122eb 100644 (file)
@@ -27,9 +27,15 @@ enum pca9633_outdrv {
        PCA9633_TOTEM_POLE, /* aka push-pull */
 };
 
+enum pca9633_blink_type {
+       PCA9633_SW_BLINK,
+       PCA9633_HW_BLINK,
+};
+
 struct pca9633_platform_data {
        struct led_platform_data leds;
        enum pca9633_outdrv outdrv;
+       enum pca9633_blink_type blink_type;
 };
 
 #endif /* __LINUX_PCA9633_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 4b14bdc911d7854163932672ad376ab615de7be4..1aa8d8ceb44bb2772058d9378fc6307d5826d919 100644 (file)
@@ -229,13 +229,9 @@ extern void rcu_irq_exit(void);
 #ifdef CONFIG_RCU_USER_QS
 extern void rcu_user_enter(void);
 extern void rcu_user_exit(void);
-extern void rcu_user_enter_after_irq(void);
-extern void rcu_user_exit_after_irq(void);
 #else
 static inline void rcu_user_enter(void) { }
 static inline void rcu_user_exit(void) { }
-static inline void rcu_user_enter_after_irq(void) { }
-static inline void rcu_user_exit_after_irq(void) { }
 static inline void rcu_user_hooks_switch(struct task_struct *prev,
                                         struct task_struct *next) { }
 #endif /* CONFIG_RCU_USER_QS */
@@ -1015,4 +1011,22 @@ static inline bool rcu_is_nocb_cpu(int cpu) { return false; }
 #endif /* #else #ifdef CONFIG_RCU_NOCB_CPU */
 
 
+/* Only for use by adaptive-ticks code. */
+#ifdef CONFIG_NO_HZ_FULL_SYSIDLE
+extern bool rcu_sys_is_idle(void);
+extern void rcu_sysidle_force_exit(void);
+#else /* #ifdef CONFIG_NO_HZ_FULL_SYSIDLE */
+
+static inline bool rcu_sys_is_idle(void)
+{
+       return false;
+}
+
+static inline void rcu_sysidle_force_exit(void)
+{
+}
+
+#endif /* #else #ifdef CONFIG_NO_HZ_FULL_SYSIDLE */
+
+
 #endif /* __LINUX_RCUPDATE_H */
index 75981d0b57dccd4b6a3b5e9833557973f33d9404..a3c68aad2381c9af4b3d9c0a025db133bf09484e 100644 (file)
@@ -470,6 +470,9 @@ struct regmap_irq {
  * @ack_base:    Base ack address.  If zero then the chip is clear on read.
  * @wake_base:   Base address for wake enables.  If zero unsupported.
  * @irq_reg_stride:  Stride to use for chips where registers are not contiguous.
+ * @init_ack_masked: Ack all masked interrupts once during initalization.
+ * @mask_invert: Inverted mask register: cleared bits are masked out.
+ * @wake_invert: Inverted wake register: cleared bits are wake enabled.
  * @runtime_pm:  Hold a runtime PM lock on the device when accessing it.
  *
  * @num_regs:    Number of registers in each control bank.
@@ -485,9 +488,10 @@ struct regmap_irq_chip {
        unsigned int ack_base;
        unsigned int wake_base;
        unsigned int irq_reg_stride;
-       unsigned int mask_invert;
-       unsigned int wake_invert;
-       bool runtime_pm;
+       bool init_ack_masked:1;
+       bool mask_invert:1;
+       bool wake_invert:1;
+       bool runtime_pm:1;
 
        int num_regs;
 
index 3a76389c6aaa6989900247712c8ffe33658b33db..3610df8dd229fae5ef7a82aaa48ca0b976bf4d68 100644 (file)
@@ -369,8 +369,11 @@ static inline int regulator_count_voltages(struct regulator *regulator)
 static inline int regulator_set_voltage_tol(struct regulator *regulator,
                                            int new_uV, int tol_uV)
 {
-       return regulator_set_voltage(regulator,
-                                    new_uV - tol_uV, new_uV + tol_uV);
+       if (regulator_set_voltage(regulator, new_uV, new_uV + tol_uV) == 0)
+               return 0;
+       else
+               return regulator_set_voltage(regulator,
+                                            new_uV - tol_uV, new_uV + tol_uV);
 }
 
 static inline int regulator_is_supported_voltage_tol(struct regulator *regulator,
index 6700cc94bdd12275df1b8be822939c298b811aff..67e13aa5a4781d2c8fdfa8fc902d2bbc90f2a3a0 100644 (file)
@@ -39,6 +39,24 @@ enum regulator_status {
        REGULATOR_STATUS_UNDEFINED,
 };
 
+/**
+ * Specify a range of voltages for regulator_map_linar_range() and
+ * regulator_list_linear_range().
+ *
+ * @min_uV:  Lowest voltage in range
+ * @max_uV:  Highest voltage in range
+ * @min_sel: Lowest selector for range
+ * @max_sel: Highest selector for range
+ * @uV_step: Step size
+ */
+struct regulator_linear_range {
+       unsigned int min_uV;
+       unsigned int max_uV;
+       unsigned int min_sel;
+       unsigned int max_sel;
+       unsigned int uV_step;
+};
+
 /**
  * struct regulator_ops - regulator operations.
  *
@@ -223,6 +241,9 @@ struct regulator_desc {
        unsigned int linear_min_sel;
        unsigned int ramp_delay;
 
+       const struct regulator_linear_range *linear_ranges;
+       int n_linear_ranges;
+
        const unsigned int *volt_table;
 
        unsigned int vsel_reg;
@@ -326,10 +347,14 @@ int regulator_mode_to_status(unsigned int);
 
 int regulator_list_voltage_linear(struct regulator_dev *rdev,
                                  unsigned int selector);
+int regulator_list_voltage_linear_range(struct regulator_dev *rdev,
+                                       unsigned int selector);
 int regulator_list_voltage_table(struct regulator_dev *rdev,
                                  unsigned int selector);
 int regulator_map_voltage_linear(struct regulator_dev *rdev,
                                  int min_uV, int max_uV);
+int regulator_map_voltage_linear_range(struct regulator_dev *rdev,
+                                      int min_uV, int max_uV);
 int regulator_map_voltage_iterate(struct regulator_dev *rdev,
                                  int min_uV, int max_uV);
 int regulator_map_voltage_ascend(struct regulator_dev *rdev,
index 36adbc82de6ae6c58c3a224f62e5d385ce7a35ba..999b20ce06cf349185f008388e12e64c70518196 100644 (file)
@@ -134,6 +134,7 @@ struct regulation_constraints {
        unsigned always_on:1;   /* regulator never off when system is on */
        unsigned boot_on:1;     /* bootloader/firmware enabled regulator */
        unsigned apply_uV:1;    /* apply uV constraint if min == max */
+       unsigned ramp_disable:1; /* disable ramp delay */
 };
 
 /**
diff --git a/include/linux/regulator/pfuze100.h b/include/linux/regulator/pfuze100.h
new file mode 100644 (file)
index 0000000..65d550b
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. 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; 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 __LINUX_REG_PFUZE100_H
+#define __LINUX_REG_PFUZE100_H
+
+#define PFUZE100_SW1AB         0
+#define PFUZE100_SW1C          1
+#define PFUZE100_SW2           2
+#define PFUZE100_SW3A          3
+#define PFUZE100_SW3B          4
+#define PFUZE100_SW4           5
+#define PFUZE100_SWBST         6
+#define PFUZE100_VSNVS         7
+#define PFUZE100_VREFDDR       8
+#define PFUZE100_VGEN1         9
+#define PFUZE100_VGEN2         10
+#define PFUZE100_VGEN3         11
+#define PFUZE100_VGEN4         12
+#define PFUZE100_VGEN5         13
+#define PFUZE100_VGEN6         14
+#define PFUZE100_MAX_REGULATOR 15
+
+struct regulator_init_data;
+
+struct pfuze_regulator_platform_data {
+       struct regulator_init_data *init_data[PFUZE100_MAX_REGULATOR];
+};
+
+#endif /* __LINUX_REG_PFUZE100_H */
index 50d04b92cedaf900532f72d1acef35d04d7ecb69..793f4cf63f0c37280ea337cfb780caafed26f64e 100644 (file)
@@ -107,14 +107,6 @@ extern unsigned long this_cpu_load(void);
 extern void calc_global_load(unsigned long ticks);
 extern void update_cpu_load_nohz(void);
 
-/* Notifier for when a task gets migrated to a new CPU */
-struct task_migration_notifier {
-       struct task_struct *task;
-       int from_cpu;
-       int to_cpu;
-};
-extern void register_task_migration_notifier(struct notifier_block *n);
-
 extern unsigned long get_parent_ip(unsigned long addr);
 
 extern void dump_cpu_task(int cpu);
@@ -1034,6 +1026,9 @@ struct task_struct {
 #ifdef CONFIG_SMP
        struct llist_node wake_entry;
        int on_cpu;
+       struct task_struct *last_wakee;
+       unsigned long wakee_flips;
+       unsigned long wakee_flip_decay_ts;
 #endif
        int on_rq;
 
@@ -1532,6 +1527,8 @@ static inline pid_t task_pgrp_nr(struct task_struct *tsk)
  * Test if a process is not yet dead (at most zombie state)
  * If pid_alive fails, then pointers within the task structure
  * can be stale and must not be dereferenced.
+ *
+ * Return: 1 if the process is alive. 0 otherwise.
  */
 static inline int pid_alive(struct task_struct *p)
 {
@@ -1543,6 +1540,8 @@ static inline int pid_alive(struct task_struct *p)
  * @tsk: Task structure to be checked.
  *
  * Check if a task structure is the first user space task the kernel created.
+ *
+ * Return: 1 if the task structure is init. 0 otherwise.
  */
 static inline int is_global_init(struct task_struct *tsk)
 {
@@ -1893,6 +1892,8 @@ extern struct task_struct *idle_task(int cpu);
 /**
  * is_idle_task - is the specified task an idle task?
  * @p: the task in question.
+ *
+ * Return: 1 if @p is an idle task. 0 otherwise.
  */
 static inline bool is_idle_task(const struct task_struct *p)
 {
index 7ce53ae1266bf04c0305f8b695dc240818a7d4ca..5623a7f965b7bbb07ab94a72351aec027ef4adb7 100644 (file)
@@ -1052,17 +1052,25 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  * @xfrm_policy_delete_security:
  *     @ctx contains the xfrm_sec_ctx.
  *     Authorize deletion of xp->security.
- * @xfrm_state_alloc_security:
+ * @xfrm_state_alloc:
  *     @x contains the xfrm_state being added to the Security Association
  *     Database by the XFRM system.
  *     @sec_ctx contains the security context information being provided by
  *     the user-level SA generation program (e.g., setkey or racoon).
- *     @secid contains the secid from which to take the mls portion of the context.
  *     Allocate a security structure to the x->security field; the security
  *     field is initialized to NULL when the xfrm_state is allocated. Set the
- *     context to correspond to either sec_ctx or polsec, with the mls portion
- *     taken from secid in the latter case.
- *     Return 0 if operation was successful (memory to allocate, legal context).
+ *     context to correspond to sec_ctx. Return 0 if operation was successful
+ *     (memory to allocate, legal context).
+ * @xfrm_state_alloc_acquire:
+ *     @x contains the xfrm_state being added to the Security Association
+ *     Database by the XFRM system.
+ *     @polsec contains the policy's security context.
+ *     @secid contains the secid from which to take the mls portion of the
+ *     context.
+ *     Allocate a security structure to the x->security field; the security
+ *     field is initialized to NULL when the xfrm_state is allocated. Set the
+ *     context to correspond to secid. Return 0 if operation was successful
+ *     (memory to allocate, legal context).
  * @xfrm_state_free_security:
  *     @x contains the xfrm_state.
  *     Deallocate x->security.
@@ -1492,7 +1500,7 @@ struct security_operations {
        int (*inode_alloc_security) (struct inode *inode);
        void (*inode_free_security) (struct inode *inode);
        int (*inode_init_security) (struct inode *inode, struct inode *dir,
-                                   const struct qstr *qstr, char **name,
+                                   const struct qstr *qstr, const char **name,
                                    void **value, size_t *len);
        int (*inode_create) (struct inode *dir,
                             struct dentry *dentry, umode_t mode);
@@ -1679,9 +1687,11 @@ struct security_operations {
        int (*xfrm_policy_clone_security) (struct xfrm_sec_ctx *old_ctx, struct xfrm_sec_ctx **new_ctx);
        void (*xfrm_policy_free_security) (struct xfrm_sec_ctx *ctx);
        int (*xfrm_policy_delete_security) (struct xfrm_sec_ctx *ctx);
-       int (*xfrm_state_alloc_security) (struct xfrm_state *x,
-               struct xfrm_user_sec_ctx *sec_ctx,
-               u32 secid);
+       int (*xfrm_state_alloc) (struct xfrm_state *x,
+                                struct xfrm_user_sec_ctx *sec_ctx);
+       int (*xfrm_state_alloc_acquire) (struct xfrm_state *x,
+                                        struct xfrm_sec_ctx *polsec,
+                                        u32 secid);
        void (*xfrm_state_free_security) (struct xfrm_state *x);
        int (*xfrm_state_delete_security) (struct xfrm_state *x);
        int (*xfrm_policy_lookup) (struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir);
@@ -1770,7 +1780,7 @@ int security_inode_init_security(struct inode *inode, struct inode *dir,
                                 const struct qstr *qstr,
                                 initxattrs initxattrs, void *fs_data);
 int security_old_inode_init_security(struct inode *inode, struct inode *dir,
-                                    const struct qstr *qstr, char **name,
+                                    const struct qstr *qstr, const char **name,
                                     void **value, size_t *len);
 int security_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode);
 int security_inode_link(struct dentry *old_dentry, struct inode *dir,
@@ -2094,8 +2104,8 @@ static inline int security_inode_init_security(struct inode *inode,
 static inline int security_old_inode_init_security(struct inode *inode,
                                                   struct inode *dir,
                                                   const struct qstr *qstr,
-                                                  char **name, void **value,
-                                                  size_t *len)
+                                                  const char **name,
+                                                  void **value, size_t *len)
 {
        return -EOPNOTSUPP;
 }
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 28e440be1c07aafaa4ac62470344b052f9107d8f..c28ac127ef3de138b9933d6138e590b7118d0dec 100644 (file)
@@ -233,6 +233,8 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
  *     suported. If set, the SPI core will reject any transfer with an
  *     unsupported bits_per_word. If not set, this value is simply ignored,
  *     and it's up to the individual driver to perform any validation.
+ * @min_speed_hz: Lowest supported transfer speed
+ * @max_speed_hz: Highest supported transfer speed
  * @flags: other constraints relevant to this driver
  * @bus_lock_spinlock: spinlock for SPI bus locking
  * @bus_lock_mutex: mutex for SPI bus locking
@@ -254,6 +256,9 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
  * @busy: message pump is busy
  * @running: message pump is running
  * @rt: whether this queue is set to run as a realtime task
+ * @auto_runtime_pm: the core should ensure a runtime PM reference is held
+ *                   while the hardware is prepared, using the parent
+ *                   device for the spidev
  * @prepare_transfer_hardware: a message will soon arrive from the queue
  *     so the subsystem requests the driver to prepare the transfer hardware
  *     by issuing this call
@@ -312,6 +317,10 @@ struct spi_master {
 #define SPI_BIT_MASK(bits) (((bits) == 32) ? ~0UL : (BIT(bits) - 1))
 #define SPI_BPW_RANGE_MASK(min, max) (SPI_BIT_MASK(max) - SPI_BIT_MASK(min - 1))
 
+       /* limits on transfer speed */
+       u32                     min_speed_hz;
+       u32                     max_speed_hz;
+
        /* other constraints relevant to this driver */
        u16                     flags;
 #define SPI_MASTER_HALF_DUPLEX BIT(0)          /* can't do full duplex */
@@ -374,11 +383,13 @@ struct spi_master {
        bool                            busy;
        bool                            running;
        bool                            rt;
+       bool                            auto_runtime_pm;
 
        int (*prepare_transfer_hardware)(struct spi_master *master);
        int (*transfer_one_message)(struct spi_master *master,
                                    struct spi_message *mesg);
        int (*unprepare_transfer_hardware)(struct spi_master *master);
+
        /* gpio chip select */
        int                     *cs_gpios;
 };
@@ -578,6 +589,7 @@ struct spi_message {
        /* completion is reported through a callback */
        void                    (*complete)(void *context);
        void                    *context;
+       unsigned                frame_length;
        unsigned                actual_length;
        int                     status;
 
index f987a2bee16a8bde6137047582de72654a39e952..daebaba886aa230e759f2d55f880c3277e19e10f 100644 (file)
@@ -4,11 +4,7 @@
 #include <linux/workqueue.h>
 
 struct spi_bitbang {
-       struct workqueue_struct *workqueue;
-       struct work_struct      work;
-
        spinlock_t              lock;
-       struct list_head        queue;
        u8                      busy;
        u8                      use_dma;
        u8                      flags;          /* extra spi->mode support */
@@ -41,7 +37,6 @@ struct spi_bitbang {
  */
 extern int spi_bitbang_setup(struct spi_device *spi);
 extern void spi_bitbang_cleanup(struct spi_device *spi);
-extern int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m);
 extern int spi_bitbang_setup_transfer(struct spi_device *spi,
                                      struct spi_transfer *t);
 
index 472120b4fac57584f30998d1be87c672607eb643..9640803a17a7682e81a436528c836708233dc6a6 100644 (file)
@@ -238,6 +238,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 a0ed78ab54d74b3f60450745fd98c5bf1491e12c..594521ba0d43f73e887375968006429c9ec19502 100644 (file)
@@ -295,7 +295,12 @@ static inline unsigned int work_static(struct work_struct *work) { return 0; }
  * Documentation/workqueue.txt.
  */
 enum {
-       WQ_NON_REENTRANT        = 1 << 0, /* guarantee non-reentrance */
+       /*
+        * All wqs are now non-reentrant making the following flag
+        * meaningless.  Will be removed.
+        */
+       WQ_NON_REENTRANT        = 1 << 0, /* DEPRECATED */
+
        WQ_UNBOUND              = 1 << 1, /* not bound to any cpu */
        WQ_FREEZABLE            = 1 << 2, /* freeze during suspend */
        WQ_MEM_RECLAIM          = 1 << 3, /* may be used for memory reclaim */
index fdbafc6841cfd609cfd0c810ddcf4c3df7a33ed2..91b0a68d38dc2a4941c1b36a8cac270af0136422 100644 (file)
@@ -31,7 +31,7 @@ struct xattr_handler {
 };
 
 struct xattr {
-       char *name;
+       const char *name;
        void *value;
        size_t value_len;
 };
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 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 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..b9f2b095b1ab448566de78d92d8fba029007b519 100644 (file)
@@ -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)
 {
@@ -2249,6 +2260,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..18fc999dae3c37ce2cb6bff6cf54b0abff5213b2 100644 (file)
@@ -284,6 +284,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 +592,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 +1094,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 +1540,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 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 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 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 0b1df41691e8cc2c5436ceeab4812c4753de6653..efef1d37a37188808fc66bc0533264193caa2189 100644 (file)
@@ -375,9 +375,12 @@ struct perf_event_mmap_page {
        __u64   time_running;           /* time event on cpu */
        union {
                __u64   capabilities;
-               __u64   cap_usr_time  : 1,
-                       cap_usr_rdpmc : 1,
-                       cap_____res   : 62;
+               struct {
+                       __u64   cap_usr_time            : 1,
+                               cap_usr_rdpmc           : 1,
+                               cap_usr_time_zero       : 1,
+                               cap_____res             : 61;
+               };
        };
 
        /*
@@ -418,12 +421,29 @@ struct perf_event_mmap_page {
        __u16   time_shift;
        __u32   time_mult;
        __u64   time_offset;
+       /*
+        * If cap_usr_time_zero, the hardware clock (e.g. TSC) can be calculated
+        * from sample timestamps.
+        *
+        *   time = timestamp - time_zero;
+        *   quot = time / time_mult;
+        *   rem  = time % time_mult;
+        *   cyc = (quot << time_shift) + (rem << time_shift) / time_mult;
+        *
+        * And vice versa:
+        *
+        *   quot = cyc >> time_shift;
+        *   rem  = cyc & ((1 << time_shift) - 1);
+        *   timestamp = time_zero + quot * time_mult +
+        *               ((rem * time_mult) >> time_shift);
+        */
+       __u64   time_zero;
 
                /*
                 * Hole for extension of the self monitor capabilities
                 */
 
-       __u64   __reserved[120];        /* align to 1k */
+       __u64   __reserved[119];        /* align to 1k */
 
        /*
         * Control data for the mmap() data buffer.
@@ -478,6 +498,16 @@ enum perf_event_type {
         * file will be supported by older perf tools, with these new optional
         * fields being ignored.
         *
+        * struct sample_id {
+        *      { u32                   pid, tid; } && PERF_SAMPLE_TID
+        *      { u64                   time;     } && PERF_SAMPLE_TIME
+        *      { u64                   id;       } && PERF_SAMPLE_ID
+        *      { u64                   stream_id;} && PERF_SAMPLE_STREAM_ID
+        *      { u32                   cpu, res; } && PERF_SAMPLE_CPU
+        * } && perf_event_attr::sample_id_all
+        */
+
+       /*
         * The MMAP events record the PROT_EXEC mappings so that we can
         * correlate userspace IPs to code. They have the following structure:
         *
@@ -498,6 +528,7 @@ enum perf_event_type {
         *      struct perf_event_header        header;
         *      u64                             id;
         *      u64                             lost;
+        *      struct sample_id                sample_id;
         * };
         */
        PERF_RECORD_LOST                        = 2,
@@ -508,6 +539,7 @@ enum perf_event_type {
         *
         *      u32                             pid, tid;
         *      char                            comm[];
+        *      struct sample_id                sample_id;
         * };
         */
        PERF_RECORD_COMM                        = 3,
@@ -518,6 +550,7 @@ enum perf_event_type {
         *      u32                             pid, ppid;
         *      u32                             tid, ptid;
         *      u64                             time;
+        *      struct sample_id                sample_id;
         * };
         */
        PERF_RECORD_EXIT                        = 4,
@@ -528,6 +561,7 @@ enum perf_event_type {
         *      u64                             time;
         *      u64                             id;
         *      u64                             stream_id;
+        *      struct sample_id                sample_id;
         * };
         */
        PERF_RECORD_THROTTLE                    = 5,
@@ -539,6 +573,7 @@ enum perf_event_type {
         *      u32                             pid, ppid;
         *      u32                             tid, ptid;
         *      u64                             time;
+        *      struct sample_id                sample_id;
         * };
         */
        PERF_RECORD_FORK                        = 7,
@@ -549,6 +584,7 @@ enum perf_event_type {
         *      u32                             pid, tid;
         *
         *      struct read_format              values;
+        *      struct sample_id                sample_id;
         * };
         */
        PERF_RECORD_READ                        = 8,
@@ -596,7 +632,7 @@ enum perf_event_type {
         *        u64                   dyn_size; } && PERF_SAMPLE_STACK_USER
         *
         *      { u64                   weight;   } && PERF_SAMPLE_WEIGHT
-        *      { u64                   data_src;     } && PERF_SAMPLE_DATA_SRC
+        *      { u64                   data_src; } && PERF_SAMPLE_DATA_SRC
         * };
         */
        PERF_RECORD_SAMPLE                      = 9,
index d8ce17c2459a1f8ce79d67267e19d9a581776439..38fdd648be214c1e94851686ae308a5a42543cbf 100644 (file)
@@ -16,7 +16,7 @@ struct reiserfs_xattr_header {
 };
 
 struct reiserfs_security_handle {
-       char *name;
+       const char *name;
        void *value;
        size_t length;
 };
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 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 0f5a2fc69af9971606a1b07185e6f366bf21fbec..c79f3813192675c96ecea7ecd57c41d2fd522422 100644 (file)
 #define ATMEL_LCDC_WIRING_BGR  0
 #define ATMEL_LCDC_WIRING_RGB  1
 
-struct atmel_lcdfb_config;
 
  /* LCD Controller info data structure, stored in device platform_data */
-struct atmel_lcdfb_info {
-       spinlock_t              lock;
-       struct fb_info          *info;
-       void __iomem            *mmio;
-       int                     irq_base;
-       struct work_struct      task;
-
+struct atmel_lcdfb_pdata {
        unsigned int            guard_time;
-       unsigned int            smem_len;
-       struct platform_device  *pdev;
-       struct clk              *bus_clk;
-       struct clk              *lcdc_clk;
-
-#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
-       struct backlight_device *backlight;
-       u8                      bl_power;
-#endif
        bool                    lcdcon_is_backlight;
        bool                    lcdcon_pol_negative;
-       u8                      saved_lcdcon;
-
        u8                      default_bpp;
        u8                      lcd_wiring_mode;
        unsigned int            default_lcdcon2;
        unsigned int            default_dmacon;
-       void (*atmel_lcdfb_power_control)(int on);
+       void (*atmel_lcdfb_power_control)(struct atmel_lcdfb_pdata *pdata, int on);
        struct fb_monspecs      *default_monspecs;
-       u32                     pseudo_palette[16];
 
-       struct atmel_lcdfb_config *config;
+       struct list_head        pwr_gpios;
 };
 
 #define ATMEL_LCDC_DMABADDR1   0x00
index 789ec4683db3b73f83e455891bdb319124215f97..a6bb5f678d6950a1ed14f2bb182982745e10a781 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,
@@ -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;
 
@@ -956,28 +957,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 +982,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 +1002,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 +1076,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 +1086,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 +1142,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 +1284,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 +1326,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 +1344,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;
 }
 
@@ -1584,7 +1531,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 +1549,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 +1558,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;
 
@@ -1657,26 +1604,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 +1647,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 +1666,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 +1683,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 +1700,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 +1733,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);
 
@@ -2782,11 +2738,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 +2769,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 +2794,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 +2804,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 +2826,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 +2849,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 +2881,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 +2890,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);
 
@@ -4148,31 +4130,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 +4170,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)
@@ -4386,7 +4369,11 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
                }
        }
 
-       err = cgroup_populate_dir(cgrp, true, root->subsys_mask);
+       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;
 
@@ -4539,9 +4526,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);
 
@@ -4800,7 +4789,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);
index e5657788feddfefaaed5f7ce3ce2ac26ca80a9c1..703bfd5a32a93225cc0828a6ef79ca503645da4d 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. */
 
@@ -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 f86599e8c12371c7d78248e0c6b2a6869b9122ee..1274114001164246ac01ea3123a6230011e89b33 100644 (file)
@@ -4462,20 +4462,6 @@ void perf_output_sample(struct perf_output_handle *handle,
                }
        }
 
-       if (!event->attr.watermark) {
-               int wakeup_events = event->attr.wakeup_events;
-
-               if (wakeup_events) {
-                       struct ring_buffer *rb = handle->rb;
-                       int events = local_inc_return(&rb->events);
-
-                       if (events >= wakeup_events) {
-                               local_sub(wakeup_events, &rb->events);
-                               local_inc(&rb->wakeup);
-                       }
-               }
-       }
-
        if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
                if (data->br_stack) {
                        size_t size;
@@ -4511,16 +4497,31 @@ void perf_output_sample(struct perf_output_handle *handle,
                }
        }
 
-       if (sample_type & PERF_SAMPLE_STACK_USER)
+       if (sample_type & PERF_SAMPLE_STACK_USER) {
                perf_output_sample_ustack(handle,
                                          data->stack_user_size,
                                          data->regs_user.regs);
+       }
 
        if (sample_type & PERF_SAMPLE_WEIGHT)
                perf_output_put(handle, data->weight);
 
        if (sample_type & PERF_SAMPLE_DATA_SRC)
                perf_output_put(handle, data->data_src.val);
+
+       if (!event->attr.watermark) {
+               int wakeup_events = event->attr.wakeup_events;
+
+               if (wakeup_events) {
+                       struct ring_buffer *rb = handle->rb;
+                       int events = local_inc_return(&rb->events);
+
+                       if (events >= wakeup_events) {
+                               local_sub(wakeup_events, &rb->events);
+                               local_inc(&rb->wakeup);
+                       }
+               }
+       }
 }
 
 void perf_prepare_sample(struct perf_event_header *header,
@@ -4680,12 +4681,10 @@ perf_event_read_event(struct perf_event *event,
        perf_output_end(&handle);
 }
 
-typedef int  (perf_event_aux_match_cb)(struct perf_event *event, void *data);
 typedef void (perf_event_aux_output_cb)(struct perf_event *event, void *data);
 
 static void
 perf_event_aux_ctx(struct perf_event_context *ctx,
-                  perf_event_aux_match_cb match,
                   perf_event_aux_output_cb output,
                   void *data)
 {
@@ -4696,15 +4695,12 @@ perf_event_aux_ctx(struct perf_event_context *ctx,
                        continue;
                if (!event_filter_match(event))
                        continue;
-               if (match(event, data))
-                       output(event, data);
+               output(event, data);
        }
 }
 
 static void
-perf_event_aux(perf_event_aux_match_cb match,
-              perf_event_aux_output_cb output,
-              void *data,
+perf_event_aux(perf_event_aux_output_cb output, void *data,
               struct perf_event_context *task_ctx)
 {
        struct perf_cpu_context *cpuctx;
@@ -4717,7 +4713,7 @@ perf_event_aux(perf_event_aux_match_cb match,
                cpuctx = get_cpu_ptr(pmu->pmu_cpu_context);
                if (cpuctx->unique_pmu != pmu)
                        goto next;
-               perf_event_aux_ctx(&cpuctx->ctx, match, output, data);
+               perf_event_aux_ctx(&cpuctx->ctx, output, data);
                if (task_ctx)
                        goto next;
                ctxn = pmu->task_ctx_nr;
@@ -4725,14 +4721,14 @@ perf_event_aux(perf_event_aux_match_cb match,
                        goto next;
                ctx = rcu_dereference(current->perf_event_ctxp[ctxn]);
                if (ctx)
-                       perf_event_aux_ctx(ctx, match, output, data);
+                       perf_event_aux_ctx(ctx, output, data);
 next:
                put_cpu_ptr(pmu->pmu_cpu_context);
        }
 
        if (task_ctx) {
                preempt_disable();
-               perf_event_aux_ctx(task_ctx, match, output, data);
+               perf_event_aux_ctx(task_ctx, output, data);
                preempt_enable();
        }
        rcu_read_unlock();
@@ -4759,6 +4755,12 @@ struct perf_task_event {
        } event_id;
 };
 
+static int perf_event_task_match(struct perf_event *event)
+{
+       return event->attr.comm || event->attr.mmap ||
+              event->attr.mmap_data || event->attr.task;
+}
+
 static void perf_event_task_output(struct perf_event *event,
                                   void *data)
 {
@@ -4768,6 +4770,9 @@ static void perf_event_task_output(struct perf_event *event,
        struct task_struct *task = task_event->task;
        int ret, size = task_event->event_id.header.size;
 
+       if (!perf_event_task_match(event))
+               return;
+
        perf_event_header__init_id(&task_event->event_id.header, &sample, event);
 
        ret = perf_output_begin(&handle, event,
@@ -4790,13 +4795,6 @@ out:
        task_event->event_id.header.size = size;
 }
 
-static int perf_event_task_match(struct perf_event *event,
-                                void *data __maybe_unused)
-{
-       return event->attr.comm || event->attr.mmap ||
-              event->attr.mmap_data || event->attr.task;
-}
-
 static void perf_event_task(struct task_struct *task,
                              struct perf_event_context *task_ctx,
                              int new)
@@ -4825,8 +4823,7 @@ static void perf_event_task(struct task_struct *task,
                },
        };
 
-       perf_event_aux(perf_event_task_match,
-                      perf_event_task_output,
+       perf_event_aux(perf_event_task_output,
                       &task_event,
                       task_ctx);
 }
@@ -4853,6 +4850,11 @@ struct perf_comm_event {
        } event_id;
 };
 
+static int perf_event_comm_match(struct perf_event *event)
+{
+       return event->attr.comm;
+}
+
 static void perf_event_comm_output(struct perf_event *event,
                                   void *data)
 {
@@ -4862,6 +4864,9 @@ static void perf_event_comm_output(struct perf_event *event,
        int size = comm_event->event_id.header.size;
        int ret;
 
+       if (!perf_event_comm_match(event))
+               return;
+
        perf_event_header__init_id(&comm_event->event_id.header, &sample, event);
        ret = perf_output_begin(&handle, event,
                                comm_event->event_id.header.size);
@@ -4883,12 +4888,6 @@ out:
        comm_event->event_id.header.size = size;
 }
 
-static int perf_event_comm_match(struct perf_event *event,
-                                void *data __maybe_unused)
-{
-       return event->attr.comm;
-}
-
 static void perf_event_comm_event(struct perf_comm_event *comm_event)
 {
        char comm[TASK_COMM_LEN];
@@ -4903,8 +4902,7 @@ static void perf_event_comm_event(struct perf_comm_event *comm_event)
 
        comm_event->event_id.header.size = sizeof(comm_event->event_id) + size;
 
-       perf_event_aux(perf_event_comm_match,
-                      perf_event_comm_output,
+       perf_event_aux(perf_event_comm_output,
                       comm_event,
                       NULL);
 }
@@ -4967,6 +4965,17 @@ struct perf_mmap_event {
        } event_id;
 };
 
+static int perf_event_mmap_match(struct perf_event *event,
+                                void *data)
+{
+       struct perf_mmap_event *mmap_event = data;
+       struct vm_area_struct *vma = mmap_event->vma;
+       int executable = vma->vm_flags & VM_EXEC;
+
+       return (!executable && event->attr.mmap_data) ||
+              (executable && event->attr.mmap);
+}
+
 static void perf_event_mmap_output(struct perf_event *event,
                                   void *data)
 {
@@ -4976,6 +4985,9 @@ static void perf_event_mmap_output(struct perf_event *event,
        int size = mmap_event->event_id.header.size;
        int ret;
 
+       if (!perf_event_mmap_match(event, data))
+               return;
+
        perf_event_header__init_id(&mmap_event->event_id.header, &sample, event);
        ret = perf_output_begin(&handle, event,
                                mmap_event->event_id.header.size);
@@ -4996,17 +5008,6 @@ out:
        mmap_event->event_id.header.size = size;
 }
 
-static int perf_event_mmap_match(struct perf_event *event,
-                                void *data)
-{
-       struct perf_mmap_event *mmap_event = data;
-       struct vm_area_struct *vma = mmap_event->vma;
-       int executable = vma->vm_flags & VM_EXEC;
-
-       return (!executable && event->attr.mmap_data) ||
-              (executable && event->attr.mmap);
-}
-
 static void perf_event_mmap_event(struct perf_mmap_event *mmap_event)
 {
        struct vm_area_struct *vma = mmap_event->vma;
@@ -5070,8 +5071,7 @@ got_name:
 
        mmap_event->event_id.header.size = sizeof(mmap_event->event_id) + size;
 
-       perf_event_aux(perf_event_mmap_match,
-                      perf_event_mmap_output,
+       perf_event_aux(perf_event_mmap_output,
                       mmap_event,
                       NULL);
 
index 6535a667a5a797a3fa1f9a9683cd9e85124692d7..86ae2aebf00432f4d681a413febebff79406889d 100644 (file)
@@ -21,7 +21,7 @@ void lg_local_lock(struct lglock *lg)
        arch_spinlock_t *lock;
 
        preempt_disable();
-       rwlock_acquire_read(&lg->lock_dep_map, 0, 0, _RET_IP_);
+       lock_acquire_shared(&lg->lock_dep_map, 0, 0, NULL, _RET_IP_);
        lock = this_cpu_ptr(lg->lock);
        arch_spin_lock(lock);
 }
@@ -31,7 +31,7 @@ void lg_local_unlock(struct lglock *lg)
 {
        arch_spinlock_t *lock;
 
-       rwlock_release(&lg->lock_dep_map, 1, _RET_IP_);
+       lock_release(&lg->lock_dep_map, 1, _RET_IP_);
        lock = this_cpu_ptr(lg->lock);
        arch_spin_unlock(lock);
        preempt_enable();
@@ -43,7 +43,7 @@ void lg_local_lock_cpu(struct lglock *lg, int cpu)
        arch_spinlock_t *lock;
 
        preempt_disable();
-       rwlock_acquire_read(&lg->lock_dep_map, 0, 0, _RET_IP_);
+       lock_acquire_shared(&lg->lock_dep_map, 0, 0, NULL, _RET_IP_);
        lock = per_cpu_ptr(lg->lock, cpu);
        arch_spin_lock(lock);
 }
@@ -53,7 +53,7 @@ void lg_local_unlock_cpu(struct lglock *lg, int cpu)
 {
        arch_spinlock_t *lock;
 
-       rwlock_release(&lg->lock_dep_map, 1, _RET_IP_);
+       lock_release(&lg->lock_dep_map, 1, _RET_IP_);
        lock = per_cpu_ptr(lg->lock, cpu);
        arch_spin_unlock(lock);
        preempt_enable();
@@ -65,7 +65,7 @@ void lg_global_lock(struct lglock *lg)
        int i;
 
        preempt_disable();
-       rwlock_acquire(&lg->lock_dep_map, 0, 0, _RET_IP_);
+       lock_acquire_exclusive(&lg->lock_dep_map, 0, 0, NULL, _RET_IP_);
        for_each_possible_cpu(i) {
                arch_spinlock_t *lock;
                lock = per_cpu_ptr(lg->lock, i);
@@ -78,7 +78,7 @@ void lg_global_unlock(struct lglock *lg)
 {
        int i;
 
-       rwlock_release(&lg->lock_dep_map, 1, _RET_IP_);
+       lock_release(&lg->lock_dep_map, 1, _RET_IP_);
        for_each_possible_cpu(i) {
                arch_spinlock_t *lock;
                lock = per_cpu_ptr(lg->lock, i);
index ff05f4bd86eb6acf10ff49307e448ddb8b00916a..98164a55a4dc677199418f8200701fca00ca824b 100644 (file)
@@ -209,11 +209,13 @@ int mutex_spin_on_owner(struct mutex *lock, struct task_struct *owner)
  */
 static inline int mutex_can_spin_on_owner(struct mutex *lock)
 {
+       struct task_struct *owner;
        int retval = 1;
 
        rcu_read_lock();
-       if (lock->owner)
-               retval = lock->owner->on_cpu;
+       owner = ACCESS_ONCE(lock->owner);
+       if (owner)
+               retval = owner->on_cpu;
        rcu_read_unlock();
        /*
         * if lock->owner is not set, the mutex owner may have just acquired
@@ -461,7 +463,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
                         * performed the optimistic spinning cannot be done.
                         */
                        if (ACCESS_ONCE(ww->ctx))
-                               break;
+                               goto slowpath;
                }
 
                /*
@@ -472,7 +474,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
                owner = ACCESS_ONCE(lock->owner);
                if (owner && !mutex_spin_on_owner(lock, owner)) {
                        mspin_unlock(MLOCK(lock), &node);
-                       break;
+                       goto slowpath;
                }
 
                if ((atomic_read(&lock->count) == 1) &&
@@ -499,7 +501,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
                 * the owner complete.
                 */
                if (!owner && (need_resched() || rt_task(task)))
-                       break;
+                       goto slowpath;
 
                /*
                 * The cpu_relax() call is a compiler barrier which forces
@@ -513,6 +515,10 @@ slowpath:
 #endif
        spin_lock_mutex(&lock->wait_lock, flags);
 
+       /* once more, can we acquire the lock? */
+       if (MUTEX_SHOW_NO_WAITER(lock) && (atomic_xchg(&lock->count, 0) == 1))
+               goto skip_wait;
+
        debug_mutex_lock_common(lock, &waiter);
        debug_mutex_add_waiter(lock, &waiter, task_thread_info(task));
 
@@ -520,9 +526,6 @@ slowpath:
        list_add_tail(&waiter.list, &lock->wait_list);
        waiter.task = task;
 
-       if (MUTEX_SHOW_NO_WAITER(lock) && (atomic_xchg(&lock->count, -1) == 1))
-               goto done;
-
        lock_contended(&lock->dep_map, ip);
 
        for (;;) {
@@ -536,7 +539,7 @@ slowpath:
                 * other waiters:
                 */
                if (MUTEX_SHOW_NO_WAITER(lock) &&
-                  (atomic_xchg(&lock->count, -1) == 1))
+                   (atomic_xchg(&lock->count, -1) == 1))
                        break;
 
                /*
@@ -561,24 +564,25 @@ slowpath:
                schedule_preempt_disabled();
                spin_lock_mutex(&lock->wait_lock, flags);
        }
+       mutex_remove_waiter(lock, &waiter, current_thread_info());
+       /* set it to 0 if there are no waiters left: */
+       if (likely(list_empty(&lock->wait_list)))
+               atomic_set(&lock->count, 0);
+       debug_mutex_free_waiter(&waiter);
 
-done:
+skip_wait:
+       /* got the lock - cleanup and rejoice! */
        lock_acquired(&lock->dep_map, ip);
-       /* got the lock - rejoice! */
-       mutex_remove_waiter(lock, &waiter, current_thread_info());
        mutex_set_owner(lock);
 
        if (!__builtin_constant_p(ww_ctx == NULL)) {
-               struct ww_mutex *ww = container_of(lock,
-                                                     struct ww_mutex,
-                                                     base);
+               struct ww_mutex *ww = container_of(lock, struct ww_mutex, base);
                struct mutex_waiter *cur;
 
                /*
                 * This branch gets optimized out for the common case,
                 * and is only important for ww_mutex_lock.
                 */
-
                ww_mutex_lock_acquired(ww, ww_ctx);
                ww->ctx = ww_ctx;
 
@@ -592,15 +596,8 @@ done:
                }
        }
 
-       /* set it to 0 if there are no waiters left: */
-       if (likely(list_empty(&lock->wait_list)))
-               atomic_set(&lock->count, 0);
-
        spin_unlock_mutex(&lock->wait_lock, flags);
-
-       debug_mutex_free_waiter(&waiter);
        preempt_enable();
-
        return 0;
 
 err:
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)
index 7f8e7590e3e5d414141f3f778caaf58f8b0f6717..ad6c3f521326254a5c475cca5aa3639a251f448d 100644 (file)
 
 extern struct debug_obj_descr rcuhead_debug_descr;
 
-static inline void debug_rcu_head_queue(struct rcu_head *head)
+static inline int debug_rcu_head_queue(struct rcu_head *head)
 {
-       debug_object_activate(head, &rcuhead_debug_descr);
+       int r1;
+
+       r1 = debug_object_activate(head, &rcuhead_debug_descr);
        debug_object_active_state(head, &rcuhead_debug_descr,
                                  STATE_RCU_HEAD_READY,
                                  STATE_RCU_HEAD_QUEUED);
+       return r1;
 }
 
 static inline void debug_rcu_head_unqueue(struct rcu_head *head)
@@ -83,8 +86,9 @@ static inline void debug_rcu_head_unqueue(struct rcu_head *head)
        debug_object_deactivate(head, &rcuhead_debug_descr);
 }
 #else  /* !CONFIG_DEBUG_OBJECTS_RCU_HEAD */
-static inline void debug_rcu_head_queue(struct rcu_head *head)
+static inline int debug_rcu_head_queue(struct rcu_head *head)
 {
+       return 0;
 }
 
 static inline void debug_rcu_head_unqueue(struct rcu_head *head)
index cce6ba8bbace7f0793d008c725c9599a5ba8c1d1..7faee78a648d5fe98cad5b7c19888a7c4a71296f 100644 (file)
@@ -211,43 +211,6 @@ static inline void debug_rcu_head_free(struct rcu_head *head)
        debug_object_free(head, &rcuhead_debug_descr);
 }
 
-/*
- * fixup_init is called when:
- * - an active object is initialized
- */
-static int rcuhead_fixup_init(void *addr, enum debug_obj_state state)
-{
-       struct rcu_head *head = addr;
-
-       switch (state) {
-       case ODEBUG_STATE_ACTIVE:
-               /*
-                * Ensure that queued callbacks are all executed.
-                * If we detect that we are nested in a RCU read-side critical
-                * section, we should simply fail, otherwise we would deadlock.
-                * In !PREEMPT configurations, there is no way to tell if we are
-                * in a RCU read-side critical section or not, so we never
-                * attempt any fixup and just print a warning.
-                */
-#ifndef CONFIG_PREEMPT
-               WARN_ON_ONCE(1);
-               return 0;
-#endif
-               if (rcu_preempt_depth() != 0 || preempt_count() != 0 ||
-                   irqs_disabled()) {
-                       WARN_ON_ONCE(1);
-                       return 0;
-               }
-               rcu_barrier();
-               rcu_barrier_sched();
-               rcu_barrier_bh();
-               debug_object_init(head, &rcuhead_debug_descr);
-               return 1;
-       default:
-               return 0;
-       }
-}
-
 /*
  * fixup_activate is called when:
  * - an active object is activated
@@ -268,69 +231,8 @@ static int rcuhead_fixup_activate(void *addr, enum debug_obj_state state)
                debug_object_init(head, &rcuhead_debug_descr);
                debug_object_activate(head, &rcuhead_debug_descr);
                return 0;
-
-       case ODEBUG_STATE_ACTIVE:
-               /*
-                * Ensure that queued callbacks are all executed.
-                * If we detect that we are nested in a RCU read-side critical
-                * section, we should simply fail, otherwise we would deadlock.
-                * In !PREEMPT configurations, there is no way to tell if we are
-                * in a RCU read-side critical section or not, so we never
-                * attempt any fixup and just print a warning.
-                */
-#ifndef CONFIG_PREEMPT
-               WARN_ON_ONCE(1);
-               return 0;
-#endif
-               if (rcu_preempt_depth() != 0 || preempt_count() != 0 ||
-                   irqs_disabled()) {
-                       WARN_ON_ONCE(1);
-                       return 0;
-               }
-               rcu_barrier();
-               rcu_barrier_sched();
-               rcu_barrier_bh();
-               debug_object_activate(head, &rcuhead_debug_descr);
-               return 1;
        default:
-               return 0;
-       }
-}
-
-/*
- * fixup_free is called when:
- * - an active object is freed
- */
-static int rcuhead_fixup_free(void *addr, enum debug_obj_state state)
-{
-       struct rcu_head *head = addr;
-
-       switch (state) {
-       case ODEBUG_STATE_ACTIVE:
-               /*
-                * Ensure that queued callbacks are all executed.
-                * If we detect that we are nested in a RCU read-side critical
-                * section, we should simply fail, otherwise we would deadlock.
-                * In !PREEMPT configurations, there is no way to tell if we are
-                * in a RCU read-side critical section or not, so we never
-                * attempt any fixup and just print a warning.
-                */
-#ifndef CONFIG_PREEMPT
-               WARN_ON_ONCE(1);
-               return 0;
-#endif
-               if (rcu_preempt_depth() != 0 || preempt_count() != 0 ||
-                   irqs_disabled()) {
-                       WARN_ON_ONCE(1);
-                       return 0;
-               }
-               rcu_barrier();
-               rcu_barrier_sched();
-               rcu_barrier_bh();
-               debug_object_free(head, &rcuhead_debug_descr);
                return 1;
-       default:
-               return 0;
        }
 }
 
@@ -369,9 +271,7 @@ EXPORT_SYMBOL_GPL(destroy_rcu_head_on_stack);
 
 struct debug_obj_descr rcuhead_debug_descr = {
        .name = "rcu_head",
-       .fixup_init = rcuhead_fixup_init,
        .fixup_activate = rcuhead_fixup_activate,
-       .fixup_free = rcuhead_fixup_free,
 };
 EXPORT_SYMBOL_GPL(rcuhead_debug_descr);
 #endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
index f4871e52c54600bb16d129d009e3d0828ad111fc..fb3949a2fc39c8ca786c91f55b53b84c6184b283 100644 (file)
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com> and Josh Triplett <josh@freedesktop.org>");
 
-static int nreaders = -1;      /* # reader threads, defaults to 2*ncpus */
-static int nfakewriters = 4;   /* # fake writer threads */
-static int stat_interval = 60; /* Interval between stats, in seconds. */
-                               /*  Zero means "only at end of test". */
-static bool verbose;           /* Print more debug info. */
-static bool test_no_idle_hz = true;
-                               /* Test RCU support for tickless idle CPUs. */
-static int shuffle_interval = 3; /* Interval between shuffles (in sec)*/
-static int stutter = 5;                /* Start/stop testing interval (in sec) */
-static int irqreader = 1;      /* RCU readers from irq (timers). */
 static int fqs_duration;       /* Duration of bursts (us), 0 to disable. */
 static int fqs_holdoff;                /* Hold time within burst (us). */
 static int fqs_stutter = 3;    /* Wait time between bursts (s). */
+static bool gp_exp = 0;                /* Use expedited GP wait primitives. */
+static bool gp_normal = 0;     /* Use normal GP wait primitives. */
+static int irqreader = 1;      /* RCU readers from irq (timers). */
 static int n_barrier_cbs;      /* Number of callbacks to test RCU barriers. */
-static int onoff_interval;     /* Wait time between CPU hotplugs, 0=disable. */
+static int nfakewriters = 4;   /* # fake writer threads */
+static int nreaders = -1;      /* # reader threads, defaults to 2*ncpus */
+static int object_debug;       /* Test object-debug double call_rcu()?. */
 static int onoff_holdoff;      /* Seconds after boot before CPU hotplugs. */
+static int onoff_interval;     /* Wait time between CPU hotplugs, 0=disable. */
+static int shuffle_interval = 3; /* Interval between shuffles (in sec)*/
 static int shutdown_secs;      /* Shutdown time (s).  <=0 for no shutdown. */
 static int stall_cpu;          /* CPU-stall duration (s).  0 for no stall. */
 static int stall_cpu_holdoff = 10; /* Time to wait until stall (s).  */
+static int stat_interval = 60; /* Interval between stats, in seconds. */
+                               /*  Zero means "only at end of test". */
+static int stutter = 5;                /* Start/stop testing interval (in sec) */
 static int test_boost = 1;     /* Test RCU prio boost: 0=no, 1=maybe, 2=yes. */
-static int test_boost_interval = 7; /* Interval between boost tests, seconds. */
 static int test_boost_duration = 4; /* Duration of each boost test, seconds. */
+static int test_boost_interval = 7; /* Interval between boost tests, seconds. */
+static bool test_no_idle_hz = true;
+                               /* Test RCU support for tickless idle CPUs. */
 static char *torture_type = "rcu"; /* What RCU implementation to torture. */
+static bool verbose;           /* Print more debug info. */
 
-module_param(nreaders, int, 0444);
-MODULE_PARM_DESC(nreaders, "Number of RCU reader threads");
-module_param(nfakewriters, int, 0444);
-MODULE_PARM_DESC(nfakewriters, "Number of RCU fake writer threads");
-module_param(stat_interval, int, 0644);
-MODULE_PARM_DESC(stat_interval, "Number of seconds between stats printk()s");
-module_param(verbose, bool, 0444);
-MODULE_PARM_DESC(verbose, "Enable verbose debugging printk()s");
-module_param(test_no_idle_hz, bool, 0444);
-MODULE_PARM_DESC(test_no_idle_hz, "Test support for tickless idle CPUs");
-module_param(shuffle_interval, int, 0444);
-MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles");
-module_param(stutter, int, 0444);
-MODULE_PARM_DESC(stutter, "Number of seconds to run/halt test");
-module_param(irqreader, int, 0444);
-MODULE_PARM_DESC(irqreader, "Allow RCU readers from irq handlers");
 module_param(fqs_duration, int, 0444);
 MODULE_PARM_DESC(fqs_duration, "Duration of fqs bursts (us)");
 module_param(fqs_holdoff, int, 0444);
 MODULE_PARM_DESC(fqs_holdoff, "Holdoff time within fqs bursts (us)");
 module_param(fqs_stutter, int, 0444);
 MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)");
+module_param(gp_exp, bool, 0444);
+MODULE_PARM_DESC(gp_exp, "Use expedited GP wait primitives");
+module_param(gp_normal, bool, 0444);
+MODULE_PARM_DESC(gp_normal, "Use normal (non-expedited) GP wait primitives");
+module_param(irqreader, int, 0444);
+MODULE_PARM_DESC(irqreader, "Allow RCU readers from irq handlers");
 module_param(n_barrier_cbs, int, 0444);
 MODULE_PARM_DESC(n_barrier_cbs, "# of callbacks/kthreads for barrier testing");
-module_param(onoff_interval, int, 0444);
-MODULE_PARM_DESC(onoff_interval, "Time between CPU hotplugs (s), 0=disable");
+module_param(nfakewriters, int, 0444);
+MODULE_PARM_DESC(nfakewriters, "Number of RCU fake writer threads");
+module_param(nreaders, int, 0444);
+MODULE_PARM_DESC(nreaders, "Number of RCU reader threads");
+module_param(object_debug, int, 0444);
+MODULE_PARM_DESC(object_debug, "Enable debug-object double call_rcu() testing");
 module_param(onoff_holdoff, int, 0444);
 MODULE_PARM_DESC(onoff_holdoff, "Time after boot before CPU hotplugs (s)");
+module_param(onoff_interval, int, 0444);
+MODULE_PARM_DESC(onoff_interval, "Time between CPU hotplugs (s), 0=disable");
+module_param(shuffle_interval, int, 0444);
+MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles");
 module_param(shutdown_secs, int, 0444);
 MODULE_PARM_DESC(shutdown_secs, "Shutdown time (s), zero to disable.");
 module_param(stall_cpu, int, 0444);
 MODULE_PARM_DESC(stall_cpu, "Stall duration (s), zero to disable.");
 module_param(stall_cpu_holdoff, int, 0444);
 MODULE_PARM_DESC(stall_cpu_holdoff, "Time to wait before starting stall (s).");
+module_param(stat_interval, int, 0644);
+MODULE_PARM_DESC(stat_interval, "Number of seconds between stats printk()s");
+module_param(stutter, int, 0444);
+MODULE_PARM_DESC(stutter, "Number of seconds to run/halt test");
 module_param(test_boost, int, 0444);
 MODULE_PARM_DESC(test_boost, "Test RCU prio boost: 0=no, 1=maybe, 2=yes.");
-module_param(test_boost_interval, int, 0444);
-MODULE_PARM_DESC(test_boost_interval, "Interval between boost tests, seconds.");
 module_param(test_boost_duration, int, 0444);
 MODULE_PARM_DESC(test_boost_duration, "Duration of each boost test, seconds.");
+module_param(test_boost_interval, int, 0444);
+MODULE_PARM_DESC(test_boost_interval, "Interval between boost tests, seconds.");
+module_param(test_no_idle_hz, bool, 0444);
+MODULE_PARM_DESC(test_no_idle_hz, "Test support for tickless idle CPUs");
 module_param(torture_type, charp, 0444);
 MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, srcu)");
+module_param(verbose, bool, 0444);
+MODULE_PARM_DESC(verbose, "Enable verbose debugging printk()s");
 
 #define TORTURE_FLAG "-torture:"
 #define PRINTK_STRING(s) \
@@ -360,6 +369,7 @@ struct rcu_torture_ops {
        int (*completed)(void);
        void (*deferred_free)(struct rcu_torture *p);
        void (*sync)(void);
+       void (*exp_sync)(void);
        void (*call)(struct rcu_head *head, void (*func)(struct rcu_head *rcu));
        void (*cb_barrier)(void);
        void (*fqs)(void);
@@ -443,81 +453,27 @@ static void rcu_torture_deferred_free(struct rcu_torture *p)
        call_rcu(&p->rtort_rcu, rcu_torture_cb);
 }
 
-static struct rcu_torture_ops rcu_ops = {
-       .init           = NULL,
-       .readlock       = rcu_torture_read_lock,
-       .read_delay     = rcu_read_delay,
-       .readunlock     = rcu_torture_read_unlock,
-       .completed      = rcu_torture_completed,
-       .deferred_free  = rcu_torture_deferred_free,
-       .sync           = synchronize_rcu,
-       .call           = call_rcu,
-       .cb_barrier     = rcu_barrier,
-       .fqs            = rcu_force_quiescent_state,
-       .stats          = NULL,
-       .irq_capable    = 1,
-       .can_boost      = rcu_can_boost(),
-       .name           = "rcu"
-};
-
-static void rcu_sync_torture_deferred_free(struct rcu_torture *p)
-{
-       int i;
-       struct rcu_torture *rp;
-       struct rcu_torture *rp1;
-
-       cur_ops->sync();
-       list_add(&p->rtort_free, &rcu_torture_removed);
-       list_for_each_entry_safe(rp, rp1, &rcu_torture_removed, rtort_free) {
-               i = rp->rtort_pipe_count;
-               if (i > RCU_TORTURE_PIPE_LEN)
-                       i = RCU_TORTURE_PIPE_LEN;
-               atomic_inc(&rcu_torture_wcount[i]);
-               if (++rp->rtort_pipe_count >= RCU_TORTURE_PIPE_LEN) {
-                       rp->rtort_mbtest = 0;
-                       list_del(&rp->rtort_free);
-                       rcu_torture_free(rp);
-               }
-       }
-}
-
 static void rcu_sync_torture_init(void)
 {
        INIT_LIST_HEAD(&rcu_torture_removed);
 }
 
-static struct rcu_torture_ops rcu_sync_ops = {
+static struct rcu_torture_ops rcu_ops = {
        .init           = rcu_sync_torture_init,
        .readlock       = rcu_torture_read_lock,
        .read_delay     = rcu_read_delay,
        .readunlock     = rcu_torture_read_unlock,
        .completed      = rcu_torture_completed,
-       .deferred_free  = rcu_sync_torture_deferred_free,
+       .deferred_free  = rcu_torture_deferred_free,
        .sync           = synchronize_rcu,
-       .call           = NULL,
-       .cb_barrier     = NULL,
-       .fqs            = rcu_force_quiescent_state,
-       .stats          = NULL,
-       .irq_capable    = 1,
-       .can_boost      = rcu_can_boost(),
-       .name           = "rcu_sync"
-};
-
-static struct rcu_torture_ops rcu_expedited_ops = {
-       .init           = rcu_sync_torture_init,
-       .readlock       = rcu_torture_read_lock,
-       .read_delay     = rcu_read_delay,  /* just reuse rcu's version. */
-       .readunlock     = rcu_torture_read_unlock,
-       .completed      = rcu_no_completed,
-       .deferred_free  = rcu_sync_torture_deferred_free,
-       .sync           = synchronize_rcu_expedited,
-       .call           = NULL,
-       .cb_barrier     = NULL,
+       .exp_sync       = synchronize_rcu_expedited,
+       .call           = call_rcu,
+       .cb_barrier     = rcu_barrier,
        .fqs            = rcu_force_quiescent_state,
        .stats          = NULL,
        .irq_capable    = 1,
        .can_boost      = rcu_can_boost(),
-       .name           = "rcu_expedited"
+       .name           = "rcu"
 };
 
 /*
@@ -546,13 +502,14 @@ static void rcu_bh_torture_deferred_free(struct rcu_torture *p)
 }
 
 static struct rcu_torture_ops rcu_bh_ops = {
-       .init           = NULL,
+       .init           = rcu_sync_torture_init,
        .readlock       = rcu_bh_torture_read_lock,
        .read_delay     = rcu_read_delay,  /* just reuse rcu's version. */
        .readunlock     = rcu_bh_torture_read_unlock,
        .completed      = rcu_bh_torture_completed,
        .deferred_free  = rcu_bh_torture_deferred_free,
        .sync           = synchronize_rcu_bh,
+       .exp_sync       = synchronize_rcu_bh_expedited,
        .call           = call_rcu_bh,
        .cb_barrier     = rcu_barrier_bh,
        .fqs            = rcu_bh_force_quiescent_state,
@@ -561,38 +518,6 @@ static struct rcu_torture_ops rcu_bh_ops = {
        .name           = "rcu_bh"
 };
 
-static struct rcu_torture_ops rcu_bh_sync_ops = {
-       .init           = rcu_sync_torture_init,
-       .readlock       = rcu_bh_torture_read_lock,
-       .read_delay     = rcu_read_delay,  /* just reuse rcu's version. */
-       .readunlock     = rcu_bh_torture_read_unlock,
-       .completed      = rcu_bh_torture_completed,
-       .deferred_free  = rcu_sync_torture_deferred_free,
-       .sync           = synchronize_rcu_bh,
-       .call           = NULL,
-       .cb_barrier     = NULL,
-       .fqs            = rcu_bh_force_quiescent_state,
-       .stats          = NULL,
-       .irq_capable    = 1,
-       .name           = "rcu_bh_sync"
-};
-
-static struct rcu_torture_ops rcu_bh_expedited_ops = {
-       .init           = rcu_sync_torture_init,
-       .readlock       = rcu_bh_torture_read_lock,
-       .read_delay     = rcu_read_delay,  /* just reuse rcu's version. */
-       .readunlock     = rcu_bh_torture_read_unlock,
-       .completed      = rcu_bh_torture_completed,
-       .deferred_free  = rcu_sync_torture_deferred_free,
-       .sync           = synchronize_rcu_bh_expedited,
-       .call           = NULL,
-       .cb_barrier     = NULL,
-       .fqs            = rcu_bh_force_quiescent_state,
-       .stats          = NULL,
-       .irq_capable    = 1,
-       .name           = "rcu_bh_expedited"
-};
-
 /*
  * Definitions for srcu torture testing.
  */
@@ -667,6 +592,11 @@ static int srcu_torture_stats(char *page)
        return cnt;
 }
 
+static void srcu_torture_synchronize_expedited(void)
+{
+       synchronize_srcu_expedited(&srcu_ctl);
+}
+
 static struct rcu_torture_ops srcu_ops = {
        .init           = rcu_sync_torture_init,
        .readlock       = srcu_torture_read_lock,
@@ -675,45 +605,13 @@ static struct rcu_torture_ops srcu_ops = {
        .completed      = srcu_torture_completed,
        .deferred_free  = srcu_torture_deferred_free,
        .sync           = srcu_torture_synchronize,
+       .exp_sync       = srcu_torture_synchronize_expedited,
        .call           = srcu_torture_call,
        .cb_barrier     = srcu_torture_barrier,
        .stats          = srcu_torture_stats,
        .name           = "srcu"
 };
 
-static struct rcu_torture_ops srcu_sync_ops = {
-       .init           = rcu_sync_torture_init,
-       .readlock       = srcu_torture_read_lock,
-       .read_delay     = srcu_read_delay,
-       .readunlock     = srcu_torture_read_unlock,
-       .completed      = srcu_torture_completed,
-       .deferred_free  = rcu_sync_torture_deferred_free,
-       .sync           = srcu_torture_synchronize,
-       .call           = NULL,
-       .cb_barrier     = NULL,
-       .stats          = srcu_torture_stats,
-       .name           = "srcu_sync"
-};
-
-static void srcu_torture_synchronize_expedited(void)
-{
-       synchronize_srcu_expedited(&srcu_ctl);
-}
-
-static struct rcu_torture_ops srcu_expedited_ops = {
-       .init           = rcu_sync_torture_init,
-       .readlock       = srcu_torture_read_lock,
-       .read_delay     = srcu_read_delay,
-       .readunlock     = srcu_torture_read_unlock,
-       .completed      = srcu_torture_completed,
-       .deferred_free  = rcu_sync_torture_deferred_free,
-       .sync           = srcu_torture_synchronize_expedited,
-       .call           = NULL,
-       .cb_barrier     = NULL,
-       .stats          = srcu_torture_stats,
-       .name           = "srcu_expedited"
-};
-
 /*
  * Definitions for sched torture testing.
  */
@@ -742,6 +640,8 @@ static struct rcu_torture_ops sched_ops = {
        .completed      = rcu_no_completed,
        .deferred_free  = rcu_sched_torture_deferred_free,
        .sync           = synchronize_sched,
+       .exp_sync       = synchronize_sched_expedited,
+       .call           = call_rcu_sched,
        .cb_barrier     = rcu_barrier_sched,
        .fqs            = rcu_sched_force_quiescent_state,
        .stats          = NULL,
@@ -749,35 +649,6 @@ static struct rcu_torture_ops sched_ops = {
        .name           = "sched"
 };
 
-static struct rcu_torture_ops sched_sync_ops = {
-       .init           = rcu_sync_torture_init,
-       .readlock       = sched_torture_read_lock,
-       .read_delay     = rcu_read_delay,  /* just reuse rcu's version. */
-       .readunlock     = sched_torture_read_unlock,
-       .completed      = rcu_no_completed,
-       .deferred_free  = rcu_sync_torture_deferred_free,
-       .sync           = synchronize_sched,
-       .cb_barrier     = NULL,
-       .fqs            = rcu_sched_force_quiescent_state,
-       .stats          = NULL,
-       .name           = "sched_sync"
-};
-
-static struct rcu_torture_ops sched_expedited_ops = {
-       .init           = rcu_sync_torture_init,
-       .readlock       = sched_torture_read_lock,
-       .read_delay     = rcu_read_delay,  /* just reuse rcu's version. */
-       .readunlock     = sched_torture_read_unlock,
-       .completed      = rcu_no_completed,
-       .deferred_free  = rcu_sync_torture_deferred_free,
-       .sync           = synchronize_sched_expedited,
-       .cb_barrier     = NULL,
-       .fqs            = rcu_sched_force_quiescent_state,
-       .stats          = NULL,
-       .irq_capable    = 1,
-       .name           = "sched_expedited"
-};
-
 /*
  * RCU torture priority-boost testing.  Runs one real-time thread per
  * CPU for moderate bursts, repeatedly registering RCU callbacks and
@@ -927,9 +798,10 @@ rcu_torture_fqs(void *arg)
 static int
 rcu_torture_writer(void *arg)
 {
+       bool exp;
        int i;
-       long oldbatch = rcu_batches_completed();
        struct rcu_torture *rp;
+       struct rcu_torture *rp1;
        struct rcu_torture *old_rp;
        static DEFINE_RCU_RANDOM(rand);
 
@@ -954,10 +826,33 @@ rcu_torture_writer(void *arg)
                                i = RCU_TORTURE_PIPE_LEN;
                        atomic_inc(&rcu_torture_wcount[i]);
                        old_rp->rtort_pipe_count++;
-                       cur_ops->deferred_free(old_rp);
+                       if (gp_normal == gp_exp)
+                               exp = !!(rcu_random(&rand) & 0x80);
+                       else
+                               exp = gp_exp;
+                       if (!exp) {
+                               cur_ops->deferred_free(old_rp);
+                       } else {
+                               cur_ops->exp_sync();
+                               list_add(&old_rp->rtort_free,
+                                        &rcu_torture_removed);
+                               list_for_each_entry_safe(rp, rp1,
+                                                        &rcu_torture_removed,
+                                                        rtort_free) {
+                                       i = rp->rtort_pipe_count;
+                                       if (i > RCU_TORTURE_PIPE_LEN)
+                                               i = RCU_TORTURE_PIPE_LEN;
+                                       atomic_inc(&rcu_torture_wcount[i]);
+                                       if (++rp->rtort_pipe_count >=
+                                           RCU_TORTURE_PIPE_LEN) {
+                                               rp->rtort_mbtest = 0;
+                                               list_del(&rp->rtort_free);
+                                               rcu_torture_free(rp);
+                                       }
+                                }
+                       }
                }
                rcutorture_record_progress(++rcu_torture_current_version);
-               oldbatch = cur_ops->completed();
                rcu_stutter_wait("rcu_torture_writer");
        } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
        VERBOSE_PRINTK_STRING("rcu_torture_writer task stopping");
@@ -983,10 +878,18 @@ rcu_torture_fakewriter(void *arg)
                schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10);
                udelay(rcu_random(&rand) & 0x3ff);
                if (cur_ops->cb_barrier != NULL &&
-                   rcu_random(&rand) % (nfakewriters * 8) == 0)
+                   rcu_random(&rand) % (nfakewriters * 8) == 0) {
                        cur_ops->cb_barrier();
-               else
+               } else if (gp_normal == gp_exp) {
+                       if (rcu_random(&rand) & 0x80)
+                               cur_ops->sync();
+                       else
+                               cur_ops->exp_sync();
+               } else if (gp_normal) {
                        cur_ops->sync();
+               } else {
+                       cur_ops->exp_sync();
+               }
                rcu_stutter_wait("rcu_torture_fakewriter");
        } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
 
@@ -1534,7 +1437,13 @@ rcu_torture_onoff(void *arg)
                                         torture_type, cpu);
                        starttime = jiffies;
                        n_online_attempts++;
-                       if (cpu_up(cpu) == 0) {
+                       ret = cpu_up(cpu);
+                       if (ret != 0) {
+                               if (verbose)
+                                       pr_alert("%s" TORTURE_FLAG
+                                                "rcu_torture_onoff task: online %d failed: errno %d\n",
+                                                torture_type, cpu, ret);
+                       } else {
                                if (verbose)
                                        pr_alert("%s" TORTURE_FLAG
                                                 "rcu_torture_onoff task: onlined %d\n",
@@ -1934,6 +1843,18 @@ rcu_torture_cleanup(void)
                rcu_torture_print_module_parms(cur_ops, "End of test: SUCCESS");
 }
 
+#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
+static void rcu_torture_leak_cb(struct rcu_head *rhp)
+{
+}
+
+static void rcu_torture_err_cb(struct rcu_head *rhp)
+{
+       /* This -might- happen due to race conditions, but is unlikely. */
+       pr_alert("rcutorture: duplicated callback was invoked.\n");
+}
+#endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+
 static int __init
 rcu_torture_init(void)
 {
@@ -1942,10 +1863,7 @@ rcu_torture_init(void)
        int firsterr = 0;
        int retval;
        static struct rcu_torture_ops *torture_ops[] =
-               { &rcu_ops, &rcu_sync_ops, &rcu_expedited_ops,
-                 &rcu_bh_ops, &rcu_bh_sync_ops, &rcu_bh_expedited_ops,
-                 &srcu_ops, &srcu_sync_ops, &srcu_expedited_ops,
-                 &sched_ops, &sched_sync_ops, &sched_expedited_ops, };
+               { &rcu_ops, &rcu_bh_ops, &srcu_ops, &sched_ops, };
 
        mutex_lock(&fullstop_mutex);
 
@@ -2163,6 +2081,28 @@ rcu_torture_init(void)
                firsterr = retval;
                goto unwind;
        }
+       if (object_debug) {
+#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
+               struct rcu_head rh1;
+               struct rcu_head rh2;
+
+               init_rcu_head_on_stack(&rh1);
+               init_rcu_head_on_stack(&rh2);
+               pr_alert("rcutorture: WARN: Duplicate call_rcu() test starting.\n");
+               local_irq_disable(); /* Make it hard to finish grace period. */
+               call_rcu(&rh1, rcu_torture_leak_cb); /* start grace period. */
+               call_rcu(&rh2, rcu_torture_err_cb);
+               call_rcu(&rh2, rcu_torture_err_cb); /* duplicate callback. */
+               local_irq_enable();
+               rcu_barrier();
+               pr_alert("rcutorture: WARN: Duplicate call_rcu() test complete.\n");
+               destroy_rcu_head_on_stack(&rh1);
+               destroy_rcu_head_on_stack(&rh2);
+#else /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+               pr_alert("rcutorture: !%s, not testing duplicate call_rcu()\n",
+                        "CONFIG_DEBUG_OBJECTS_RCU_HEAD");
+#endif /* #else #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+       }
        rcutorture_record_test_transition();
        mutex_unlock(&fullstop_mutex);
        return 0;
index 068de3a93606980268351ccaf6b19fc45573b4ea..aa3f525e2a45c0e85adb5fbc9a2e0fe3ad1e487c 100644 (file)
@@ -53,6 +53,7 @@
 #include <linux/delay.h>
 #include <linux/stop_machine.h>
 #include <linux/random.h>
+#include <linux/suspend.h>
 
 #include "rcutree.h"
 #include <trace/events/rcu.h>
@@ -208,6 +209,10 @@ EXPORT_SYMBOL_GPL(rcu_note_context_switch);
 DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = {
        .dynticks_nesting = DYNTICK_TASK_EXIT_IDLE,
        .dynticks = ATOMIC_INIT(1),
+#ifdef CONFIG_NO_HZ_FULL_SYSIDLE
+       .dynticks_idle_nesting = DYNTICK_TASK_NEST_VALUE,
+       .dynticks_idle = ATOMIC_INIT(1),
+#endif /* #ifdef CONFIG_NO_HZ_FULL_SYSIDLE */
 };
 
 static long blimit = 10;       /* Maximum callbacks per rcu_do_batch. */
@@ -226,7 +231,9 @@ module_param(jiffies_till_next_fqs, ulong, 0644);
 
 static void rcu_start_gp_advanced(struct rcu_state *rsp, struct rcu_node *rnp,
                                  struct rcu_data *rdp);
-static void force_qs_rnp(struct rcu_state *rsp, int (*f)(struct rcu_data *));
+static void force_qs_rnp(struct rcu_state *rsp,
+                        int (*f)(struct rcu_data *, bool *, unsigned long *),
+                        bool *isidle, unsigned long *maxj);
 static void force_quiescent_state(struct rcu_state *rsp);
 static int rcu_pending(int cpu);
 
@@ -411,6 +418,7 @@ void rcu_idle_enter(void)
 
        local_irq_save(flags);
        rcu_eqs_enter(false);
+       rcu_sysidle_enter(&__get_cpu_var(rcu_dynticks), 0);
        local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(rcu_idle_enter);
@@ -428,27 +436,6 @@ void rcu_user_enter(void)
 {
        rcu_eqs_enter(1);
 }
-
-/**
- * rcu_user_enter_after_irq - inform RCU that we are going to resume userspace
- * after the current irq returns.
- *
- * This is similar to rcu_user_enter() but in the context of a non-nesting
- * irq. After this call, RCU enters into idle mode when the interrupt
- * returns.
- */
-void rcu_user_enter_after_irq(void)
-{
-       unsigned long flags;
-       struct rcu_dynticks *rdtp;
-
-       local_irq_save(flags);
-       rdtp = &__get_cpu_var(rcu_dynticks);
-       /* Ensure this irq is interrupting a non-idle RCU state.  */
-       WARN_ON_ONCE(!(rdtp->dynticks_nesting & DYNTICK_TASK_MASK));
-       rdtp->dynticks_nesting = 1;
-       local_irq_restore(flags);
-}
 #endif /* CONFIG_RCU_USER_QS */
 
 /**
@@ -482,6 +469,7 @@ void rcu_irq_exit(void)
                trace_rcu_dyntick("--=", oldval, rdtp->dynticks_nesting);
        else
                rcu_eqs_enter_common(rdtp, oldval, true);
+       rcu_sysidle_enter(rdtp, 1);
        local_irq_restore(flags);
 }
 
@@ -550,6 +538,7 @@ void rcu_idle_exit(void)
 
        local_irq_save(flags);
        rcu_eqs_exit(false);
+       rcu_sysidle_exit(&__get_cpu_var(rcu_dynticks), 0);
        local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(rcu_idle_exit);
@@ -565,28 +554,6 @@ void rcu_user_exit(void)
 {
        rcu_eqs_exit(1);
 }
-
-/**
- * rcu_user_exit_after_irq - inform RCU that we won't resume to userspace
- * idle mode after the current non-nesting irq returns.
- *
- * This is similar to rcu_user_exit() but in the context of an irq.
- * This is called when the irq has interrupted a userspace RCU idle mode
- * context. When the current non-nesting interrupt returns after this call,
- * the CPU won't restore the RCU idle mode.
- */
-void rcu_user_exit_after_irq(void)
-{
-       unsigned long flags;
-       struct rcu_dynticks *rdtp;
-
-       local_irq_save(flags);
-       rdtp = &__get_cpu_var(rcu_dynticks);
-       /* Ensure we are interrupting an RCU idle mode. */
-       WARN_ON_ONCE(rdtp->dynticks_nesting & DYNTICK_TASK_NEST_MASK);
-       rdtp->dynticks_nesting += DYNTICK_TASK_EXIT_IDLE;
-       local_irq_restore(flags);
-}
 #endif /* CONFIG_RCU_USER_QS */
 
 /**
@@ -623,6 +590,7 @@ void rcu_irq_enter(void)
                trace_rcu_dyntick("++=", oldval, rdtp->dynticks_nesting);
        else
                rcu_eqs_exit_common(rdtp, oldval, true);
+       rcu_sysidle_exit(rdtp, 1);
        local_irq_restore(flags);
 }
 
@@ -746,9 +714,11 @@ static int rcu_is_cpu_rrupt_from_idle(void)
  * credit them with an implicit quiescent state.  Return 1 if this CPU
  * is in dynticks idle mode, which is an extended quiescent state.
  */
-static int dyntick_save_progress_counter(struct rcu_data *rdp)
+static int dyntick_save_progress_counter(struct rcu_data *rdp,
+                                        bool *isidle, unsigned long *maxj)
 {
        rdp->dynticks_snap = atomic_add_return(0, &rdp->dynticks->dynticks);
+       rcu_sysidle_check_cpu(rdp, isidle, maxj);
        return (rdp->dynticks_snap & 0x1) == 0;
 }
 
@@ -758,7 +728,8 @@ static int dyntick_save_progress_counter(struct rcu_data *rdp)
  * idle state since the last call to dyntick_save_progress_counter()
  * for this same CPU, or by virtue of having been offline.
  */
-static int rcu_implicit_dynticks_qs(struct rcu_data *rdp)
+static int rcu_implicit_dynticks_qs(struct rcu_data *rdp,
+                                   bool *isidle, unsigned long *maxj)
 {
        unsigned int curr;
        unsigned int snap;
@@ -1315,6 +1286,7 @@ static int rcu_gp_init(struct rcu_state *rsp)
        struct rcu_data *rdp;
        struct rcu_node *rnp = rcu_get_root(rsp);
 
+       rcu_bind_gp_kthread();
        raw_spin_lock_irq(&rnp->lock);
        rsp->gp_flags = 0; /* Clear all flags: New grace period. */
 
@@ -1379,16 +1351,25 @@ static int rcu_gp_init(struct rcu_state *rsp)
 int rcu_gp_fqs(struct rcu_state *rsp, int fqs_state_in)
 {
        int fqs_state = fqs_state_in;
+       bool isidle = 0;
+       unsigned long maxj;
        struct rcu_node *rnp = rcu_get_root(rsp);
 
        rsp->n_force_qs++;
        if (fqs_state == RCU_SAVE_DYNTICK) {
                /* Collect dyntick-idle snapshots. */
-               force_qs_rnp(rsp, dyntick_save_progress_counter);
+               if (is_sysidle_rcu_state(rsp)) {
+                       isidle = 1;
+                       maxj = jiffies - ULONG_MAX / 4;
+               }
+               force_qs_rnp(rsp, dyntick_save_progress_counter,
+                            &isidle, &maxj);
+               rcu_sysidle_report(rsp, isidle, maxj);
                fqs_state = RCU_FORCE_QS;
        } else {
                /* Handle dyntick-idle and offline CPUs. */
-               force_qs_rnp(rsp, rcu_implicit_dynticks_qs);
+               isidle = 0;
+               force_qs_rnp(rsp, rcu_implicit_dynticks_qs, &isidle, &maxj);
        }
        /* Clear flag to prevent immediate re-entry. */
        if (ACCESS_ONCE(rsp->gp_flags) & RCU_GP_FLAG_FQS) {
@@ -1558,10 +1539,12 @@ rcu_start_gp_advanced(struct rcu_state *rsp, struct rcu_node *rnp,
 
        /*
         * We can't do wakeups while holding the rnp->lock, as that
-        * could cause possible deadlocks with the rq->lock. Deter
-        * the wakeup to interrupt context.
+        * could cause possible deadlocks with the rq->lock. Defer
+        * the wakeup to interrupt context.  And don't bother waking
+        * up the running kthread.
         */
-       irq_work_queue(&rsp->wakeup_work);
+       if (current != rsp->gp_kthread)
+               irq_work_queue(&rsp->wakeup_work);
 }
 
 /*
@@ -2087,7 +2070,9 @@ void rcu_check_callbacks(int cpu, int user)
  *
  * The caller must have suppressed start of new grace periods.
  */
-static void force_qs_rnp(struct rcu_state *rsp, int (*f)(struct rcu_data *))
+static void force_qs_rnp(struct rcu_state *rsp,
+                        int (*f)(struct rcu_data *, bool *, unsigned long *),
+                        bool *isidle, unsigned long *maxj)
 {
        unsigned long bit;
        int cpu;
@@ -2110,9 +2095,12 @@ static void force_qs_rnp(struct rcu_state *rsp, int (*f)(struct rcu_data *))
                cpu = rnp->grplo;
                bit = 1;
                for (; cpu <= rnp->grphi; cpu++, bit <<= 1) {
-                       if ((rnp->qsmask & bit) != 0 &&
-                           f(per_cpu_ptr(rsp->rda, cpu)))
-                               mask |= bit;
+                       if ((rnp->qsmask & bit) != 0) {
+                               if ((rnp->qsmaskinit & bit) != 0)
+                                       *isidle = 0;
+                               if (f(per_cpu_ptr(rsp->rda, cpu), isidle, maxj))
+                                       mask |= bit;
+                       }
                }
                if (mask != 0) {
 
@@ -2286,6 +2274,13 @@ static void __call_rcu_core(struct rcu_state *rsp, struct rcu_data *rdp,
        }
 }
 
+/*
+ * RCU callback function to leak a callback.
+ */
+static void rcu_leak_callback(struct rcu_head *rhp)
+{
+}
+
 /*
  * Helper function for call_rcu() and friends.  The cpu argument will
  * normally be -1, indicating "currently running CPU".  It may specify
@@ -2300,7 +2295,12 @@ __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu),
        struct rcu_data *rdp;
 
        WARN_ON_ONCE((unsigned long)head & 0x3); /* Misaligned rcu_head! */
-       debug_rcu_head_queue(head);
+       if (debug_rcu_head_queue(head)) {
+               /* Probable double call_rcu(), so leak the callback. */
+               ACCESS_ONCE(head->func) = rcu_leak_callback;
+               WARN_ONCE(1, "__call_rcu(): Leaked duplicate callback\n");
+               return;
+       }
        head->func = func;
        head->next = NULL;
 
@@ -2930,6 +2930,7 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptible)
        rdp->blimit = blimit;
        init_callback_list(rdp);  /* Re-enable callbacks on this CPU. */
        rdp->dynticks->dynticks_nesting = DYNTICK_TASK_EXIT_IDLE;
+       rcu_sysidle_init_percpu_data(rdp->dynticks);
        atomic_set(&rdp->dynticks->dynticks,
                   (atomic_read(&rdp->dynticks->dynticks) & ~0x1) + 1);
        raw_spin_unlock(&rnp->lock);            /* irqs remain disabled. */
@@ -3015,6 +3016,25 @@ static int rcu_cpu_notify(struct notifier_block *self,
        return NOTIFY_OK;
 }
 
+static int rcu_pm_notify(struct notifier_block *self,
+                        unsigned long action, void *hcpu)
+{
+       switch (action) {
+       case PM_HIBERNATION_PREPARE:
+       case PM_SUSPEND_PREPARE:
+               if (nr_cpu_ids <= 256) /* Expediting bad for large systems. */
+                       rcu_expedited = 1;
+               break;
+       case PM_POST_HIBERNATION:
+       case PM_POST_SUSPEND:
+               rcu_expedited = 0;
+               break;
+       default:
+               break;
+       }
+       return NOTIFY_OK;
+}
+
 /*
  * Spawn the kthread that handles this RCU flavor's grace periods.
  */
@@ -3256,6 +3276,7 @@ void __init rcu_init(void)
         * or the scheduler are operational.
         */
        cpu_notifier(rcu_cpu_notify, 0);
+       pm_notifier(rcu_pm_notify, 0);
        for_each_online_cpu(cpu)
                rcu_cpu_notify(NULL, CPU_UP_PREPARE, (void *)(long)cpu);
 }
index b3832581043ceeff9c294669db5d26b58ba6a559..1602c21bb0125daaed75f1771a314a4c50073ecd 100644 (file)
@@ -88,6 +88,14 @@ struct rcu_dynticks {
                                    /* Process level is worth LLONG_MAX/2. */
        int dynticks_nmi_nesting;   /* Track NMI nesting level. */
        atomic_t dynticks;          /* Even value for idle, else odd. */
+#ifdef CONFIG_NO_HZ_FULL_SYSIDLE
+       long long dynticks_idle_nesting;
+                                   /* irq/process nesting level from idle. */
+       atomic_t dynticks_idle;     /* Even value for idle, else odd. */
+                                   /*  "Idle" excludes userspace execution. */
+       unsigned long dynticks_idle_jiffies;
+                                   /* End of last non-NMI non-idle period. */
+#endif /* #ifdef CONFIG_NO_HZ_FULL_SYSIDLE */
 #ifdef CONFIG_RCU_FAST_NO_HZ
        bool all_lazy;              /* Are all CPU's CBs lazy? */
        unsigned long nonlazy_posted;
@@ -545,6 +553,15 @@ static void rcu_boot_init_nocb_percpu_data(struct rcu_data *rdp);
 static void rcu_spawn_nocb_kthreads(struct rcu_state *rsp);
 static void rcu_kick_nohz_cpu(int cpu);
 static bool init_nocb_callback_list(struct rcu_data *rdp);
+static void rcu_sysidle_enter(struct rcu_dynticks *rdtp, int irq);
+static void rcu_sysidle_exit(struct rcu_dynticks *rdtp, int irq);
+static void rcu_sysidle_check_cpu(struct rcu_data *rdp, bool *isidle,
+                                 unsigned long *maxj);
+static bool is_sysidle_rcu_state(struct rcu_state *rsp);
+static void rcu_bind_gp_kthread(void);
+static void rcu_sysidle_report(struct rcu_state *rsp, int isidle,
+                              unsigned long maxj);
+static void rcu_sysidle_init_percpu_data(struct rcu_dynticks *rdtp);
 
 #endif /* #ifndef RCU_TREE_NONCORE */
 
index 769e12e3151b6ec9f7a557532ce5f3ae2984aaef..a4d44c3e3320310273e698a19328a6f1466663de 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/gfp.h>
 #include <linux/oom.h>
 #include <linux/smpboot.h>
-#include <linux/tick.h>
+#include "time/tick-internal.h"
 
 #define RCU_KTHREAD_PRIO 1
 
@@ -2375,3 +2375,414 @@ static void rcu_kick_nohz_cpu(int cpu)
                smp_send_reschedule(cpu);
 #endif /* #ifdef CONFIG_NO_HZ_FULL */
 }
+
+
+#ifdef CONFIG_NO_HZ_FULL_SYSIDLE
+
+/*
+ * Handle small systems specially, accelerating their transition into
+ * full idle state.  Allow arches to override this code's idea of
+ * what constitutes a "small" system.
+ */
+#ifdef CONFIG_ARCH_RCU_SYSIDLE_SMALL
+#define RCU_SYSIDLE_SMALL CONFIG_ARCH_RCU_SYSIDLE_SMALL
+#else /* #ifdef CONFIG_ARCH_RCU_SYSIDLE_SMALL */
+#define RCU_SYSIDLE_SMALL 8
+#endif
+
+/*
+ * Define RCU flavor that holds sysidle state.  This needs to be the
+ * most active flavor of RCU.
+ */
+#ifdef CONFIG_PREEMPT_RCU
+static struct rcu_state *rcu_sysidle_state = &rcu_preempt_state;
+#else /* #ifdef CONFIG_PREEMPT_RCU */
+static struct rcu_state *rcu_sysidle_state = &rcu_sched_state;
+#endif /* #else #ifdef CONFIG_PREEMPT_RCU */
+
+static int full_sysidle_state;         /* Current system-idle state. */
+#define RCU_SYSIDLE_NOT                0       /* Some CPU is not idle. */
+#define RCU_SYSIDLE_SHORT      1       /* All CPUs idle for brief period. */
+#define RCU_SYSIDLE_LONG       2       /* All CPUs idle for long enough. */
+#define RCU_SYSIDLE_FULL       3       /* All CPUs idle, ready for sysidle. */
+#define RCU_SYSIDLE_FULL_NOTED 4       /* Actually entered sysidle state. */
+
+/*
+ * Invoked to note exit from irq or task transition to idle.  Note that
+ * usermode execution does -not- count as idle here!  After all, we want
+ * to detect full-system idle states, not RCU quiescent states and grace
+ * periods.  The caller must have disabled interrupts.
+ */
+static void rcu_sysidle_enter(struct rcu_dynticks *rdtp, int irq)
+{
+       unsigned long j;
+
+       /* Adjust nesting, check for fully idle. */
+       if (irq) {
+               rdtp->dynticks_idle_nesting--;
+               WARN_ON_ONCE(rdtp->dynticks_idle_nesting < 0);
+               if (rdtp->dynticks_idle_nesting != 0)
+                       return;  /* Still not fully idle. */
+       } else {
+               if ((rdtp->dynticks_idle_nesting & DYNTICK_TASK_NEST_MASK) ==
+                   DYNTICK_TASK_NEST_VALUE) {
+                       rdtp->dynticks_idle_nesting = 0;
+               } else {
+                       rdtp->dynticks_idle_nesting -= DYNTICK_TASK_NEST_VALUE;
+                       WARN_ON_ONCE(rdtp->dynticks_idle_nesting < 0);
+                       return;  /* Still not fully idle. */
+               }
+       }
+
+       /* Record start of fully idle period. */
+       j = jiffies;
+       ACCESS_ONCE(rdtp->dynticks_idle_jiffies) = j;
+       smp_mb__before_atomic_inc();
+       atomic_inc(&rdtp->dynticks_idle);
+       smp_mb__after_atomic_inc();
+       WARN_ON_ONCE(atomic_read(&rdtp->dynticks_idle) & 0x1);
+}
+
+/*
+ * Unconditionally force exit from full system-idle state.  This is
+ * invoked when a normal CPU exits idle, but must be called separately
+ * for the timekeeping CPU (tick_do_timer_cpu).  The reason for this
+ * is that the timekeeping CPU is permitted to take scheduling-clock
+ * interrupts while the system is in system-idle state, and of course
+ * rcu_sysidle_exit() has no way of distinguishing a scheduling-clock
+ * interrupt from any other type of interrupt.
+ */
+void rcu_sysidle_force_exit(void)
+{
+       int oldstate = ACCESS_ONCE(full_sysidle_state);
+       int newoldstate;
+
+       /*
+        * Each pass through the following loop attempts to exit full
+        * system-idle state.  If contention proves to be a problem,
+        * a trylock-based contention tree could be used here.
+        */
+       while (oldstate > RCU_SYSIDLE_SHORT) {
+               newoldstate = cmpxchg(&full_sysidle_state,
+                                     oldstate, RCU_SYSIDLE_NOT);
+               if (oldstate == newoldstate &&
+                   oldstate == RCU_SYSIDLE_FULL_NOTED) {
+                       rcu_kick_nohz_cpu(tick_do_timer_cpu);
+                       return; /* We cleared it, done! */
+               }
+               oldstate = newoldstate;
+       }
+       smp_mb(); /* Order initial oldstate fetch vs. later non-idle work. */
+}
+
+/*
+ * Invoked to note entry to irq or task transition from idle.  Note that
+ * usermode execution does -not- count as idle here!  The caller must
+ * have disabled interrupts.
+ */
+static void rcu_sysidle_exit(struct rcu_dynticks *rdtp, int irq)
+{
+       /* Adjust nesting, check for already non-idle. */
+       if (irq) {
+               rdtp->dynticks_idle_nesting++;
+               WARN_ON_ONCE(rdtp->dynticks_idle_nesting <= 0);
+               if (rdtp->dynticks_idle_nesting != 1)
+                       return; /* Already non-idle. */
+       } else {
+               /*
+                * Allow for irq misnesting.  Yes, it really is possible
+                * to enter an irq handler then never leave it, and maybe
+                * also vice versa.  Handle both possibilities.
+                */
+               if (rdtp->dynticks_idle_nesting & DYNTICK_TASK_NEST_MASK) {
+                       rdtp->dynticks_idle_nesting += DYNTICK_TASK_NEST_VALUE;
+                       WARN_ON_ONCE(rdtp->dynticks_idle_nesting <= 0);
+                       return; /* Already non-idle. */
+               } else {
+                       rdtp->dynticks_idle_nesting = DYNTICK_TASK_EXIT_IDLE;
+               }
+       }
+
+       /* Record end of idle period. */
+       smp_mb__before_atomic_inc();
+       atomic_inc(&rdtp->dynticks_idle);
+       smp_mb__after_atomic_inc();
+       WARN_ON_ONCE(!(atomic_read(&rdtp->dynticks_idle) & 0x1));
+
+       /*
+        * If we are the timekeeping CPU, we are permitted to be non-idle
+        * during a system-idle state.  This must be the case, because
+        * the timekeeping CPU has to take scheduling-clock interrupts
+        * during the time that the system is transitioning to full
+        * system-idle state.  This means that the timekeeping CPU must
+        * invoke rcu_sysidle_force_exit() directly if it does anything
+        * more than take a scheduling-clock interrupt.
+        */
+       if (smp_processor_id() == tick_do_timer_cpu)
+               return;
+
+       /* Update system-idle state: We are clearly no longer fully idle! */
+       rcu_sysidle_force_exit();
+}
+
+/*
+ * Check to see if the current CPU is idle.  Note that usermode execution
+ * does not count as idle.  The caller must have disabled interrupts.
+ */
+static void rcu_sysidle_check_cpu(struct rcu_data *rdp, bool *isidle,
+                                 unsigned long *maxj)
+{
+       int cur;
+       unsigned long j;
+       struct rcu_dynticks *rdtp = rdp->dynticks;
+
+       /*
+        * If some other CPU has already reported non-idle, if this is
+        * not the flavor of RCU that tracks sysidle state, or if this
+        * is an offline or the timekeeping CPU, nothing to do.
+        */
+       if (!*isidle || rdp->rsp != rcu_sysidle_state ||
+           cpu_is_offline(rdp->cpu) || rdp->cpu == tick_do_timer_cpu)
+               return;
+       WARN_ON_ONCE(smp_processor_id() != tick_do_timer_cpu);
+
+       /* Pick up current idle and NMI-nesting counter and check. */
+       cur = atomic_read(&rdtp->dynticks_idle);
+       if (cur & 0x1) {
+               *isidle = 0; /* We are not idle! */
+               return;
+       }
+       smp_mb(); /* Read counters before timestamps. */
+
+       /* Pick up timestamps. */
+       j = ACCESS_ONCE(rdtp->dynticks_idle_jiffies);
+       /* If this CPU entered idle more recently, update maxj timestamp. */
+       if (ULONG_CMP_LT(*maxj, j))
+               *maxj = j;
+}
+
+/*
+ * Is this the flavor of RCU that is handling full-system idle?
+ */
+static bool is_sysidle_rcu_state(struct rcu_state *rsp)
+{
+       return rsp == rcu_sysidle_state;
+}
+
+/*
+ * Bind the grace-period kthread for the sysidle flavor of RCU to the
+ * timekeeping CPU.
+ */
+static void rcu_bind_gp_kthread(void)
+{
+       int cpu = ACCESS_ONCE(tick_do_timer_cpu);
+
+       if (cpu < 0 || cpu >= nr_cpu_ids)
+               return;
+       if (raw_smp_processor_id() != cpu)
+               set_cpus_allowed_ptr(current, cpumask_of(cpu));
+}
+
+/*
+ * Return a delay in jiffies based on the number of CPUs, rcu_node
+ * leaf fanout, and jiffies tick rate.  The idea is to allow larger
+ * systems more time to transition to full-idle state in order to
+ * avoid the cache thrashing that otherwise occur on the state variable.
+ * Really small systems (less than a couple of tens of CPUs) should
+ * instead use a single global atomically incremented counter, and later
+ * versions of this will automatically reconfigure themselves accordingly.
+ */
+static unsigned long rcu_sysidle_delay(void)
+{
+       if (nr_cpu_ids <= RCU_SYSIDLE_SMALL)
+               return 0;
+       return DIV_ROUND_UP(nr_cpu_ids * HZ, rcu_fanout_leaf * 1000);
+}
+
+/*
+ * Advance the full-system-idle state.  This is invoked when all of
+ * the non-timekeeping CPUs are idle.
+ */
+static void rcu_sysidle(unsigned long j)
+{
+       /* Check the current state. */
+       switch (ACCESS_ONCE(full_sysidle_state)) {
+       case RCU_SYSIDLE_NOT:
+
+               /* First time all are idle, so note a short idle period. */
+               ACCESS_ONCE(full_sysidle_state) = RCU_SYSIDLE_SHORT;
+               break;
+
+       case RCU_SYSIDLE_SHORT:
+
+               /*
+                * Idle for a bit, time to advance to next state?
+                * cmpxchg failure means race with non-idle, let them win.
+                */
+               if (ULONG_CMP_GE(jiffies, j + rcu_sysidle_delay()))
+                       (void)cmpxchg(&full_sysidle_state,
+                                     RCU_SYSIDLE_SHORT, RCU_SYSIDLE_LONG);
+               break;
+
+       case RCU_SYSIDLE_LONG:
+
+               /*
+                * Do an additional check pass before advancing to full.
+                * cmpxchg failure means race with non-idle, let them win.
+                */
+               if (ULONG_CMP_GE(jiffies, j + rcu_sysidle_delay()))
+                       (void)cmpxchg(&full_sysidle_state,
+                                     RCU_SYSIDLE_LONG, RCU_SYSIDLE_FULL);
+               break;
+
+       default:
+               break;
+       }
+}
+
+/*
+ * Found a non-idle non-timekeeping CPU, so kick the system-idle state
+ * back to the beginning.
+ */
+static void rcu_sysidle_cancel(void)
+{
+       smp_mb();
+       ACCESS_ONCE(full_sysidle_state) = RCU_SYSIDLE_NOT;
+}
+
+/*
+ * Update the sysidle state based on the results of a force-quiescent-state
+ * scan of the CPUs' dyntick-idle state.
+ */
+static void rcu_sysidle_report(struct rcu_state *rsp, int isidle,
+                              unsigned long maxj)
+{
+       if (rsp != rcu_sysidle_state)
+               return;  /* Wrong flavor, ignore. */
+       if (isidle)
+               rcu_sysidle(maxj);    /* More idle! */
+       else
+               rcu_sysidle_cancel(); /* Idle is over. */
+}
+
+/* Callback and function for forcing an RCU grace period. */
+struct rcu_sysidle_head {
+       struct rcu_head rh;
+       int inuse;
+};
+
+static void rcu_sysidle_cb(struct rcu_head *rhp)
+{
+       struct rcu_sysidle_head *rshp;
+
+       smp_mb();  /* grace period precedes setting inuse. */
+       rshp = container_of(rhp, struct rcu_sysidle_head, rh);
+       ACCESS_ONCE(rshp->inuse) = 0;
+}
+
+/*
+ * Check to see if the system is fully idle, other than the timekeeping CPU.
+ * The caller must have disabled interrupts.
+ */
+bool rcu_sys_is_idle(void)
+{
+       static struct rcu_sysidle_head rsh;
+       int rss = ACCESS_ONCE(full_sysidle_state);
+
+       if (WARN_ON_ONCE(smp_processor_id() != tick_do_timer_cpu))
+               return false;
+
+       /* Handle small-system case by doing a full scan of CPUs. */
+       if (nr_cpu_ids <= RCU_SYSIDLE_SMALL) {
+               int oldrss = rss - 1;
+
+               /*
+                * One pass to advance to each state up to _FULL.
+                * Give up if any pass fails to advance the state.
+                */
+               while (rss < RCU_SYSIDLE_FULL && oldrss < rss) {
+                       int cpu;
+                       bool isidle = true;
+                       unsigned long maxj = jiffies - ULONG_MAX / 4;
+                       struct rcu_data *rdp;
+
+                       /* Scan all the CPUs looking for nonidle CPUs. */
+                       for_each_possible_cpu(cpu) {
+                               rdp = per_cpu_ptr(rcu_sysidle_state->rda, cpu);
+                               rcu_sysidle_check_cpu(rdp, &isidle, &maxj);
+                               if (!isidle)
+                                       break;
+                       }
+                       rcu_sysidle_report(rcu_sysidle_state, isidle, maxj);
+                       oldrss = rss;
+                       rss = ACCESS_ONCE(full_sysidle_state);
+               }
+       }
+
+       /* If this is the first observation of an idle period, record it. */
+       if (rss == RCU_SYSIDLE_FULL) {
+               rss = cmpxchg(&full_sysidle_state,
+                             RCU_SYSIDLE_FULL, RCU_SYSIDLE_FULL_NOTED);
+               return rss == RCU_SYSIDLE_FULL;
+       }
+
+       smp_mb(); /* ensure rss load happens before later caller actions. */
+
+       /* If already fully idle, tell the caller (in case of races). */
+       if (rss == RCU_SYSIDLE_FULL_NOTED)
+               return true;
+
+       /*
+        * If we aren't there yet, and a grace period is not in flight,
+        * initiate a grace period.  Either way, tell the caller that
+        * we are not there yet.
+        */
+       if (nr_cpu_ids > RCU_SYSIDLE_SMALL &&
+           !rcu_gp_in_progress(rcu_sysidle_state) &&
+           !rsh.inuse && xchg(&rsh.inuse, 1) == 0)
+               call_rcu(&rsh.rh, rcu_sysidle_cb);
+       return false;
+}
+
+/*
+ * Initialize dynticks sysidle state for CPUs coming online.
+ */
+static void rcu_sysidle_init_percpu_data(struct rcu_dynticks *rdtp)
+{
+       rdtp->dynticks_idle_nesting = DYNTICK_TASK_NEST_VALUE;
+}
+
+#else /* #ifdef CONFIG_NO_HZ_FULL_SYSIDLE */
+
+static void rcu_sysidle_enter(struct rcu_dynticks *rdtp, int irq)
+{
+}
+
+static void rcu_sysidle_exit(struct rcu_dynticks *rdtp, int irq)
+{
+}
+
+static void rcu_sysidle_check_cpu(struct rcu_data *rdp, bool *isidle,
+                                 unsigned long *maxj)
+{
+}
+
+static bool is_sysidle_rcu_state(struct rcu_state *rsp)
+{
+       return false;
+}
+
+static void rcu_bind_gp_kthread(void)
+{
+}
+
+static void rcu_sysidle_report(struct rcu_state *rsp, int isidle,
+                              unsigned long maxj)
+{
+}
+
+static void rcu_sysidle_init_percpu_data(struct rcu_dynticks *rdtp)
+{
+}
+
+#endif /* #else #ifdef CONFIG_NO_HZ_FULL_SYSIDLE */
index b7c32cb7bfebbd5912f06a421decb87b15c34bf9..6e17978515af73b2ae6661ce657072205c823929 100644 (file)
@@ -933,6 +933,8 @@ static int effective_prio(struct task_struct *p)
 /**
  * task_curr - is this task currently executing on a CPU?
  * @p: the task in question.
+ *
+ * Return: 1 if the task is currently executing. 0 otherwise.
  */
 inline int task_curr(const struct task_struct *p)
 {
@@ -976,13 +978,6 @@ void check_preempt_curr(struct rq *rq, struct task_struct *p, int flags)
                rq->skip_clock_update = 1;
 }
 
-static ATOMIC_NOTIFIER_HEAD(task_migration_notifier);
-
-void register_task_migration_notifier(struct notifier_block *n)
-{
-       atomic_notifier_chain_register(&task_migration_notifier, n);
-}
-
 #ifdef CONFIG_SMP
 void set_task_cpu(struct task_struct *p, unsigned int new_cpu)
 {
@@ -1013,18 +1008,10 @@ void set_task_cpu(struct task_struct *p, unsigned int new_cpu)
        trace_sched_migrate_task(p, new_cpu);
 
        if (task_cpu(p) != new_cpu) {
-               struct task_migration_notifier tmn;
-
                if (p->sched_class->migrate_task_rq)
                        p->sched_class->migrate_task_rq(p, new_cpu);
                p->se.nr_migrations++;
                perf_sw_event(PERF_COUNT_SW_CPU_MIGRATIONS, 1, NULL, 0);
-
-               tmn.task = p;
-               tmn.from_cpu = task_cpu(p);
-               tmn.to_cpu = new_cpu;
-
-               atomic_notifier_call_chain(&task_migration_notifier, 0, &tmn);
        }
 
        __set_task_cpu(p, new_cpu);
@@ -1482,7 +1469,7 @@ static void ttwu_queue(struct task_struct *p, int cpu)
  * the simpler "current->state = TASK_RUNNING" to mark yourself
  * runnable without the overhead of this.
  *
- * Returns %true if @p was woken up, %false if it was already running
+ * Return: %true if @p was woken up, %false if it was already running.
  * or @state didn't match @p's state.
  */
 static int
@@ -1577,8 +1564,9 @@ out:
  * @p: The process to be woken up.
  *
  * Attempt to wake up the nominated process and move it to the set of runnable
- * processes.  Returns 1 if the process was woken up, 0 if it was already
- * running.
+ * processes.
+ *
+ * Return: 1 if the process was woken up, 0 if it was already running.
  *
  * It may be assumed that this function implies a write memory barrier before
  * changing the task state if and only if any tasks are woken up.
@@ -2191,6 +2179,8 @@ void scheduler_tick(void)
  * This makes sure that uptime, CFS vruntime, load
  * balancing, etc... continue to move forward, even
  * with a very low granularity.
+ *
+ * Return: Maximum deferment in nanoseconds.
  */
 u64 scheduler_tick_max_deferment(void)
 {
@@ -2660,7 +2650,7 @@ void __wake_up_sync_key(wait_queue_head_t *q, unsigned int mode,
        if (unlikely(!q))
                return;
 
-       if (unlikely(!nr_exclusive))
+       if (unlikely(nr_exclusive != 1))
                wake_flags = 0;
 
        spin_lock_irqsave(&q->lock, flags);
@@ -2796,8 +2786,8 @@ EXPORT_SYMBOL(wait_for_completion);
  * specified timeout to expire. The timeout is in jiffies. It is not
  * interruptible.
  *
- * The return value is 0 if timed out, and positive (at least 1, or number of
- * jiffies left till timeout) if completed.
+ * Return: 0 if timed out, and positive (at least 1, or number of jiffies left
+ * till timeout) if completed.
  */
 unsigned long __sched
 wait_for_completion_timeout(struct completion *x, unsigned long timeout)
@@ -2829,8 +2819,8 @@ EXPORT_SYMBOL(wait_for_completion_io);
  * specified timeout to expire. The timeout is in jiffies. It is not
  * interruptible. The caller is accounted as waiting for IO.
  *
- * The return value is 0 if timed out, and positive (at least 1, or number of
- * jiffies left till timeout) if completed.
+ * Return: 0 if timed out, and positive (at least 1, or number of jiffies left
+ * till timeout) if completed.
  */
 unsigned long __sched
 wait_for_completion_io_timeout(struct completion *x, unsigned long timeout)
@@ -2846,7 +2836,7 @@ EXPORT_SYMBOL(wait_for_completion_io_timeout);
  * This waits for completion of a specific task to be signaled. It is
  * interruptible.
  *
- * The return value is -ERESTARTSYS if interrupted, 0 if completed.
+ * Return: -ERESTARTSYS if interrupted, 0 if completed.
  */
 int __sched wait_for_completion_interruptible(struct completion *x)
 {
@@ -2865,8 +2855,8 @@ EXPORT_SYMBOL(wait_for_completion_interruptible);
  * This waits for either a completion of a specific task to be signaled or for a
  * specified timeout to expire. It is interruptible. The timeout is in jiffies.
  *
- * The return value is -ERESTARTSYS if interrupted, 0 if timed out,
- * positive (at least 1, or number of jiffies left till timeout) if completed.
+ * Return: -ERESTARTSYS if interrupted, 0 if timed out, positive (at least 1,
+ * or number of jiffies left till timeout) if completed.
  */
 long __sched
 wait_for_completion_interruptible_timeout(struct completion *x,
@@ -2883,7 +2873,7 @@ EXPORT_SYMBOL(wait_for_completion_interruptible_timeout);
  * This waits to be signaled for completion of a specific task. It can be
  * interrupted by a kill signal.
  *
- * The return value is -ERESTARTSYS if interrupted, 0 if completed.
+ * Return: -ERESTARTSYS if interrupted, 0 if completed.
  */
 int __sched wait_for_completion_killable(struct completion *x)
 {
@@ -2903,8 +2893,8 @@ EXPORT_SYMBOL(wait_for_completion_killable);
  * signaled or for a specified timeout to expire. It can be
  * interrupted by a kill signal. The timeout is in jiffies.
  *
- * The return value is -ERESTARTSYS if interrupted, 0 if timed out,
- * positive (at least 1, or number of jiffies left till timeout) if completed.
+ * Return: -ERESTARTSYS if interrupted, 0 if timed out, positive (at least 1,
+ * or number of jiffies left till timeout) if completed.
  */
 long __sched
 wait_for_completion_killable_timeout(struct completion *x,
@@ -2918,7 +2908,7 @@ EXPORT_SYMBOL(wait_for_completion_killable_timeout);
  *     try_wait_for_completion - try to decrement a completion without blocking
  *     @x:     completion structure
  *
- *     Returns: 0 if a decrement cannot be done without blocking
+ *     Return: 0 if a decrement cannot be done without blocking
  *              1 if a decrement succeeded.
  *
  *     If a completion is being used as a counting completion,
@@ -2945,7 +2935,7 @@ EXPORT_SYMBOL(try_wait_for_completion);
  *     completion_done - Test to see if a completion has any waiters
  *     @x:     completion structure
  *
- *     Returns: 0 if there are waiters (wait_for_completion() in progress)
+ *     Return: 0 if there are waiters (wait_for_completion() in progress)
  *              1 if there are no waiters.
  *
  */
@@ -3182,7 +3172,7 @@ SYSCALL_DEFINE1(nice, int, increment)
  * task_prio - return the priority value of a given task.
  * @p: the task in question.
  *
- * This is the priority value as seen by users in /proc.
+ * Return: The priority value as seen by users in /proc.
  * RT tasks are offset by -200. Normal tasks are centered
  * around 0, value goes from -16 to +15.
  */
@@ -3194,6 +3184,8 @@ int task_prio(const struct task_struct *p)
 /**
  * task_nice - return the nice value of a given task.
  * @p: the task in question.
+ *
+ * Return: The nice value [ -20 ... 0 ... 19 ].
  */
 int task_nice(const struct task_struct *p)
 {
@@ -3204,6 +3196,8 @@ EXPORT_SYMBOL(task_nice);
 /**
  * idle_cpu - is a given cpu idle currently?
  * @cpu: the processor in question.
+ *
+ * Return: 1 if the CPU is currently idle. 0 otherwise.
  */
 int idle_cpu(int cpu)
 {
@@ -3226,6 +3220,8 @@ int idle_cpu(int cpu)
 /**
  * idle_task - return the idle task for a given cpu.
  * @cpu: the processor in question.
+ *
+ * Return: The idle task for the cpu @cpu.
  */
 struct task_struct *idle_task(int cpu)
 {
@@ -3235,6 +3231,8 @@ struct task_struct *idle_task(int cpu)
 /**
  * find_process_by_pid - find a process with a matching PID value.
  * @pid: the pid in question.
+ *
+ * The task of @pid, if found. %NULL otherwise.
  */
 static struct task_struct *find_process_by_pid(pid_t pid)
 {
@@ -3432,6 +3430,8 @@ recheck:
  * @policy: new policy.
  * @param: structure containing the new RT priority.
  *
+ * Return: 0 on success. An error code otherwise.
+ *
  * NOTE that the task may be already dead.
  */
 int sched_setscheduler(struct task_struct *p, int policy,
@@ -3451,6 +3451,8 @@ EXPORT_SYMBOL_GPL(sched_setscheduler);
  * current context has permission.  For example, this is needed in
  * stop_machine(): we create temporary high priority worker threads,
  * but our caller might not have that capability.
+ *
+ * Return: 0 on success. An error code otherwise.
  */
 int sched_setscheduler_nocheck(struct task_struct *p, int policy,
                               const struct sched_param *param)
@@ -3485,6 +3487,8 @@ do_sched_setscheduler(pid_t pid, int policy, struct sched_param __user *param)
  * @pid: the pid in question.
  * @policy: new policy.
  * @param: structure containing the new RT priority.
+ *
+ * Return: 0 on success. An error code otherwise.
  */
 SYSCALL_DEFINE3(sched_setscheduler, pid_t, pid, int, policy,
                struct sched_param __user *, param)
@@ -3500,6 +3504,8 @@ SYSCALL_DEFINE3(sched_setscheduler, pid_t, pid, int, policy,
  * sys_sched_setparam - set/change the RT priority of a thread
  * @pid: the pid in question.
  * @param: structure containing the new RT priority.
+ *
+ * Return: 0 on success. An error code otherwise.
  */
 SYSCALL_DEFINE2(sched_setparam, pid_t, pid, struct sched_param __user *, param)
 {
@@ -3509,6 +3515,9 @@ SYSCALL_DEFINE2(sched_setparam, pid_t, pid, struct sched_param __user *, param)
 /**
  * sys_sched_getscheduler - get the policy (scheduling class) of a thread
  * @pid: the pid in question.
+ *
+ * Return: On success, the policy of the thread. Otherwise, a negative error
+ * code.
  */
 SYSCALL_DEFINE1(sched_getscheduler, pid_t, pid)
 {
@@ -3535,6 +3544,9 @@ SYSCALL_DEFINE1(sched_getscheduler, pid_t, pid)
  * sys_sched_getparam - get the RT priority of a thread
  * @pid: the pid in question.
  * @param: structure containing the RT priority.
+ *
+ * Return: On success, 0 and the RT priority is in @param. Otherwise, an error
+ * code.
  */
 SYSCALL_DEFINE2(sched_getparam, pid_t, pid, struct sched_param __user *, param)
 {
@@ -3659,6 +3671,8 @@ static int get_user_cpu_mask(unsigned long __user *user_mask_ptr, unsigned len,
  * @pid: pid of the process
  * @len: length in bytes of the bitmask pointed to by user_mask_ptr
  * @user_mask_ptr: user-space pointer to the new cpu mask
+ *
+ * Return: 0 on success. An error code otherwise.
  */
 SYSCALL_DEFINE3(sched_setaffinity, pid_t, pid, unsigned int, len,
                unsigned long __user *, user_mask_ptr)
@@ -3710,6 +3724,8 @@ out_unlock:
  * @pid: pid of the process
  * @len: length in bytes of the bitmask pointed to by user_mask_ptr
  * @user_mask_ptr: user-space pointer to hold the current cpu mask
+ *
+ * Return: 0 on success. An error code otherwise.
  */
 SYSCALL_DEFINE3(sched_getaffinity, pid_t, pid, unsigned int, len,
                unsigned long __user *, user_mask_ptr)
@@ -3744,6 +3760,8 @@ SYSCALL_DEFINE3(sched_getaffinity, pid_t, pid, unsigned int, len,
  *
  * This function yields the current CPU to other tasks. If there are no
  * other threads running on this CPU then this function will return.
+ *
+ * Return: 0.
  */
 SYSCALL_DEFINE0(sched_yield)
 {
@@ -3869,7 +3887,7 @@ EXPORT_SYMBOL(yield);
  * It's the caller's job to ensure that the target task struct
  * can't go away on us before we can do any checks.
  *
- * Returns:
+ * Return:
  *     true (>0) if we indeed boosted the target task.
  *     false (0) if we failed to boost the target.
  *     -ESRCH if there's no task to yield to.
@@ -3972,8 +3990,9 @@ long __sched io_schedule_timeout(long timeout)
  * sys_sched_get_priority_max - return maximum RT priority.
  * @policy: scheduling class.
  *
- * this syscall returns the maximum rt_priority that can be used
- * by a given scheduling class.
+ * Return: On success, this syscall returns the maximum
+ * rt_priority that can be used by a given scheduling class.
+ * On failure, a negative error code is returned.
  */
 SYSCALL_DEFINE1(sched_get_priority_max, int, policy)
 {
@@ -3997,8 +4016,9 @@ SYSCALL_DEFINE1(sched_get_priority_max, int, policy)
  * sys_sched_get_priority_min - return minimum RT priority.
  * @policy: scheduling class.
  *
- * this syscall returns the minimum rt_priority that can be used
- * by a given scheduling class.
+ * Return: On success, this syscall returns the minimum
+ * rt_priority that can be used by a given scheduling class.
+ * On failure, a negative error code is returned.
  */
 SYSCALL_DEFINE1(sched_get_priority_min, int, policy)
 {
@@ -4024,6 +4044,9 @@ SYSCALL_DEFINE1(sched_get_priority_min, int, policy)
  *
  * this syscall writes the default timeslice value of a given process
  * into the user-space timespec buffer. A value of '0' means infinity.
+ *
+ * Return: On success, 0 and the timeslice is in @interval. Otherwise,
+ * an error code.
  */
 SYSCALL_DEFINE2(sched_rr_get_interval, pid_t, pid,
                struct timespec __user *, interval)
@@ -5083,18 +5106,23 @@ static void destroy_sched_domains(struct sched_domain *sd, int cpu)
  * two cpus are in the same cache domain, see cpus_share_cache().
  */
 DEFINE_PER_CPU(struct sched_domain *, sd_llc);
+DEFINE_PER_CPU(int, sd_llc_size);
 DEFINE_PER_CPU(int, sd_llc_id);
 
 static void update_top_cache_domain(int cpu)
 {
        struct sched_domain *sd;
        int id = cpu;
+       int size = 1;
 
        sd = highest_flag_domain(cpu, SD_SHARE_PKG_RESOURCES);
-       if (sd)
+       if (sd) {
                id = cpumask_first(sched_domain_span(sd));
+               size = cpumask_weight(sched_domain_span(sd));
+       }
 
        rcu_assign_pointer(per_cpu(sd_llc, cpu), sd);
+       per_cpu(sd_llc_size, cpu) = size;
        per_cpu(sd_llc_id, cpu) = id;
 }
 
@@ -6632,6 +6660,8 @@ void normalize_rt_tasks(void)
  * @cpu: the processor in question.
  *
  * ONLY VALID WHEN THE WHOLE SYSTEM IS STOPPED!
+ *
+ * Return: The current task for @cpu.
  */
 struct task_struct *curr_task(int cpu)
 {
index 1095e878a46fdbe4a7224eb07a68cf1fc90c2530..8b836b376d9129760066326eabf5040f72b2e4f3 100644 (file)
@@ -62,7 +62,7 @@ static int convert_prio(int prio)
  * any discrepancies created by racing against the uncertainty of the current
  * priority configuration.
  *
- * Returns: (int)bool - CPUs were found
+ * Return: (int)bool - CPUs were found
  */
 int cpupri_find(struct cpupri *cp, struct task_struct *p,
                struct cpumask *lowest_mask)
@@ -203,7 +203,7 @@ void cpupri_set(struct cpupri *cp, int cpu, int newpri)
  * cpupri_init - initialize the cpupri structure
  * @cp: The cpupri context
  *
- * Returns: -ENOMEM if memory fails.
+ * Return: -ENOMEM on memory allocation failure.
  */
 int cpupri_init(struct cpupri *cp)
 {
index bb456f44b7b1cdbfc6b4e6be3b04cd6f22da6b4d..84e3b7ce92b3b3eee83f0ae5f46b5b195804af90 100644 (file)
@@ -3017,6 +3017,23 @@ static unsigned long cpu_avg_load_per_task(int cpu)
        return 0;
 }
 
+static void record_wakee(struct task_struct *p)
+{
+       /*
+        * Rough decay (wiping) for cost saving, don't worry
+        * about the boundary, really active task won't care
+        * about the loss.
+        */
+       if (jiffies > current->wakee_flip_decay_ts + HZ) {
+               current->wakee_flips = 0;
+               current->wakee_flip_decay_ts = jiffies;
+       }
+
+       if (current->last_wakee != p) {
+               current->last_wakee = p;
+               current->wakee_flips++;
+       }
+}
 
 static void task_waking_fair(struct task_struct *p)
 {
@@ -3037,6 +3054,7 @@ static void task_waking_fair(struct task_struct *p)
 #endif
 
        se->vruntime -= min_vruntime;
+       record_wakee(p);
 }
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
@@ -3155,6 +3173,28 @@ static inline unsigned long effective_load(struct task_group *tg, int cpu,
 
 #endif
 
+static int wake_wide(struct task_struct *p)
+{
+       int factor = this_cpu_read(sd_llc_size);
+
+       /*
+        * Yeah, it's the switching-frequency, could means many wakee or
+        * rapidly switch, use factor here will just help to automatically
+        * adjust the loose-degree, so bigger node will lead to more pull.
+        */
+       if (p->wakee_flips > factor) {
+               /*
+                * wakee is somewhat hot, it needs certain amount of cpu
+                * resource, so if waker is far more hot, prefer to leave
+                * it alone.
+                */
+               if (current->wakee_flips > (factor * p->wakee_flips))
+                       return 1;
+       }
+
+       return 0;
+}
+
 static int wake_affine(struct sched_domain *sd, struct task_struct *p, int sync)
 {
        s64 this_load, load;
@@ -3164,6 +3204,13 @@ static int wake_affine(struct sched_domain *sd, struct task_struct *p, int sync)
        unsigned long weight;
        int balanced;
 
+       /*
+        * If we wake multiple tasks be careful to not bounce
+        * ourselves around too much.
+        */
+       if (wake_wide(p))
+               return 0;
+
        idx       = sd->wake_idx;
        this_cpu  = smp_processor_id();
        prev_cpu  = task_cpu(p);
@@ -4171,47 +4218,48 @@ static void update_blocked_averages(int cpu)
 }
 
 /*
- * Compute the cpu's hierarchical load factor for each task group.
+ * Compute the hierarchical load factor for cfs_rq and all its ascendants.
  * This needs to be done in a top-down fashion because the load of a child
  * group is a fraction of its parents load.
  */
-static int tg_load_down(struct task_group *tg, void *data)
-{
-       unsigned long load;
-       long cpu = (long)data;
-
-       if (!tg->parent) {
-               load = cpu_rq(cpu)->avg.load_avg_contrib;
-       } else {
-               load = tg->parent->cfs_rq[cpu]->h_load;
-               load = div64_ul(load * tg->se[cpu]->avg.load_avg_contrib,
-                               tg->parent->cfs_rq[cpu]->runnable_load_avg + 1);
-       }
-
-       tg->cfs_rq[cpu]->h_load = load;
-
-       return 0;
-}
-
-static void update_h_load(long cpu)
+static void update_cfs_rq_h_load(struct cfs_rq *cfs_rq)
 {
-       struct rq *rq = cpu_rq(cpu);
+       struct rq *rq = rq_of(cfs_rq);
+       struct sched_entity *se = cfs_rq->tg->se[cpu_of(rq)];
        unsigned long now = jiffies;
+       unsigned long load;
 
-       if (rq->h_load_throttle == now)
+       if (cfs_rq->last_h_load_update == now)
                return;
 
-       rq->h_load_throttle = now;
+       cfs_rq->h_load_next = NULL;
+       for_each_sched_entity(se) {
+               cfs_rq = cfs_rq_of(se);
+               cfs_rq->h_load_next = se;
+               if (cfs_rq->last_h_load_update == now)
+                       break;
+       }
 
-       rcu_read_lock();
-       walk_tg_tree(tg_load_down, tg_nop, (void *)cpu);
-       rcu_read_unlock();
+       if (!se) {
+               cfs_rq->h_load = rq->avg.load_avg_contrib;
+               cfs_rq->last_h_load_update = now;
+       }
+
+       while ((se = cfs_rq->h_load_next) != NULL) {
+               load = cfs_rq->h_load;
+               load = div64_ul(load * se->avg.load_avg_contrib,
+                               cfs_rq->runnable_load_avg + 1);
+               cfs_rq = group_cfs_rq(se);
+               cfs_rq->h_load = load;
+               cfs_rq->last_h_load_update = now;
+       }
 }
 
 static unsigned long task_h_load(struct task_struct *p)
 {
        struct cfs_rq *cfs_rq = task_cfs_rq(p);
 
+       update_cfs_rq_h_load(cfs_rq);
        return div64_ul(p->se.avg.load_avg_contrib * cfs_rq->h_load,
                        cfs_rq->runnable_load_avg + 1);
 }
@@ -4220,10 +4268,6 @@ static inline void update_blocked_averages(int cpu)
 {
 }
 
-static inline void update_h_load(long cpu)
-{
-}
-
 static unsigned long task_h_load(struct task_struct *p)
 {
        return p->se.avg.load_avg_contrib;
@@ -4280,6 +4324,8 @@ struct sg_lb_stats {
  * get_sd_load_idx - Obtain the load index for a given sched domain.
  * @sd: The sched_domain whose load_idx is to be obtained.
  * @idle: The Idle status of the CPU for whose sd load_icx is obtained.
+ *
+ * Return: The load index.
  */
 static inline int get_sd_load_idx(struct sched_domain *sd,
                                        enum cpu_idle_type idle)
@@ -4574,6 +4620,9 @@ static inline void update_sg_lb_stats(struct lb_env *env,
  *
  * Determine if @sg is a busier group than the previously selected
  * busiest group.
+ *
+ * Return: %true if @sg is a busier group than the previously selected
+ * busiest group. %false otherwise.
  */
 static bool update_sd_pick_busiest(struct lb_env *env,
                                   struct sd_lb_stats *sds,
@@ -4691,7 +4740,7 @@ static inline void update_sd_lb_stats(struct lb_env *env,
  * assuming lower CPU number will be equivalent to lower a SMT thread
  * number.
  *
- * Returns 1 when packing is required and a task should be moved to
+ * Return: 1 when packing is required and a task should be moved to
  * this CPU.  The amount of the imbalance is returned in *imbalance.
  *
  * @env: The load balancing environment.
@@ -4869,7 +4918,7 @@ static inline void calculate_imbalance(struct lb_env *env, struct sd_lb_stats *s
  * @balance: Pointer to a variable indicating if this_cpu
  *     is the appropriate cpu to perform load balancing at this_level.
  *
- * Returns:    - the busiest group if imbalance exists.
+ * Return:     - The busiest group if imbalance exists.
  *             - If no imbalance and user has opted for power-savings balance,
  *                return the least loaded group whose CPUs can be
  *                put to idle by rebalancing its tasks onto our group.
@@ -5108,7 +5157,6 @@ redo:
                env.src_rq    = busiest;
                env.loop_max  = min(sysctl_sched_nr_migrate, busiest->nr_running);
 
-               update_h_load(env.src_cpu);
 more_balance:
                local_irq_save(flags);
                double_rq_lock(env.dst_rq, busiest);
@@ -5889,11 +5937,9 @@ static void switched_from_fair(struct rq *rq, struct task_struct *p)
        * and ensure we don't carry in an old decay_count if we
        * switch back.
        */
-       if (p->se.avg.decay_count) {
-               struct cfs_rq *cfs_rq = cfs_rq_of(&p->se);
-               __synchronize_entity_decay(&p->se);
-               subtract_blocked_load_contrib(cfs_rq,
-                               p->se.avg.load_avg_contrib);
+       if (se->avg.decay_count) {
+               __synchronize_entity_decay(se);
+               subtract_blocked_load_contrib(cfs_rq, se->avg.load_avg_contrib);
        }
 #endif
 }
index ef0a7b2439dde25bdd3d4ee54c4801364e09607d..4c1cb8029feb484d81cd1c5f8c9c3ecd03d21795 100644 (file)
@@ -285,7 +285,6 @@ struct cfs_rq {
        /* Required to track per-cpu representation of a task_group */
        u32 tg_runnable_contrib;
        unsigned long tg_load_contrib;
-#endif /* CONFIG_FAIR_GROUP_SCHED */
 
        /*
         *   h_load = weight * f(tg)
@@ -294,6 +293,9 @@ struct cfs_rq {
         * this group.
         */
        unsigned long h_load;
+       u64 last_h_load_update;
+       struct sched_entity *h_load_next;
+#endif /* CONFIG_FAIR_GROUP_SCHED */
 #endif /* CONFIG_SMP */
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
@@ -429,9 +431,6 @@ struct rq {
 #ifdef CONFIG_FAIR_GROUP_SCHED
        /* list of leaf cfs_rq on this cpu: */
        struct list_head leaf_cfs_rq_list;
-#ifdef CONFIG_SMP
-       unsigned long h_load_throttle;
-#endif /* CONFIG_SMP */
 #endif /* CONFIG_FAIR_GROUP_SCHED */
 
 #ifdef CONFIG_RT_GROUP_SCHED
@@ -595,6 +594,7 @@ static inline struct sched_domain *highest_flag_domain(int cpu, int flag)
 }
 
 DECLARE_PER_CPU(struct sched_domain *, sd_llc);
+DECLARE_PER_CPU(int, sd_llc_size);
 DECLARE_PER_CPU(int, sd_llc_id);
 
 struct sched_group_power {
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 70f27e89012b29d18b4aeb9c6e5c367d1b3955a5..a613c2a925182ce288bb4fe9611c41dab34e25c4 100644 (file)
@@ -134,6 +134,29 @@ config NO_HZ_FULL_ALL
         Note the boot CPU will still be kept outside the range to
         handle the timekeeping duty.
 
+config NO_HZ_FULL_SYSIDLE
+       bool "Detect full-system idle state for full dynticks system"
+       depends on NO_HZ_FULL
+       default n
+       help
+        At least one CPU must keep the scheduling-clock tick running
+        for timekeeping purposes whenever there is a non-idle CPU,
+        where "non-idle" includes CPUs with a single runnable task
+        in adaptive-idle mode.  Because the underlying adaptive-tick
+        support cannot distinguish between all CPUs being idle and
+        all CPUs each running a single task in adaptive-idle mode,
+        the underlying support simply ensures that there is always
+        a CPU handling the scheduling-clock tick, whether or not all
+        CPUs are idle.  This Kconfig option enables scalable detection
+        of the all-CPUs-idle state, thus allowing the scheduling-clock
+        tick to be disabled when all CPUs are idle.  Note that scalable
+        detection of the all-CPUs-idle state means that larger systems
+        will be slower to declare the all-CPUs-idle state.
+
+        Say Y if you would like to help debug all-CPUs-idle detection.
+
+        Say N if you are unsure.
+
 config NO_HZ
        bool "Old Idle dynticks config"
        depends on !ARCH_USES_GETTIMEOFFSET && GENERIC_CLOCKEVENTS
index e80183f4a6c4f3d6abea4b6d7720e381381259e0..e8a1516cc0a36d3c247d2bd4a18ef6d69f17b42c 100644 (file)
@@ -182,7 +182,8 @@ static bool can_stop_full_tick(void)
                 * Don't allow the user to think they can get
                 * full NO_HZ with this machine.
                 */
-               WARN_ONCE(1, "NO_HZ FULL will not work with unstable sched clock");
+               WARN_ONCE(have_nohz_full_mask,
+                         "NO_HZ FULL will not work with unstable sched clock");
                return false;
        }
 #endif
@@ -343,8 +344,6 @@ static int tick_nohz_init_all(void)
 
 void __init tick_nohz_init(void)
 {
-       int cpu;
-
        if (!have_nohz_full_mask) {
                if (tick_nohz_init_all() < 0)
                        return;
@@ -827,13 +826,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 +927,6 @@ void tick_nohz_idle_exit(void)
 
        ts->inidle = 0;
 
-       /* Cancel the timer because CPU already waken up from the C-states*/
-       menu_hrtimer_cancel();
        if (ts->idle_active || ts->tick_stopped)
                now = ktime_get();
 
index 8ce9eefc5bb4f6aae3ffa520152a51eb033adb1e..6de8cbd91fa57e8e63fc19b8c4eb5b96899755fb 100644 (file)
@@ -3384,6 +3384,12 @@ ftrace_match_addr(struct ftrace_hash *hash, unsigned long ip, int remove)
        return add_hash_entry(hash, ip);
 }
 
+static void ftrace_ops_update_code(struct ftrace_ops *ops)
+{
+       if (ops->flags & FTRACE_OPS_FL_ENABLED && ftrace_enabled)
+               ftrace_run_update_code(FTRACE_UPDATE_CALLS);
+}
+
 static int
 ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len,
                unsigned long ip, int remove, int reset, int enable)
@@ -3426,9 +3432,8 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len,
 
        mutex_lock(&ftrace_lock);
        ret = ftrace_hash_move(ops, enable, orig_hash, hash);
-       if (!ret && ops->flags & FTRACE_OPS_FL_ENABLED
-           && ftrace_enabled)
-               ftrace_run_update_code(FTRACE_UPDATE_CALLS);
+       if (!ret)
+               ftrace_ops_update_code(ops);
 
        mutex_unlock(&ftrace_lock);
 
@@ -3655,9 +3660,8 @@ int ftrace_regex_release(struct inode *inode, struct file *file)
                mutex_lock(&ftrace_lock);
                ret = ftrace_hash_move(iter->ops, filter_hash,
                                       orig_hash, iter->hash);
-               if (!ret && (iter->ops->flags & FTRACE_OPS_FL_ENABLED)
-                   && ftrace_enabled)
-                       ftrace_run_update_code(FTRACE_UPDATE_CALLS);
+               if (!ret)
+                       ftrace_ops_update_code(iter->ops);
 
                mutex_unlock(&ftrace_lock);
        }
@@ -4057,6 +4061,63 @@ static int ftrace_process_locs(struct module *mod,
 
 #ifdef CONFIG_MODULES
 
+/*
+ * If the filter is cleared, then all functions may end up being
+ * traced. We need to pass that information down to update the
+ * records.
+ */
+static bool remove_rec_entry(struct ftrace_hash *hash, struct dyn_ftrace *rec)
+{
+       struct ftrace_func_entry *entry;
+
+       entry = ftrace_lookup_ip(hash, rec->ip);
+       if (!entry)
+               return false;
+
+       free_hash_entry(hash, entry);
+
+       /* If we cleared the hash, then we now trace all functions */
+       return ftrace_hash_empty(hash);
+}
+
+static void clear_recs(struct ftrace_ops *ops, struct ftrace_page *pg)
+{
+       struct dyn_ftrace *rec;
+       bool update = false;
+       int i;
+
+       for (i = 0; i < pg->index; i++) {
+               rec = &pg->records[i];
+
+               /* If the filter hash gets cleared, we trace all functions */
+               if (remove_rec_entry(ops->filter_hash, rec))
+                       update = true;
+               remove_rec_entry(ops->notrace_hash, rec);
+       }
+
+       if (update) {
+               ftrace_hash_rec_enable(ops, 1);
+               if (ftrace_enabled)
+                       ftrace_run_update_code(FTRACE_UPDATE_CALLS);
+       }
+}
+
+static bool ops_has_filter(struct ftrace_ops *ops)
+{
+       return !ftrace_hash_empty(ops->filter_hash) ||
+               !ftrace_hash_empty(ops->notrace_hash);
+}
+
+static void clear_hashes(struct ftrace_page *pg)
+{
+       struct ftrace_ops *ops;
+
+       for (ops = ftrace_ops_list; ops != &ftrace_list_end; ops = ops->next) {
+               if ((ops->flags & FTRACE_OPS_FL_ENABLED) && ops_has_filter(ops))
+                       clear_recs(ops, pg);
+       }
+}
+
 #define next_to_ftrace_page(p) container_of(p, struct ftrace_page, next)
 
 void ftrace_release_mod(struct module *mod)
@@ -4090,6 +4151,9 @@ void ftrace_release_mod(struct module *mod)
                        if (pg == ftrace_pages)
                                ftrace_pages = next_to_ftrace_page(last_pg);
 
+                       /* Make sure no hashes reference this module record */
+                       clear_hashes(pg);
+
                        *last_pg = pg->next;
                        order = get_count_order(pg->size / ENTRIES_PER_PAGE);
                        free_pages((unsigned long)pg->records, order);
index 898f868833f2d4df0d80838f9461385b5eedcd77..a67c913e2f9f148b7a857f5d9d27070ff003e8ea 100644 (file)
@@ -409,33 +409,42 @@ static void put_system(struct ftrace_subsystem_dir *dir)
        mutex_unlock(&event_mutex);
 }
 
-/*
- * Open and update trace_array ref count.
- * Must have the current trace_array passed to it.
- */
-static int tracing_open_generic_file(struct inode *inode, struct file *filp)
+static void remove_subsystem(struct ftrace_subsystem_dir *dir)
 {
-       struct ftrace_event_file *file = inode->i_private;
-       struct trace_array *tr = file->tr;
-       int ret;
+       if (!dir)
+               return;
 
-       if (trace_array_get(tr) < 0)
-               return -ENODEV;
+       if (!--dir->nr_events) {
+               debugfs_remove_recursive(dir->entry);
+               list_del(&dir->list);
+               __put_system_dir(dir);
+       }
+}
 
-       ret = tracing_open_generic(inode, filp);
-       if (ret < 0)
-               trace_array_put(tr);
-       return ret;
+static void *event_file_data(struct file *filp)
+{
+       return ACCESS_ONCE(file_inode(filp)->i_private);
 }
 
-static int tracing_release_generic_file(struct inode *inode, struct file *filp)
+static void remove_event_file_dir(struct ftrace_event_file *file)
 {
-       struct ftrace_event_file *file = inode->i_private;
-       struct trace_array *tr = file->tr;
+       struct dentry *dir = file->dir;
+       struct dentry *child;
 
-       trace_array_put(tr);
+       if (dir) {
+               spin_lock(&dir->d_lock);        /* probably unneeded */
+               list_for_each_entry(child, &dir->d_subdirs, d_u.d_child) {
+                       if (child->d_inode)     /* probably unneeded */
+                               child->d_inode->i_private = NULL;
+               }
+               spin_unlock(&dir->d_lock);
 
-       return 0;
+               debugfs_remove_recursive(dir);
+       }
+
+       list_del(&file->list);
+       remove_subsystem(file->system);
+       kmem_cache_free(file_cachep, file);
 }
 
 /*
@@ -679,15 +688,25 @@ static ssize_t
 event_enable_read(struct file *filp, char __user *ubuf, size_t cnt,
                  loff_t *ppos)
 {
-       struct ftrace_event_file *file = filp->private_data;
+       struct ftrace_event_file *file;
+       unsigned long flags;
        char buf[4] = "0";
 
-       if (file->flags & FTRACE_EVENT_FL_ENABLED &&
-           !(file->flags & FTRACE_EVENT_FL_SOFT_DISABLED))
+       mutex_lock(&event_mutex);
+       file = event_file_data(filp);
+       if (likely(file))
+               flags = file->flags;
+       mutex_unlock(&event_mutex);
+
+       if (!file)
+               return -ENODEV;
+
+       if (flags & FTRACE_EVENT_FL_ENABLED &&
+           !(flags & FTRACE_EVENT_FL_SOFT_DISABLED))
                strcpy(buf, "1");
 
-       if (file->flags & FTRACE_EVENT_FL_SOFT_DISABLED ||
-           file->flags & FTRACE_EVENT_FL_SOFT_MODE)
+       if (flags & FTRACE_EVENT_FL_SOFT_DISABLED ||
+           flags & FTRACE_EVENT_FL_SOFT_MODE)
                strcat(buf, "*");
 
        strcat(buf, "\n");
@@ -699,13 +718,10 @@ static ssize_t
 event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt,
                   loff_t *ppos)
 {
-       struct ftrace_event_file *file = filp->private_data;
+       struct ftrace_event_file *file;
        unsigned long val;
        int ret;
 
-       if (!file)
-               return -EINVAL;
-
        ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
        if (ret)
                return ret;
@@ -717,8 +733,11 @@ event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt,
        switch (val) {
        case 0:
        case 1:
+               ret = -ENODEV;
                mutex_lock(&event_mutex);
-               ret = ftrace_event_enable_disable(file, val);
+               file = event_file_data(filp);
+               if (likely(file))
+                       ret = ftrace_event_enable_disable(file, val);
                mutex_unlock(&event_mutex);
                break;
 
@@ -825,7 +844,7 @@ enum {
 
 static void *f_next(struct seq_file *m, void *v, loff_t *pos)
 {
-       struct ftrace_event_call *call = m->private;
+       struct ftrace_event_call *call = event_file_data(m->private);
        struct list_head *common_head = &ftrace_common_fields;
        struct list_head *head = trace_get_fields(call);
        struct list_head *node = v;
@@ -857,7 +876,7 @@ static void *f_next(struct seq_file *m, void *v, loff_t *pos)
 
 static int f_show(struct seq_file *m, void *v)
 {
-       struct ftrace_event_call *call = m->private;
+       struct ftrace_event_call *call = event_file_data(m->private);
        struct ftrace_event_field *field;
        const char *array_descriptor;
 
@@ -910,6 +929,11 @@ static void *f_start(struct seq_file *m, loff_t *pos)
        void *p = (void *)FORMAT_HEADER;
        loff_t l = 0;
 
+       /* ->stop() is called even if ->start() fails */
+       mutex_lock(&event_mutex);
+       if (!event_file_data(m->private))
+               return ERR_PTR(-ENODEV);
+
        while (l < *pos && p)
                p = f_next(m, p, &l);
 
@@ -918,6 +942,7 @@ static void *f_start(struct seq_file *m, loff_t *pos)
 
 static void f_stop(struct seq_file *m, void *p)
 {
+       mutex_unlock(&event_mutex);
 }
 
 static const struct seq_operations trace_format_seq_ops = {
@@ -929,7 +954,6 @@ static const struct seq_operations trace_format_seq_ops = {
 
 static int trace_format_open(struct inode *inode, struct file *file)
 {
-       struct ftrace_event_call *call = inode->i_private;
        struct seq_file *m;
        int ret;
 
@@ -938,7 +962,7 @@ static int trace_format_open(struct inode *inode, struct file *file)
                return ret;
 
        m = file->private_data;
-       m->private = call;
+       m->private = file;
 
        return 0;
 }
@@ -946,14 +970,18 @@ static int trace_format_open(struct inode *inode, struct file *file)
 static ssize_t
 event_id_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
 {
-       struct ftrace_event_call *call = filp->private_data;
+       int id = (long)event_file_data(filp);
        char buf[32];
        int len;
 
        if (*ppos)
                return 0;
 
-       len = sprintf(buf, "%d\n", call->event.type);
+       if (unlikely(!id))
+               return -ENODEV;
+
+       len = sprintf(buf, "%d\n", id);
+
        return simple_read_from_buffer(ubuf, cnt, ppos, buf, len);
 }
 
@@ -961,21 +989,28 @@ static ssize_t
 event_filter_read(struct file *filp, char __user *ubuf, size_t cnt,
                  loff_t *ppos)
 {
-       struct ftrace_event_call *call = filp->private_data;
+       struct ftrace_event_call *call;
        struct trace_seq *s;
-       int r;
+       int r = -ENODEV;
 
        if (*ppos)
                return 0;
 
        s = kmalloc(sizeof(*s), GFP_KERNEL);
+
        if (!s)
                return -ENOMEM;
 
        trace_seq_init(s);
 
-       print_event_filter(call, s);
-       r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, s->len);
+       mutex_lock(&event_mutex);
+       call = event_file_data(filp);
+       if (call)
+               print_event_filter(call, s);
+       mutex_unlock(&event_mutex);
+
+       if (call)
+               r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, s->len);
 
        kfree(s);
 
@@ -986,9 +1021,9 @@ static ssize_t
 event_filter_write(struct file *filp, const char __user *ubuf, size_t cnt,
                   loff_t *ppos)
 {
-       struct ftrace_event_call *call = filp->private_data;
+       struct ftrace_event_call *call;
        char *buf;
-       int err;
+       int err = -ENODEV;
 
        if (cnt >= PAGE_SIZE)
                return -EINVAL;
@@ -1003,7 +1038,12 @@ event_filter_write(struct file *filp, const char __user *ubuf, size_t cnt,
        }
        buf[cnt] = '\0';
 
-       err = apply_event_filter(call, buf);
+       mutex_lock(&event_mutex);
+       call = event_file_data(filp);
+       if (call)
+               err = apply_event_filter(call, buf);
+       mutex_unlock(&event_mutex);
+
        free_page((unsigned long) buf);
        if (err < 0)
                return err;
@@ -1225,10 +1265,9 @@ static const struct file_operations ftrace_set_event_fops = {
 };
 
 static const struct file_operations ftrace_enable_fops = {
-       .open = tracing_open_generic_file,
+       .open = tracing_open_generic,
        .read = event_enable_read,
        .write = event_enable_write,
-       .release = tracing_release_generic_file,
        .llseek = default_llseek,
 };
 
@@ -1240,7 +1279,6 @@ static const struct file_operations ftrace_event_format_fops = {
 };
 
 static const struct file_operations ftrace_event_id_fops = {
-       .open = tracing_open_generic,
        .read = event_id_read,
        .llseek = default_llseek,
 };
@@ -1488,8 +1526,8 @@ event_create_dir(struct dentry *parent,
 
 #ifdef CONFIG_PERF_EVENTS
        if (call->event.type && call->class->reg)
-               trace_create_file("id", 0444, file->dir, call,
-                                 id);
+               trace_create_file("id", 0444, file->dir,
+                                 (void *)(long)call->event.type, id);
 #endif
 
        /*
@@ -1514,33 +1552,16 @@ event_create_dir(struct dentry *parent,
        return 0;
 }
 
-static void remove_subsystem(struct ftrace_subsystem_dir *dir)
-{
-       if (!dir)
-               return;
-
-       if (!--dir->nr_events) {
-               debugfs_remove_recursive(dir->entry);
-               list_del(&dir->list);
-               __put_system_dir(dir);
-       }
-}
-
 static void remove_event_from_tracers(struct ftrace_event_call *call)
 {
        struct ftrace_event_file *file;
        struct trace_array *tr;
 
        do_for_each_event_file_safe(tr, file) {
-
                if (file->event_call != call)
                        continue;
 
-               list_del(&file->list);
-               debugfs_remove_recursive(file->dir);
-               remove_subsystem(file->system);
-               kmem_cache_free(file_cachep, file);
-
+               remove_event_file_dir(file);
                /*
                 * The do_for_each_event_file_safe() is
                 * a double loop. After finding the call for this
@@ -2270,12 +2291,8 @@ __trace_remove_event_dirs(struct trace_array *tr)
 {
        struct ftrace_event_file *file, *next;
 
-       list_for_each_entry_safe(file, next, &tr->events, list) {
-               list_del(&file->list);
-               debugfs_remove_recursive(file->dir);
-               remove_subsystem(file->system);
-               kmem_cache_free(file_cachep, file);
-       }
+       list_for_each_entry_safe(file, next, &tr->events, list)
+               remove_event_file_dir(file);
 }
 
 static void
index 0c7b75a8acc8f9ccad53d75bc6a3fe0da425ae9f..97daa8cf958df8e73c9fa8090f89cbaf4e63893e 100644 (file)
@@ -637,17 +637,15 @@ static void append_filter_err(struct filter_parse_state *ps,
        free_page((unsigned long) buf);
 }
 
+/* caller must hold event_mutex */
 void print_event_filter(struct ftrace_event_call *call, struct trace_seq *s)
 {
-       struct event_filter *filter;
+       struct event_filter *filter = call->filter;
 
-       mutex_lock(&event_mutex);
-       filter = call->filter;
        if (filter && filter->filter_string)
                trace_seq_printf(s, "%s\n", filter->filter_string);
        else
                trace_seq_puts(s, "none\n");
-       mutex_unlock(&event_mutex);
 }
 
 void print_subsystem_event_filter(struct event_subsystem *system,
@@ -1841,23 +1839,22 @@ static int create_system_filter(struct event_subsystem *system,
        return err;
 }
 
+/* caller must hold event_mutex */
 int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
 {
        struct event_filter *filter;
-       int err = 0;
-
-       mutex_lock(&event_mutex);
+       int err;
 
        if (!strcmp(strstrip(filter_string), "0")) {
                filter_disable(call);
                filter = call->filter;
                if (!filter)
-                       goto out_unlock;
+                       return 0;
                RCU_INIT_POINTER(call->filter, NULL);
                /* Make sure the filter is not being used */
                synchronize_sched();
                __free_filter(filter);
-               goto out_unlock;
+               return 0;
        }
 
        err = create_filter(call, filter_string, true, &filter);
@@ -1884,8 +1881,6 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
                        __free_filter(tmp);
                }
        }
-out_unlock:
-       mutex_unlock(&event_mutex);
 
        return err;
 }
index 0b72e816b8d0126f0a3e72c1f3a2496fc3545030..38c4255a518e7c090b514fc49f4bd9d460ae8eb1 100644 (file)
@@ -2817,6 +2817,19 @@ already_gone:
        return false;
 }
 
+static bool __flush_work(struct work_struct *work)
+{
+       struct wq_barrier barr;
+
+       if (start_flush_work(work, &barr)) {
+               wait_for_completion(&barr.done);
+               destroy_work_on_stack(&barr.work);
+               return true;
+       } else {
+               return false;
+       }
+}
+
 /**
  * flush_work - wait for a work to finish executing the last queueing instance
  * @work: the work to flush
@@ -2830,18 +2843,10 @@ already_gone:
  */
 bool flush_work(struct work_struct *work)
 {
-       struct wq_barrier barr;
-
        lock_map_acquire(&work->lockdep_map);
        lock_map_release(&work->lockdep_map);
 
-       if (start_flush_work(work, &barr)) {
-               wait_for_completion(&barr.done);
-               destroy_work_on_stack(&barr.work);
-               return true;
-       } else {
-               return false;
-       }
+       return __flush_work(work);
 }
 EXPORT_SYMBOL_GPL(flush_work);
 
@@ -4756,7 +4761,14 @@ long work_on_cpu(int cpu, long (*fn)(void *), void *arg)
 
        INIT_WORK_ONSTACK(&wfc.work, work_for_cpu_fn);
        schedule_work_on(cpu, &wfc.work);
-       flush_work(&wfc.work);
+
+       /*
+        * The work item is on-stack and can't lead to deadlock through
+        * flushing.  Use __flush_work() to avoid spurious lockdep warnings
+        * when work_on_cpu()s are nested.
+        */
+       __flush_work(&wfc.work);
+
        return wfc.ret;
 }
 EXPORT_SYMBOL_GPL(work_on_cpu);
index 37061ede8b8124e7fa59cd0963ede7ba27979007..bf2c8b1043d8bb5a8b44d19a139842ffb5514067 100644 (file)
@@ -381,19 +381,21 @@ void debug_object_init_on_stack(void *addr, struct debug_obj_descr *descr)
  * debug_object_activate - debug checks when an object is activated
  * @addr:      address of the object
  * @descr:     pointer to an object specific debug description structure
+ * Returns 0 for success, -EINVAL for check failed.
  */
-void debug_object_activate(void *addr, struct debug_obj_descr *descr)
+int debug_object_activate(void *addr, struct debug_obj_descr *descr)
 {
        enum debug_obj_state state;
        struct debug_bucket *db;
        struct debug_obj *obj;
        unsigned long flags;
+       int ret;
        struct debug_obj o = { .object = addr,
                               .state = ODEBUG_STATE_NOTAVAILABLE,
                               .descr = descr };
 
        if (!debug_objects_enabled)
-               return;
+               return 0;
 
        db = get_bucket((unsigned long) addr);
 
@@ -405,23 +407,26 @@ void debug_object_activate(void *addr, struct debug_obj_descr *descr)
                case ODEBUG_STATE_INIT:
                case ODEBUG_STATE_INACTIVE:
                        obj->state = ODEBUG_STATE_ACTIVE;
+                       ret = 0;
                        break;
 
                case ODEBUG_STATE_ACTIVE:
                        debug_print_object(obj, "activate");
                        state = obj->state;
                        raw_spin_unlock_irqrestore(&db->lock, flags);
-                       debug_object_fixup(descr->fixup_activate, addr, state);
-                       return;
+                       ret = debug_object_fixup(descr->fixup_activate, addr, state);
+                       return ret ? -EINVAL : 0;
 
                case ODEBUG_STATE_DESTROYED:
                        debug_print_object(obj, "activate");
+                       ret = -EINVAL;
                        break;
                default:
+                       ret = 0;
                        break;
                }
                raw_spin_unlock_irqrestore(&db->lock, flags);
-               return;
+               return ret;
        }
 
        raw_spin_unlock_irqrestore(&db->lock, flags);
@@ -431,8 +436,11 @@ void debug_object_activate(void *addr, struct debug_obj_descr *descr)
         * true or not.
         */
        if (debug_object_fixup(descr->fixup_activate, addr,
-                          ODEBUG_STATE_NOTAVAILABLE))
+                          ODEBUG_STATE_NOTAVAILABLE)) {
                debug_print_object(&o, "activate");
+               return -EINVAL;
+       }
+       return 0;
 }
 
 /**
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 8028dcc6615c6bbd533adf060ea3d9db36b9a48c..256bfd0f6007dc3e40e6575318d120554d06a49e 100644 (file)
@@ -519,3 +519,27 @@ config MEM_SOFT_DIRTY
          it can be cleared by hands.
 
          See Documentation/vm/soft-dirty.txt for more details.
+
+config CMA
+       bool "Contiguous Memory Allocator"
+       depends on HAVE_MEMBLOCK
+       select MIGRATION
+       select MEMORY_ISOLATION
+       help
+         This enables the Contiguous Memory Allocator which allows other
+         subsystems to allocate big physically-contiguous blocks of memory.
+         CMA reserves a region of memory and allows only movable pages to
+         be allocated from it. This way, the kernel can use the memory for
+         pagecache and when a subsystem requests for contiguous area, the
+         allocated pages are migrated away to serve the contiguous request.
+
+         If unsure, say "n".
+
+config CMA_DEBUG
+       bool "CMA debug messages (DEVELOPMENT)"
+       depends on DEBUG_KERNEL && CMA
+       help
+         Turns on debug messages in CMA.  This produces KERN_DEBUG
+         messages for every CMA call as well as various messages while
+         processing calls such as dma_alloc_from_contiguous().
+         This option does not affect warning and error messages.
index 2c13aa7a0164101a360e4f776090f6b183aab5ab..55d7c8026ab078215afff2fe3b088143bcd43f2d 100644 (file)
@@ -1286,7 +1286,10 @@ static void memory_failure_work_func(struct work_struct *work)
                spin_unlock_irqrestore(&mf_cpu->lock, proc_flags);
                if (!gotten)
                        break;
-               memory_failure(entry.pfn, entry.trapno, entry.flags);
+               if (entry.flags & MF_SOFT_OFFLINE)
+                       soft_offline_page(pfn_to_page(entry.pfn), entry.flags);
+               else
+                       memory_failure(entry.pfn, entry.trapno, entry.flags);
        }
 }
 
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 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..37162eb88f07ee9960c8bd4c347f2658f04d7823 100644 (file)
@@ -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..b821b199b333429828a493ce0fb99239225a65e9 100644 (file)
@@ -605,7 +605,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;
 
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..50d86b3e3941f948e0e36a2a1480e06a37b824b4 100644 (file)
@@ -244,22 +244,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 69af490cce4437bdc107f8b5b1216780b4c126af..4b99c9a27044e1ce1988ababe9b7c65b1ff425b7 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++;
 
@@ -1126,7 +1129,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;
 
@@ -1204,7 +1206,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;
 
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..43347f1299433383fd612eb5b3d7742325e843bf 100644 (file)
@@ -333,11 +333,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 +345,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)
 {
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..dfd9f5d56ae0037982cebfff3b2d5f321aaf2ce9 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)
 {
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 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 20e02d2605ecb2f10f5f74ab6f00cbd8fb852615..3df4d4ccf4405b640689bbedd322b225dfc2594d 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 :
index 548d716c5f62ac8c9d90d0959d19022714f9585d..85e8de1bc7fd8897434af2f3da5b17ea80d38f89 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>
@@ -2425,6 +2426,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 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 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 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..c27e81392398d643081f67a0efd637fb1cc32af7 100644 (file)
@@ -499,7 +499,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 +510,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 +2631,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 +2851,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 5fc9c7a68d8d102aef37b7b13ab1dd772553a9cb..8b6c77389a040f656b08afe34be4427e88339468 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);
 
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 a8c891aa24645e9a45d2f8e47712b0698a29b216..74ab1f74abcddcb056d9dbe847a1364ab7bceb04 100644 (file)
@@ -285,7 +285,6 @@ static inline struct rt6_info *ip6_dst_alloc(struct net *net,
                rt6_init_peer(rt, table ? &table->tb6_peers : net->ipv6.peers);
                rt->rt6i_genid = rt_genid(net);
                INIT_LIST_HEAD(&rt->rt6i_siblings);
-               rt->rt6i_nsiblings = 0;
        }
        return rt;
 }
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..43dd7525bfcba54c02dbd9dde2bd89cfc2d29c97 100644 (file)
@@ -666,6 +666,8 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy,
                        if (sta->sdata->dev != dev)
                                continue;
 
+                       sinfo.filled = 0;
+                       sta_set_sinfo(sta, &sinfo);
                        i = 0;
                        ADD_STA_STATS(sta);
                }
index 3b7bfc01ee36e922927958be79e1ec7414c8a3d6..22290a929b94595445865baecdb692aff5e0be9c 100644 (file)
@@ -229,6 +229,10 @@ void ieee80211_mps_sta_status_update(struct sta_info *sta)
        enum nl80211_mesh_power_mode pm;
        bool do_buffer;
 
+       /* For non-assoc STA, prevent buffering or frame transmission */
+       if (sta->sta_state < IEEE80211_STA_ASSOC)
+               return;
+
        /*
         * use peer-specific power mode if peering is established and the
         * peer's power mode is known
index 7fc5d0d8149a53f2a20377499841657dd9a97c7c..340126204343a063902bb205675cc14bea743a4c 100644 (file)
@@ -99,10 +99,13 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
        }
        mutex_unlock(&local->sta_mtx);
 
-       /* remove all interfaces */
+       /* remove all interfaces that were created in the driver */
        list_for_each_entry(sdata, &local->interfaces, list) {
-               if (!ieee80211_sdata_running(sdata))
+               if (!ieee80211_sdata_running(sdata) ||
+                   sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+                   sdata->vif.type == NL80211_IFTYPE_MONITOR)
                        continue;
+
                drv_remove_interface(local, sdata);
        }
 
index ac7ef5414bdede030d289a81946eaabc7b5d7a88..e6512e2ffd200223cd5cb75090802a98f544bb7d 100644 (file)
@@ -290,7 +290,7 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
        struct minstrel_rate *msr, *mr;
        unsigned int ndx;
        bool mrr_capable;
-       bool prev_sample = mi->prev_sample;
+       bool prev_sample;
        int delta;
        int sampling_ratio;
 
@@ -314,6 +314,7 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
                        (mi->sample_count + mi->sample_deferred / 2);
 
        /* delta < 0: no sampling required */
+       prev_sample = mi->prev_sample;
        mi->prev_sample = false;
        if (delta < 0 || (!mrr_capable && prev_sample))
                return;
index 5b2d3012b9830aef8d9101c26ba761402993b382..f5aed963b22e62cd997872d1068bfb6c45eeda7a 100644 (file)
@@ -804,10 +804,18 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
 
        sample_group = &minstrel_mcs_groups[sample_idx / MCS_GROUP_RATES];
        info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
+       rate->count = 1;
+
+       if (sample_idx / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) {
+               int idx = sample_idx % ARRAY_SIZE(mp->cck_rates);
+               rate->idx = mp->cck_rates[idx];
+               rate->flags = 0;
+               return;
+       }
+
        rate->idx = sample_idx % MCS_GROUP_RATES +
                    (sample_group->streams - 1) * MCS_GROUP_RATES;
        rate->flags = IEEE80211_TX_RC_MCS | sample_group->flags;
-       rate->count = 1;
 }
 
 static void
index 23dbcfc69b3b7f09ffc35c81d03dddc38d36da5a..2c5a79bd3777f5c313d3205a1154ef6b714a8d4d 100644 (file)
@@ -936,8 +936,14 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
 
-       /* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */
-       if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) {
+       /*
+        * Drop duplicate 802.11 retransmissions
+        * (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery")
+        */
+       if (rx->skb->len >= 24 && rx->sta &&
+           !ieee80211_is_ctl(hdr->frame_control) &&
+           !ieee80211_is_qos_nullfunc(hdr->frame_control) &&
+           !is_multicast_ether_addr(hdr->addr1)) {
                if (unlikely(ieee80211_has_retry(hdr->frame_control) &&
                             rx->sta->last_seq_ctrl[rx->seqno_idx] ==
                             hdr->seq_ctrl)) {
index 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 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 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 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 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 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 1cc47aca7f05baee3e7ffdf18a4e002b2d62279d..25d217d90807f05f6a56945cb89dcd7b3314a53d 100644 (file)
@@ -4770,9 +4770,9 @@ do {                                                                          \
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding, 0, 1,
                                  mask, NL80211_MESHCONF_FORWARDING,
                                  nla_get_u8);
-       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, 1, 255,
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, -255, 0,
                                  mask, NL80211_MESHCONF_RSSI_THRESHOLD,
-                                 nla_get_u32);
+                                 nla_get_s32);
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg, ht_opmode, 0, 16,
                                  mask, NL80211_MESHCONF_HT_OPMODE,
                                  nla_get_u16);
@@ -6613,12 +6613,14 @@ EXPORT_SYMBOL(cfg80211_testmode_alloc_event_skb);
 
 void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
 {
+       struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
        void *hdr = ((void **)skb->cb)[1];
        struct nlattr *data = ((void **)skb->cb)[2];
 
        nla_nest_end(skb, data);
        genlmsg_end(skb, hdr);
-       genlmsg_multicast(skb, 0, nl80211_testmode_mcgrp.id, gfp);
+       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), skb, 0,
+                               nl80211_testmode_mcgrp.id, gfp);
 }
 EXPORT_SYMBOL(cfg80211_testmode_event);
 #endif
@@ -10064,7 +10066,8 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
 
        genlmsg_end(msg, hdr);
 
-       genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp);
+       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+                               nl80211_mlme_mcgrp.id, gfp);
        return;
 
  nla_put_failure:
index 5a24c986f34be27e61613f0deb421a35efc61533..de06d5d1287f97b6f6c8a1fd6b3e59371d80ae3e 100644 (file)
@@ -2247,10 +2247,13 @@ int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env)
 
 void wiphy_regulatory_register(struct wiphy *wiphy)
 {
+       struct regulatory_request *lr;
+
        if (!reg_dev_ignore_cell_hint(wiphy))
                reg_num_devs_support_basehint++;
 
-       wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE);
+       lr = get_last_request();
+       wiphy_update_regulatory(wiphy, lr->initiator);
 }
 
 void wiphy_regulatory_deregister(struct wiphy *wiphy)
@@ -2279,7 +2282,9 @@ void wiphy_regulatory_deregister(struct wiphy *wiphy)
 static void reg_timeout_work(struct work_struct *work)
 {
        REG_DBG_PRINT("Timeout while waiting for CRDA to reply, restoring regulatory settings\n");
+       rtnl_lock();
        restore_regulatory_settings(true);
+       rtnl_unlock();
 }
 
 int __init regulatory_init(void)
index 1d3cfb1a3f28b3a74a32c1c629ddbcba7fb30def..81c8a10d743c04fb76981498b42588f9b821f33f 100644 (file)
@@ -34,8 +34,10 @@ struct cfg80211_conn {
                CFG80211_CONN_SCAN_AGAIN,
                CFG80211_CONN_AUTHENTICATE_NEXT,
                CFG80211_CONN_AUTHENTICATING,
+               CFG80211_CONN_AUTH_FAILED,
                CFG80211_CONN_ASSOCIATE_NEXT,
                CFG80211_CONN_ASSOCIATING,
+               CFG80211_CONN_ASSOC_FAILED,
                CFG80211_CONN_DEAUTH,
                CFG80211_CONN_CONNECTED,
        } state;
@@ -164,6 +166,8 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
                                          NULL, 0,
                                          params->key, params->key_len,
                                          params->key_idx, NULL, 0);
+       case CFG80211_CONN_AUTH_FAILED:
+               return -ENOTCONN;
        case CFG80211_CONN_ASSOCIATE_NEXT:
                BUG_ON(!rdev->ops->assoc);
                wdev->conn->state = CFG80211_CONN_ASSOCIATING;
@@ -188,10 +192,17 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
                                             WLAN_REASON_DEAUTH_LEAVING,
                                             false);
                return err;
+       case CFG80211_CONN_ASSOC_FAILED:
+               cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
+                                    NULL, 0,
+                                    WLAN_REASON_DEAUTH_LEAVING, false);
+               return -ENOTCONN;
        case CFG80211_CONN_DEAUTH:
                cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
                                     NULL, 0,
                                     WLAN_REASON_DEAUTH_LEAVING, false);
+               /* free directly, disconnected event already sent */
+               cfg80211_sme_free(wdev);
                return 0;
        default:
                return 0;
@@ -371,7 +382,7 @@ bool cfg80211_sme_rx_assoc_resp(struct wireless_dev *wdev, u16 status)
                return true;
        }
 
-       wdev->conn->state = CFG80211_CONN_DEAUTH;
+       wdev->conn->state = CFG80211_CONN_ASSOC_FAILED;
        schedule_work(&rdev->conn_work);
        return false;
 }
@@ -383,7 +394,13 @@ void cfg80211_sme_deauth(struct wireless_dev *wdev)
 
 void cfg80211_sme_auth_timeout(struct wireless_dev *wdev)
 {
-       cfg80211_sme_free(wdev);
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+
+       if (!wdev->conn)
+               return;
+
+       wdev->conn->state = CFG80211_CONN_AUTH_FAILED;
+       schedule_work(&rdev->conn_work);
 }
 
 void cfg80211_sme_disassoc(struct wireless_dev *wdev)
@@ -399,7 +416,13 @@ void cfg80211_sme_disassoc(struct wireless_dev *wdev)
 
 void cfg80211_sme_assoc_timeout(struct wireless_dev *wdev)
 {
-       cfg80211_sme_disassoc(wdev);
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+
+       if (!wdev->conn)
+               return;
+
+       wdev->conn->state = CFG80211_CONN_ASSOC_FAILED;
+       schedule_work(&rdev->conn_work);
 }
 
 static int cfg80211_sme_connect(struct wireless_dev *wdev,
index 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 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 32b515766df17c984c6a1c56c86fa67dba4ee25d..8b4f24ae43381de05af67271edd9a8ddd57c651f 100644 (file)
@@ -129,7 +129,7 @@ static void cap_inode_free_security(struct inode *inode)
 }
 
 static int cap_inode_init_security(struct inode *inode, struct inode *dir,
-                                  const struct qstr *qstr, char **name,
+                                  const struct qstr *qstr, const char **name,
                                   void **value, size_t *len)
 {
        return -EOPNOTSUPP;
@@ -777,9 +777,15 @@ static int cap_xfrm_policy_delete_security(struct xfrm_sec_ctx *ctx)
        return 0;
 }
 
-static int cap_xfrm_state_alloc_security(struct xfrm_state *x,
-                                        struct xfrm_user_sec_ctx *sec_ctx,
-                                        u32 secid)
+static int cap_xfrm_state_alloc(struct xfrm_state *x,
+                               struct xfrm_user_sec_ctx *sec_ctx)
+{
+       return 0;
+}
+
+static int cap_xfrm_state_alloc_acquire(struct xfrm_state *x,
+                                       struct xfrm_sec_ctx *polsec,
+                                       u32 secid)
 {
        return 0;
 }
@@ -1101,7 +1107,8 @@ void __init security_fixup_ops(struct security_operations *ops)
        set_to_cap_if_null(ops, xfrm_policy_clone_security);
        set_to_cap_if_null(ops, xfrm_policy_free_security);
        set_to_cap_if_null(ops, xfrm_policy_delete_security);
-       set_to_cap_if_null(ops, xfrm_state_alloc_security);
+       set_to_cap_if_null(ops, xfrm_state_alloc);
+       set_to_cap_if_null(ops, xfrm_state_alloc_acquire);
        set_to_cap_if_null(ops, xfrm_state_free_security);
        set_to_cap_if_null(ops, xfrm_state_delete_security);
        set_to_cap_if_null(ops, xfrm_policy_lookup);
index df0fa451a8718312ba319d4d27f2edfdf7a3b8e4..af9b6852f4e1bf571b55a2010fd6ab0488119cda 100644 (file)
@@ -418,7 +418,7 @@ int evm_inode_init_security(struct inode *inode,
 
        evm_xattr->value = xattr_data;
        evm_xattr->value_len = sizeof(*xattr_data);
-       evm_xattr->name = kstrdup(XATTR_EVM_SUFFIX, GFP_NOFS);
+       evm_xattr->name = XATTR_EVM_SUFFIX;
        return 0;
 out:
        kfree(xattr_data);
index 94b35aef6871a9978cf21799cfec3385502bc555..15b6928592ef68aac565e3fc94daf4737b6adc54 100644 (file)
@@ -348,10 +348,10 @@ int security_inode_init_security(struct inode *inode, struct inode *dir,
        if (unlikely(IS_PRIVATE(inode)))
                return 0;
 
-       memset(new_xattrs, 0, sizeof new_xattrs);
        if (!initxattrs)
                return security_ops->inode_init_security(inode, dir, qstr,
                                                         NULL, NULL, NULL);
+       memset(new_xattrs, 0, sizeof(new_xattrs));
        lsm_xattr = new_xattrs;
        ret = security_ops->inode_init_security(inode, dir, qstr,
                                                &lsm_xattr->name,
@@ -366,16 +366,14 @@ int security_inode_init_security(struct inode *inode, struct inode *dir,
                goto out;
        ret = initxattrs(inode, new_xattrs, fs_data);
 out:
-       for (xattr = new_xattrs; xattr->name != NULL; xattr++) {
-               kfree(xattr->name);
+       for (xattr = new_xattrs; xattr->value != NULL; xattr++)
                kfree(xattr->value);
-       }
        return (ret == -EOPNOTSUPP) ? 0 : ret;
 }
 EXPORT_SYMBOL(security_inode_init_security);
 
 int security_old_inode_init_security(struct inode *inode, struct inode *dir,
-                                    const struct qstr *qstr, char **name,
+                                    const struct qstr *qstr, const char **name,
                                     void **value, size_t *len)
 {
        if (unlikely(IS_PRIVATE(inode)))
@@ -1342,22 +1340,17 @@ int security_xfrm_policy_delete(struct xfrm_sec_ctx *ctx)
        return security_ops->xfrm_policy_delete_security(ctx);
 }
 
-int security_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx)
+int security_xfrm_state_alloc(struct xfrm_state *x,
+                             struct xfrm_user_sec_ctx *sec_ctx)
 {
-       return security_ops->xfrm_state_alloc_security(x, sec_ctx, 0);
+       return security_ops->xfrm_state_alloc(x, sec_ctx);
 }
 EXPORT_SYMBOL(security_xfrm_state_alloc);
 
 int security_xfrm_state_alloc_acquire(struct xfrm_state *x,
                                      struct xfrm_sec_ctx *polsec, u32 secid)
 {
-       if (!polsec)
-               return 0;
-       /*
-        * We want the context to be taken from secid which is usually
-        * from the sock.
-        */
-       return security_ops->xfrm_state_alloc_security(x, NULL, secid);
+       return security_ops->xfrm_state_alloc_acquire(x, polsec, secid);
 }
 
 int security_xfrm_state_delete(struct xfrm_state *x)
index c956390a9136b75a7fb8ed17ded49c69310b31cf..cf0f8df7f8ed60f34bfba5a0af8ac6b352f886e5 100644 (file)
@@ -95,8 +95,6 @@
 #include "audit.h"
 #include "avc_ss.h"
 
-#define NUM_SEL_MNT_OPTS 5
-
 extern struct security_operations *security_ops;
 
 /* SECMARK reference count */
@@ -139,12 +137,28 @@ static struct kmem_cache *sel_inode_cache;
  * This function checks the SECMARK reference counter to see if any SECMARK
  * targets are currently configured, if the reference counter is greater than
  * zero SECMARK is considered to be enabled.  Returns true (1) if SECMARK is
- * enabled, false (0) if SECMARK is disabled.
+ * enabled, false (0) if SECMARK is disabled.  If the always_check_network
+ * policy capability is enabled, SECMARK is always considered enabled.
  *
  */
 static int selinux_secmark_enabled(void)
 {
-       return (atomic_read(&selinux_secmark_refcount) > 0);
+       return (selinux_policycap_alwaysnetwork || atomic_read(&selinux_secmark_refcount));
+}
+
+/**
+ * selinux_peerlbl_enabled - Check to see if peer labeling is currently enabled
+ *
+ * Description:
+ * This function checks if NetLabel or labeled IPSEC is enabled.  Returns true
+ * (1) if any are enabled or false (0) if neither are enabled.  If the
+ * always_check_network policy capability is enabled, peer labeling
+ * is always considered enabled.
+ *
+ */
+static int selinux_peerlbl_enabled(void)
+{
+       return (selinux_policycap_alwaysnetwork || netlbl_enabled() || selinux_xfrm_enabled());
 }
 
 /*
@@ -309,8 +323,11 @@ enum {
        Opt_defcontext = 3,
        Opt_rootcontext = 4,
        Opt_labelsupport = 5,
+       Opt_nextmntopt = 6,
 };
 
+#define NUM_SEL_MNT_OPTS       (Opt_nextmntopt - 1)
+
 static const match_table_t tokens = {
        {Opt_context, CONTEXT_STR "%s"},
        {Opt_fscontext, FSCONTEXT_STR "%s"},
@@ -355,6 +372,29 @@ static int may_context_mount_inode_relabel(u32 sid,
        return rc;
 }
 
+static int selinux_is_sblabel_mnt(struct super_block *sb)
+{
+       struct superblock_security_struct *sbsec = sb->s_security;
+
+       if (sbsec->behavior == SECURITY_FS_USE_XATTR ||
+           sbsec->behavior == SECURITY_FS_USE_TRANS ||
+           sbsec->behavior == SECURITY_FS_USE_TASK)
+               return 1;
+
+       /* Special handling for sysfs. Is genfs but also has setxattr handler*/
+       if (strncmp(sb->s_type->name, "sysfs", sizeof("sysfs")) == 0)
+               return 1;
+
+       /*
+        * Special handling for rootfs. Is genfs but supports
+        * setting SELinux context on in-core inodes.
+        */
+       if (strncmp(sb->s_type->name, "rootfs", sizeof("rootfs")) == 0)
+               return 1;
+
+       return 0;
+}
+
 static int sb_finish_set_opts(struct super_block *sb)
 {
        struct superblock_security_struct *sbsec = sb->s_security;
@@ -388,8 +428,6 @@ static int sb_finish_set_opts(struct super_block *sb)
                }
        }
 
-       sbsec->flags |= (SE_SBINITIALIZED | SE_SBLABELSUPP);
-
        if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
                printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n",
                       sb->s_id, sb->s_type->name);
@@ -398,15 +436,9 @@ static int sb_finish_set_opts(struct super_block *sb)
                       sb->s_id, sb->s_type->name,
                       labeling_behaviors[sbsec->behavior-1]);
 
-       if (sbsec->behavior == SECURITY_FS_USE_GENFS ||
-           sbsec->behavior == SECURITY_FS_USE_MNTPOINT ||
-           sbsec->behavior == SECURITY_FS_USE_NONE ||
-           sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
-               sbsec->flags &= ~SE_SBLABELSUPP;
-
-       /* Special handling for sysfs. Is genfs but also has setxattr handler*/
-       if (strncmp(sb->s_type->name, "sysfs", sizeof("sysfs")) == 0)
-               sbsec->flags |= SE_SBLABELSUPP;
+       sbsec->flags |= SE_SBINITIALIZED;
+       if (selinux_is_sblabel_mnt(sb))
+               sbsec->flags |= SBLABEL_MNT;
 
        /* Initialize the root inode. */
        rc = inode_doinit_with_dentry(root_inode, root);
@@ -460,16 +492,16 @@ static int selinux_get_mnt_opts(const struct super_block *sb,
        if (!ss_initialized)
                return -EINVAL;
 
+       /* make sure we always check enough bits to cover the mask */
+       BUILD_BUG_ON(SE_MNTMASK >= (1 << NUM_SEL_MNT_OPTS));
+
        tmp = sbsec->flags & SE_MNTMASK;
        /* count the number of mount options for this sb */
-       for (i = 0; i < 8; i++) {
+       for (i = 0; i < NUM_SEL_MNT_OPTS; i++) {
                if (tmp & 0x01)
                        opts->num_mnt_opts++;
                tmp >>= 1;
        }
-       /* Check if the Label support flag is set */
-       if (sbsec->flags & SE_SBLABELSUPP)
-               opts->num_mnt_opts++;
 
        opts->mnt_opts = kcalloc(opts->num_mnt_opts, sizeof(char *), GFP_ATOMIC);
        if (!opts->mnt_opts) {
@@ -515,9 +547,9 @@ static int selinux_get_mnt_opts(const struct super_block *sb,
                opts->mnt_opts[i] = context;
                opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT;
        }
-       if (sbsec->flags & SE_SBLABELSUPP) {
+       if (sbsec->flags & SBLABEL_MNT) {
                opts->mnt_opts[i] = NULL;
-               opts->mnt_opts_flags[i++] = SE_SBLABELSUPP;
+               opts->mnt_opts_flags[i++] = SBLABEL_MNT;
        }
 
        BUG_ON(i != opts->num_mnt_opts);
@@ -614,7 +646,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
        for (i = 0; i < num_opts; i++) {
                u32 sid;
 
-               if (flags[i] == SE_SBLABELSUPP)
+               if (flags[i] == SBLABEL_MNT)
                        continue;
                rc = security_context_to_sid(mount_options[i],
                                             strlen(mount_options[i]), &sid);
@@ -685,9 +717,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
                 * Determine the labeling behavior to use for this
                 * filesystem type.
                 */
-               rc = security_fs_use((sbsec->flags & SE_SBPROC) ?
-                                       "proc" : sb->s_type->name,
-                                       &sbsec->behavior, &sbsec->sid);
+               rc = security_fs_use(sb);
                if (rc) {
                        printk(KERN_WARNING
                                "%s: security_fs_use(%s) returned %d\n",
@@ -1037,7 +1067,7 @@ static void selinux_write_opts(struct seq_file *m,
                case DEFCONTEXT_MNT:
                        prefix = DEFCONTEXT_STR;
                        break;
-               case SE_SBLABELSUPP:
+               case SBLABEL_MNT:
                        seq_putc(m, ',');
                        seq_puts(m, LABELSUPP_STR);
                        continue;
@@ -1650,7 +1680,7 @@ static int may_create(struct inode *dir,
        if (rc)
                return rc;
 
-       if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
+       if (!newsid || !(sbsec->flags & SBLABEL_MNT)) {
                rc = security_transition_sid(sid, dsec->sid, tclass,
                                             &dentry->d_name, &newsid);
                if (rc)
@@ -2438,7 +2468,7 @@ static int selinux_sb_remount(struct super_block *sb, void *data)
                u32 sid;
                size_t len;
 
-               if (flags[i] == SE_SBLABELSUPP)
+               if (flags[i] == SBLABEL_MNT)
                        continue;
                len = strlen(mount_options[i]);
                rc = security_context_to_sid(mount_options[i], len, &sid);
@@ -2587,7 +2617,8 @@ static int selinux_dentry_init_security(struct dentry *dentry, int mode,
 }
 
 static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
-                                      const struct qstr *qstr, char **name,
+                                      const struct qstr *qstr,
+                                      const char **name,
                                       void **value, size_t *len)
 {
        const struct task_security_struct *tsec = current_security();
@@ -2595,7 +2626,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
        struct superblock_security_struct *sbsec;
        u32 sid, newsid, clen;
        int rc;
-       char *namep = NULL, *context;
+       char *context;
 
        dsec = dir->i_security;
        sbsec = dir->i_sb->s_security;
@@ -2606,7 +2637,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
        if ((sbsec->flags & SE_SBINITIALIZED) &&
            (sbsec->behavior == SECURITY_FS_USE_MNTPOINT))
                newsid = sbsec->mntpoint_sid;
-       else if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
+       else if (!newsid || !(sbsec->flags & SBLABEL_MNT)) {
                rc = security_transition_sid(sid, dsec->sid,
                                             inode_mode_to_security_class(inode->i_mode),
                                             qstr, &newsid);
@@ -2628,22 +2659,16 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
                isec->initialized = 1;
        }
 
-       if (!ss_initialized || !(sbsec->flags & SE_SBLABELSUPP))
+       if (!ss_initialized || !(sbsec->flags & SBLABEL_MNT))
                return -EOPNOTSUPP;
 
-       if (name) {
-               namep = kstrdup(XATTR_SELINUX_SUFFIX, GFP_NOFS);
-               if (!namep)
-                       return -ENOMEM;
-               *name = namep;
-       }
+       if (name)
+               *name = XATTR_SELINUX_SUFFIX;
 
        if (value && len) {
                rc = security_sid_to_context_force(newsid, &context, &clen);
-               if (rc) {
-                       kfree(namep);
+               if (rc)
                        return rc;
-               }
                *value = context;
                *len = clen;
        }
@@ -2836,7 +2861,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
                return selinux_inode_setotherxattr(dentry, name);
 
        sbsec = inode->i_sb->s_security;
-       if (!(sbsec->flags & SE_SBLABELSUPP))
+       if (!(sbsec->flags & SBLABEL_MNT))
                return -EOPNOTSUPP;
 
        if (!inode_owner_or_capable(inode))
@@ -3797,8 +3822,12 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
        u32 nlbl_sid;
        u32 nlbl_type;
 
-       selinux_skb_xfrm_sid(skb, &xfrm_sid);
-       selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid);
+       err = selinux_skb_xfrm_sid(skb, &xfrm_sid);
+       if (unlikely(err))
+               return -EACCES;
+       err = selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid);
+       if (unlikely(err))
+               return -EACCES;
 
        err = security_net_peersid_resolve(nlbl_sid, nlbl_type, xfrm_sid, sid);
        if (unlikely(err)) {
@@ -4252,7 +4281,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
                return selinux_sock_rcv_skb_compat(sk, skb, family);
 
        secmark_active = selinux_secmark_enabled();
-       peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
+       peerlbl_active = selinux_peerlbl_enabled();
        if (!secmark_active && !peerlbl_active)
                return 0;
 
@@ -4634,7 +4663,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
 
        secmark_active = selinux_secmark_enabled();
        netlbl_active = netlbl_enabled();
-       peerlbl_active = netlbl_active || selinux_xfrm_enabled();
+       peerlbl_active = selinux_peerlbl_enabled();
        if (!secmark_active && !peerlbl_active)
                return NF_ACCEPT;
 
@@ -4786,7 +4815,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
                return NF_ACCEPT;
 #endif
        secmark_active = selinux_secmark_enabled();
-       peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
+       peerlbl_active = selinux_peerlbl_enabled();
        if (!secmark_active && !peerlbl_active)
                return NF_ACCEPT;
 
@@ -5790,7 +5819,8 @@ static struct security_operations selinux_ops = {
        .xfrm_policy_clone_security =   selinux_xfrm_policy_clone,
        .xfrm_policy_free_security =    selinux_xfrm_policy_free,
        .xfrm_policy_delete_security =  selinux_xfrm_policy_delete,
-       .xfrm_state_alloc_security =    selinux_xfrm_state_alloc,
+       .xfrm_state_alloc =             selinux_xfrm_state_alloc,
+       .xfrm_state_alloc_acquire =     selinux_xfrm_state_alloc_acquire,
        .xfrm_state_free_security =     selinux_xfrm_state_free,
        .xfrm_state_delete_security =   selinux_xfrm_state_delete,
        .xfrm_policy_lookup =           selinux_xfrm_policy_lookup,
index aa47bcabb5f65e728aadbaa39cdecfa55d20aa16..b1dfe104945078ead53647c247c46aa6134fac2e 100644 (file)
@@ -58,8 +58,8 @@ struct superblock_security_struct {
        u32 sid;                        /* SID of file system superblock */
        u32 def_sid;                    /* default SID for labeling */
        u32 mntpoint_sid;               /* SECURITY_FS_USE_MNTPOINT context for files */
-       unsigned int behavior;          /* labeling behavior */
-       unsigned char flags;            /* which mount options were specified */
+       unsigned short behavior;        /* labeling behavior */
+       unsigned short flags;           /* which mount options were specified */
        struct mutex lock;
        struct list_head isec_head;
        spinlock_t isec_lock;
index 8fd8e18ea34019c863d91ba88268b8c4018f3410..216e53fd61369842769da1850f9db3dc5cdb3375 100644 (file)
 #endif
 
 /* Mask for just the mount related flags */
-#define SE_MNTMASK     0x0f
+#define SE_MNTMASK     0x1f
 /* Super block security struct flags for mount options */
+/* BE CAREFUL, these need to be the low order bits for selinux_get_mnt_opts */
 #define CONTEXT_MNT    0x01
 #define FSCONTEXT_MNT  0x02
 #define ROOTCONTEXT_MNT        0x04
 #define DEFCONTEXT_MNT 0x08
+#define SBLABEL_MNT    0x10
 /* Non-mount related flags */
-#define SE_SBINITIALIZED       0x10
-#define SE_SBPROC              0x20
-#define SE_SBLABELSUPP 0x40
+#define SE_SBINITIALIZED       0x0100
+#define SE_SBPROC              0x0200
 
 #define CONTEXT_STR    "context="
 #define FSCONTEXT_STR  "fscontext="
@@ -68,12 +69,15 @@ extern int selinux_enabled;
 enum {
        POLICYDB_CAPABILITY_NETPEER,
        POLICYDB_CAPABILITY_OPENPERM,
+       POLICYDB_CAPABILITY_REDHAT1,
+       POLICYDB_CAPABILITY_ALWAYSNETWORK,
        __POLICYDB_CAPABILITY_MAX
 };
 #define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1)
 
 extern int selinux_policycap_netpeer;
 extern int selinux_policycap_openperm;
+extern int selinux_policycap_alwaysnetwork;
 
 /*
  * type_datum properties
@@ -172,8 +176,7 @@ int security_get_allow_unknown(void);
 #define SECURITY_FS_USE_NATIVE         7 /* use native label support */
 #define SECURITY_FS_USE_MAX            7 /* Highest SECURITY_FS_USE_XXX */
 
-int security_fs_use(const char *fstype, unsigned int *behavior,
-       u32 *sid);
+int security_fs_use(struct super_block *sb);
 
 int security_genfs_sid(const char *fstype, char *name, u16 sclass,
        u32 *sid);
index 65f67cb0aefb22f323d8048c140417555c273c9d..7605251936f502bef385bec737eb4b85c7c3df7f 100644 (file)
 #include <net/flow.h>
 
 int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp,
-                             struct xfrm_user_sec_ctx *sec_ctx);
+                             struct xfrm_user_sec_ctx *uctx);
 int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx,
                              struct xfrm_sec_ctx **new_ctxp);
 void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx);
 int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx);
 int selinux_xfrm_state_alloc(struct xfrm_state *x,
-       struct xfrm_user_sec_ctx *sec_ctx, u32 secid);
+                            struct xfrm_user_sec_ctx *uctx);
+int selinux_xfrm_state_alloc_acquire(struct xfrm_state *x,
+                                    struct xfrm_sec_ctx *polsec, u32 secid);
 void selinux_xfrm_state_free(struct xfrm_state *x);
 int selinux_xfrm_state_delete(struct xfrm_state *x);
 int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir);
 int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x,
-                       struct xfrm_policy *xp, const struct flowi *fl);
-
-/*
- * Extract the security blob from the sock (it's actually on the socket)
- */
-static inline struct inode_security_struct *get_sock_isec(struct sock *sk)
-{
-       if (!sk->sk_socket)
-               return NULL;
-
-       return SOCK_INODE(sk->sk_socket)->i_security;
-}
+                                     struct xfrm_policy *xp,
+                                     const struct flowi *fl);
 
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
 extern atomic_t selinux_xfrm_refcount;
@@ -42,10 +34,10 @@ static inline int selinux_xfrm_enabled(void)
        return (atomic_read(&selinux_xfrm_refcount) > 0);
 }
 
-int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb,
-                       struct common_audit_data *ad);
-int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb,
-                       struct common_audit_data *ad, u8 proto);
+int selinux_xfrm_sock_rcv_skb(u32 sk_sid, struct sk_buff *skb,
+                             struct common_audit_data *ad);
+int selinux_xfrm_postroute_last(u32 sk_sid, struct sk_buff *skb,
+                               struct common_audit_data *ad, u8 proto);
 int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall);
 
 static inline void selinux_xfrm_notify_policyload(void)
@@ -59,19 +51,21 @@ static inline int selinux_xfrm_enabled(void)
        return 0;
 }
 
-static inline int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb,
-                       struct common_audit_data *ad)
+static inline int selinux_xfrm_sock_rcv_skb(u32 sk_sid, struct sk_buff *skb,
+                                           struct common_audit_data *ad)
 {
        return 0;
 }
 
-static inline int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb,
-                       struct common_audit_data *ad, u8 proto)
+static inline int selinux_xfrm_postroute_last(u32 sk_sid, struct sk_buff *skb,
+                                             struct common_audit_data *ad,
+                                             u8 proto)
 {
        return 0;
 }
 
-static inline int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall)
+static inline int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid,
+                                             int ckall)
 {
        *sid = SECSID_NULL;
        return 0;
@@ -82,10 +76,9 @@ static inline void selinux_xfrm_notify_policyload(void)
 }
 #endif
 
-static inline void selinux_skb_xfrm_sid(struct sk_buff *skb, u32 *sid)
+static inline int selinux_skb_xfrm_sid(struct sk_buff *skb, u32 *sid)
 {
-       int err = selinux_xfrm_decode_session(skb, sid, 0);
-       BUG_ON(err);
+       return selinux_xfrm_decode_session(skb, sid, 0);
 }
 
 #endif /* _SELINUX_XFRM_H_ */
index c5454c0477c346e4d814f5ff209feba86e5b86ad..03a72c32afd738ccad5c188bbe853202c32f53f6 100644 (file)
@@ -166,6 +166,7 @@ static void sel_netnode_insert(struct sel_netnode *node)
                break;
        default:
                BUG();
+               return;
        }
 
        /* we need to impose a limit on the growth of the hash table so check
@@ -225,6 +226,7 @@ static int sel_netnode_sid_slow(void *addr, u16 family, u32 *sid)
                break;
        default:
                BUG();
+               ret = -EINVAL;
        }
        if (ret != 0)
                goto out;
index ff427733c2903cab275a05da0887478850e1e374..5122affe06a8840e193150d62bd9b2f996fe67fe 100644 (file)
@@ -44,7 +44,9 @@
 /* Policy capability filenames */
 static char *policycap_names[] = {
        "network_peer_controls",
-       "open_perms"
+       "open_perms",
+       "redhat1",
+       "always_check_network"
 };
 
 unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE;
index 30f119b1d1ec36a95dc456c52b5b0ac1a6868514..820313a04d49bf4c4a8bc0f04ea01514ff184a64 100644 (file)
@@ -213,7 +213,12 @@ netlbl_import_failure:
 }
 #endif /* CONFIG_NETLABEL */
 
-int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
+/*
+ * Check to see if all the bits set in e2 are also set in e1. Optionally,
+ * if last_e2bit is non-zero, the highest set bit in e2 cannot exceed
+ * last_e2bit.
+ */
+int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2, u32 last_e2bit)
 {
        struct ebitmap_node *n1, *n2;
        int i;
@@ -223,14 +228,25 @@ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
 
        n1 = e1->node;
        n2 = e2->node;
+
        while (n1 && n2 && (n1->startbit <= n2->startbit)) {
                if (n1->startbit < n2->startbit) {
                        n1 = n1->next;
                        continue;
                }
-               for (i = 0; i < EBITMAP_UNIT_NUMS; i++) {
+               for (i = EBITMAP_UNIT_NUMS - 1; (i >= 0) && !n2->maps[i]; )
+                       i--;    /* Skip trailing NULL map entries */
+               if (last_e2bit && (i >= 0)) {
+                       u32 lastsetbit = n2->startbit + i * EBITMAP_UNIT_SIZE +
+                                        __fls(n2->maps[i]);
+                       if (lastsetbit > last_e2bit)
+                               return 0;
+               }
+
+               while (i >= 0) {
                        if ((n1->maps[i] & n2->maps[i]) != n2->maps[i])
                                return 0;
+                       i--;
                }
 
                n1 = n1->next;
index 922f8afa89dd5837e2617daaf793db0e40ad009e..712c8a7b8e8b879d3835b5ee3650b66baa46e106 100644 (file)
 
 #include <net/netlabel.h>
 
-#define EBITMAP_UNIT_NUMS      ((32 - sizeof(void *) - sizeof(u32))    \
+#ifdef CONFIG_64BIT
+#define        EBITMAP_NODE_SIZE       64
+#else
+#define        EBITMAP_NODE_SIZE       32
+#endif
+
+#define EBITMAP_UNIT_NUMS      ((EBITMAP_NODE_SIZE-sizeof(void *)-sizeof(u32))\
                                        / sizeof(unsigned long))
 #define EBITMAP_UNIT_SIZE      BITS_PER_LONG
 #define EBITMAP_SIZE           (EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE)
@@ -117,7 +123,7 @@ static inline void ebitmap_node_clr_bit(struct ebitmap_node *n,
 
 int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);
 int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
-int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2);
+int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2, u32 last_e2bit);
 int ebitmap_get_bit(struct ebitmap *e, unsigned long bit);
 int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value);
 void ebitmap_destroy(struct ebitmap *e);
index 40de8d3f208ecf95db162f4ae355d0d53ba99265..c85bc1ec040c0c58f93772004361cbcd04861575 100644 (file)
@@ -160,8 +160,6 @@ void mls_sid_to_context(struct context *context,
 int mls_level_isvalid(struct policydb *p, struct mls_level *l)
 {
        struct level_datum *levdatum;
-       struct ebitmap_node *node;
-       int i;
 
        if (!l->sens || l->sens > p->p_levels.nprim)
                return 0;
@@ -170,19 +168,13 @@ int mls_level_isvalid(struct policydb *p, struct mls_level *l)
        if (!levdatum)
                return 0;
 
-       ebitmap_for_each_positive_bit(&l->cat, node, i) {
-               if (i > p->p_cats.nprim)
-                       return 0;
-               if (!ebitmap_get_bit(&levdatum->level->cat, i)) {
-                       /*
-                        * Category may not be associated with
-                        * sensitivity.
-                        */
-                       return 0;
-               }
-       }
-
-       return 1;
+       /*
+        * Return 1 iff all the bits set in l->cat are also be set in
+        * levdatum->level->cat and no bit in l->cat is larger than
+        * p->p_cats.nprim.
+        */
+       return ebitmap_contains(&levdatum->level->cat, &l->cat,
+                               p->p_cats.nprim);
 }
 
 int mls_range_isvalid(struct policydb *p, struct mls_range *r)
index 03bed52a80526abfbda766a33859595cc1d8bfa5..e93648774137c601f5ec90ce14a03983655ce36d 100644 (file)
@@ -35,7 +35,7 @@ static inline int mls_level_eq(struct mls_level *l1, struct mls_level *l2)
 static inline int mls_level_dom(struct mls_level *l1, struct mls_level *l2)
 {
        return ((l1->sens >= l2->sens) &&
-               ebitmap_contains(&l1->cat, &l2->cat));
+               ebitmap_contains(&l1->cat, &l2->cat, 0));
 }
 
 #define mls_level_incomp(l1, l2) \
index c8adde3aff8fdbe93fb2f867e55f71b9879685a5..f6195ebde3c94eef0cdf1cf92933246069b25059 100644 (file)
@@ -3203,9 +3203,8 @@ static int range_write_helper(void *key, void *data, void *ptr)
 
 static int range_write(struct policydb *p, void *fp)
 {
-       size_t nel;
        __le32 buf[1];
-       int rc;
+       int rc, nel;
        struct policy_data pd;
 
        pd.p = p;
index b4feecc3fe0110d10bbdc183c369a03ab8495a6c..d106733ad9878d6ee7543ff31c05a51f2c74b523 100644 (file)
@@ -72,6 +72,7 @@
 
 int selinux_policycap_netpeer;
 int selinux_policycap_openperm;
+int selinux_policycap_alwaysnetwork;
 
 static DEFINE_RWLOCK(policy_rwlock);
 
@@ -1812,6 +1813,8 @@ static void security_load_policycaps(void)
                                                  POLICYDB_CAPABILITY_NETPEER);
        selinux_policycap_openperm = ebitmap_get_bit(&policydb.policycaps,
                                                  POLICYDB_CAPABILITY_OPENPERM);
+       selinux_policycap_alwaysnetwork = ebitmap_get_bit(&policydb.policycaps,
+                                                 POLICYDB_CAPABILITY_ALWAYSNETWORK);
 }
 
 static int security_preserve_bools(struct policydb *p);
@@ -2323,17 +2326,14 @@ out:
 
 /**
  * security_fs_use - Determine how to handle labeling for a filesystem.
- * @fstype: filesystem type
- * @behavior: labeling behavior
- * @sid: SID for filesystem (superblock)
+ * @sb: superblock in question
  */
-int security_fs_use(
-       const char *fstype,
-       unsigned int *behavior,
-       u32 *sid)
+int security_fs_use(struct super_block *sb)
 {
        int rc = 0;
        struct ocontext *c;
+       struct superblock_security_struct *sbsec = sb->s_security;
+       const char *fstype = sb->s_type->name;
 
        read_lock(&policy_rwlock);
 
@@ -2345,21 +2345,21 @@ int security_fs_use(
        }
 
        if (c) {
-               *behavior = c->v.behavior;
+               sbsec->behavior = c->v.behavior;
                if (!c->sid[0]) {
                        rc = sidtab_context_to_sid(&sidtab, &c->context[0],
                                                   &c->sid[0]);
                        if (rc)
                                goto out;
                }
-               *sid = c->sid[0];
+               sbsec->sid = c->sid[0];
        } else {
-               rc = security_genfs_sid(fstype, "/", SECCLASS_DIR, sid);
+               rc = security_genfs_sid(fstype, "/", SECCLASS_DIR, &sbsec->sid);
                if (rc) {
-                       *behavior = SECURITY_FS_USE_NONE;
+                       sbsec->behavior = SECURITY_FS_USE_NONE;
                        rc = 0;
                } else {
-                       *behavior = SECURITY_FS_USE_GENFS;
+                       sbsec->behavior = SECURITY_FS_USE_GENFS;
                }
        }
 
index d030818862146732ebe30c8cc3f266d485ef0677..425b9f91d755f6aa229f9bc71c58a747d0f9fa98 100644 (file)
@@ -56,7 +56,7 @@
 atomic_t selinux_xfrm_refcount = ATOMIC_INIT(0);
 
 /*
- * Returns true if an LSM/SELinux context
+ * Returns true if the context is an LSM/SELinux context.
  */
 static inline int selinux_authorizable_ctx(struct xfrm_sec_ctx *ctx)
 {
@@ -66,7 +66,7 @@ static inline int selinux_authorizable_ctx(struct xfrm_sec_ctx *ctx)
 }
 
 /*
- * Returns true if the xfrm contains a security blob for SELinux
+ * Returns true if the xfrm contains a security blob for SELinux.
  */
 static inline int selinux_authorizable_xfrm(struct xfrm_state *x)
 {
@@ -74,48 +74,111 @@ static inline int selinux_authorizable_xfrm(struct xfrm_state *x)
 }
 
 /*
- * LSM hook implementation that authorizes that a flow can use
- * a xfrm policy rule.
+ * Allocates a xfrm_sec_state and populates it using the supplied security
+ * xfrm_user_sec_ctx context.
  */
-int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir)
+static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp,
+                                  struct xfrm_user_sec_ctx *uctx)
 {
        int rc;
-       u32 sel_sid;
+       const struct task_security_struct *tsec = current_security();
+       struct xfrm_sec_ctx *ctx = NULL;
+       u32 str_len;
 
-       /* Context sid is either set to label or ANY_ASSOC */
-       if (ctx) {
-               if (!selinux_authorizable_ctx(ctx))
-                       return -EINVAL;
-
-               sel_sid = ctx->ctx_sid;
-       } else
-               /*
-                * All flows should be treated as polmatch'ing an
-                * otherwise applicable "non-labeled" policy. This
-                * would prevent inadvertent "leaks".
-                */
-               return 0;
+       if (ctxp == NULL || uctx == NULL ||
+           uctx->ctx_doi != XFRM_SC_DOI_LSM ||
+           uctx->ctx_alg != XFRM_SC_ALG_SELINUX)
+               return -EINVAL;
 
-       rc = avc_has_perm(fl_secid, sel_sid, SECCLASS_ASSOCIATION,
-                         ASSOCIATION__POLMATCH,
-                         NULL);
+       str_len = uctx->ctx_len;
+       if (str_len >= PAGE_SIZE)
+               return -ENOMEM;
 
-       if (rc == -EACCES)
-               return -ESRCH;
+       ctx = kmalloc(sizeof(*ctx) + str_len + 1, GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
 
+       ctx->ctx_doi = XFRM_SC_DOI_LSM;
+       ctx->ctx_alg = XFRM_SC_ALG_SELINUX;
+       ctx->ctx_len = str_len;
+       memcpy(ctx->ctx_str, &uctx[1], str_len);
+       ctx->ctx_str[str_len] = '\0';
+       rc = security_context_to_sid(ctx->ctx_str, str_len, &ctx->ctx_sid);
+       if (rc)
+               goto err;
+
+       rc = avc_has_perm(tsec->sid, ctx->ctx_sid,
+                         SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, NULL);
+       if (rc)
+               goto err;
+
+       *ctxp = ctx;
+       atomic_inc(&selinux_xfrm_refcount);
+       return 0;
+
+err:
+       kfree(ctx);
        return rc;
 }
 
+/*
+ * Free the xfrm_sec_ctx structure.
+ */
+static void selinux_xfrm_free(struct xfrm_sec_ctx *ctx)
+{
+       if (!ctx)
+               return;
+
+       atomic_dec(&selinux_xfrm_refcount);
+       kfree(ctx);
+}
+
+/*
+ * Authorize the deletion of a labeled SA or policy rule.
+ */
+static int selinux_xfrm_delete(struct xfrm_sec_ctx *ctx)
+{
+       const struct task_security_struct *tsec = current_security();
+
+       if (!ctx)
+               return 0;
+
+       return avc_has_perm(tsec->sid, ctx->ctx_sid,
+                           SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT,
+                           NULL);
+}
+
+/*
+ * LSM hook implementation that authorizes that a flow can use a xfrm policy
+ * rule.
+ */
+int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir)
+{
+       int rc;
+
+       /* All flows should be treated as polmatch'ing an otherwise applicable
+        * "non-labeled" policy. This would prevent inadvertent "leaks". */
+       if (!ctx)
+               return 0;
+
+       /* Context sid is either set to label or ANY_ASSOC */
+       if (!selinux_authorizable_ctx(ctx))
+               return -EINVAL;
+
+       rc = avc_has_perm(fl_secid, ctx->ctx_sid,
+                         SECCLASS_ASSOCIATION, ASSOCIATION__POLMATCH, NULL);
+       return (rc == -EACCES ? -ESRCH : rc);
+}
+
 /*
  * LSM hook implementation that authorizes that a state matches
  * the given policy, flow combo.
  */
-
-int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy *xp,
-                       const struct flowi *fl)
+int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x,
+                                     struct xfrm_policy *xp,
+                                     const struct flowi *fl)
 {
        u32 state_sid;
-       int rc;
 
        if (!xp->security)
                if (x->security)
@@ -138,187 +201,80 @@ int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy *
        if (fl->flowi_secid != state_sid)
                return 0;
 
-       rc = avc_has_perm(fl->flowi_secid, state_sid, SECCLASS_ASSOCIATION,
-                         ASSOCIATION__SENDTO,
-                         NULL)? 0:1;
-
-       /*
-        * We don't need a separate SA Vs. policy polmatch check
-        * since the SA is now of the same label as the flow and
-        * a flow Vs. policy polmatch check had already happened
-        * in selinux_xfrm_policy_lookup() above.
-        */
-
-       return rc;
+       /* We don't need a separate SA Vs. policy polmatch check since the SA
+        * is now of the same label as the flow and a flow Vs. policy polmatch
+        * check had already happened in selinux_xfrm_policy_lookup() above. */
+       return (avc_has_perm(fl->flowi_secid, state_sid,
+                           SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO,
+                           NULL) ? 0 : 1);
 }
 
 /*
  * LSM hook implementation that checks and/or returns the xfrm sid for the
  * incoming packet.
  */
-
 int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall)
 {
+       u32 sid_session = SECSID_NULL;
        struct sec_path *sp;
 
-       *sid = SECSID_NULL;
-
        if (skb == NULL)
-               return 0;
+               goto out;
 
        sp = skb->sp;
        if (sp) {
-               int i, sid_set = 0;
+               int i;
 
-               for (i = sp->len-1; i >= 0; i--) {
+               for (i = sp->len - 1; i >= 0; i--) {
                        struct xfrm_state *x = sp->xvec[i];
                        if (selinux_authorizable_xfrm(x)) {
                                struct xfrm_sec_ctx *ctx = x->security;
 
-                               if (!sid_set) {
-                                       *sid = ctx->ctx_sid;
-                                       sid_set = 1;
-
+                               if (sid_session == SECSID_NULL) {
+                                       sid_session = ctx->ctx_sid;
                                        if (!ckall)
-                                               break;
-                               } else if (*sid != ctx->ctx_sid)
+                                               goto out;
+                               } else if (sid_session != ctx->ctx_sid) {
+                                       *sid = SECSID_NULL;
                                        return -EINVAL;
+                               }
                        }
                }
        }
 
-       return 0;
-}
-
-/*
- * Security blob allocation for xfrm_policy and xfrm_state
- * CTX does not have a meaningful value on input
- */
-static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp,
-       struct xfrm_user_sec_ctx *uctx, u32 sid)
-{
-       int rc = 0;
-       const struct task_security_struct *tsec = current_security();
-       struct xfrm_sec_ctx *ctx = NULL;
-       char *ctx_str = NULL;
-       u32 str_len;
-
-       BUG_ON(uctx && sid);
-
-       if (!uctx)
-               goto not_from_user;
-
-       if (uctx->ctx_alg != XFRM_SC_ALG_SELINUX)
-               return -EINVAL;
-
-       str_len = uctx->ctx_len;
-       if (str_len >= PAGE_SIZE)
-               return -ENOMEM;
-
-       *ctxp = ctx = kmalloc(sizeof(*ctx) +
-                             str_len + 1,
-                             GFP_KERNEL);
-
-       if (!ctx)
-               return -ENOMEM;
-
-       ctx->ctx_doi = uctx->ctx_doi;
-       ctx->ctx_len = str_len;
-       ctx->ctx_alg = uctx->ctx_alg;
-
-       memcpy(ctx->ctx_str,
-              uctx+1,
-              str_len);
-       ctx->ctx_str[str_len] = 0;
-       rc = security_context_to_sid(ctx->ctx_str,
-                                    str_len,
-                                    &ctx->ctx_sid);
-
-       if (rc)
-               goto out;
-
-       /*
-        * Does the subject have permission to set security context?
-        */
-       rc = avc_has_perm(tsec->sid, ctx->ctx_sid,
-                         SECCLASS_ASSOCIATION,
-                         ASSOCIATION__SETCONTEXT, NULL);
-       if (rc)
-               goto out;
-
-       return rc;
-
-not_from_user:
-       rc = security_sid_to_context(sid, &ctx_str, &str_len);
-       if (rc)
-               goto out;
-
-       *ctxp = ctx = kmalloc(sizeof(*ctx) +
-                             str_len,
-                             GFP_ATOMIC);
-
-       if (!ctx) {
-               rc = -ENOMEM;
-               goto out;
-       }
-
-       ctx->ctx_doi = XFRM_SC_DOI_LSM;
-       ctx->ctx_alg = XFRM_SC_ALG_SELINUX;
-       ctx->ctx_sid = sid;
-       ctx->ctx_len = str_len;
-       memcpy(ctx->ctx_str,
-              ctx_str,
-              str_len);
-
-       goto out2;
-
 out:
-       *ctxp = NULL;
-       kfree(ctx);
-out2:
-       kfree(ctx_str);
-       return rc;
+       *sid = sid_session;
+       return 0;
 }
 
 /*
- * LSM hook implementation that allocs and transfers uctx spec to
- * xfrm_policy.
+ * LSM hook implementation that allocs and transfers uctx spec to xfrm_policy.
  */
 int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp,
                              struct xfrm_user_sec_ctx *uctx)
 {
-       int err;
-
-       BUG_ON(!uctx);
-
-       err = selinux_xfrm_sec_ctx_alloc(ctxp, uctx, 0);
-       if (err == 0)
-               atomic_inc(&selinux_xfrm_refcount);
-
-       return err;
+       return selinux_xfrm_alloc_user(ctxp, uctx);
 }
 
-
 /*
- * LSM hook implementation that copies security data structure from old to
- * new for policy cloning.
+ * LSM hook implementation that copies security data structure from old to new
+ * for policy cloning.
  */
 int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx,
                              struct xfrm_sec_ctx **new_ctxp)
 {
        struct xfrm_sec_ctx *new_ctx;
 
-       if (old_ctx) {
-               new_ctx = kmalloc(sizeof(*old_ctx) + old_ctx->ctx_len,
-                                 GFP_ATOMIC);
-               if (!new_ctx)
-                       return -ENOMEM;
+       if (!old_ctx)
+               return 0;
+
+       new_ctx = kmalloc(sizeof(*old_ctx) + old_ctx->ctx_len, GFP_ATOMIC);
+       if (!new_ctx)
+               return -ENOMEM;
+       memcpy(new_ctx, old_ctx, sizeof(*old_ctx) + old_ctx->ctx_len);
+       atomic_inc(&selinux_xfrm_refcount);
+       *new_ctxp = new_ctx;
 
-               memcpy(new_ctx, old_ctx, sizeof(*new_ctx));
-               memcpy(new_ctx->ctx_str, old_ctx->ctx_str, new_ctx->ctx_len);
-               atomic_inc(&selinux_xfrm_refcount);
-               *new_ctxp = new_ctx;
-       }
        return 0;
 }
 
@@ -327,8 +283,7 @@ int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx,
  */
 void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx)
 {
-       atomic_dec(&selinux_xfrm_refcount);
-       kfree(ctx);
+       selinux_xfrm_free(ctx);
 }
 
 /*
@@ -336,31 +291,55 @@ void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx)
  */
 int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx)
 {
-       const struct task_security_struct *tsec = current_security();
-
-       if (!ctx)
-               return 0;
+       return selinux_xfrm_delete(ctx);
+}
 
-       return avc_has_perm(tsec->sid, ctx->ctx_sid,
-                           SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT,
-                           NULL);
+/*
+ * LSM hook implementation that allocates a xfrm_sec_state, populates it using
+ * the supplied security context, and assigns it to the xfrm_state.
+ */
+int selinux_xfrm_state_alloc(struct xfrm_state *x,
+                            struct xfrm_user_sec_ctx *uctx)
+{
+       return selinux_xfrm_alloc_user(&x->security, uctx);
 }
 
 /*
- * LSM hook implementation that allocs and transfers sec_ctx spec to
- * xfrm_state.
+ * LSM hook implementation that allocates a xfrm_sec_state and populates based
+ * on a secid.
  */
-int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uctx,
-               u32 secid)
+int selinux_xfrm_state_alloc_acquire(struct xfrm_state *x,
+                                    struct xfrm_sec_ctx *polsec, u32 secid)
 {
-       int err;
+       int rc;
+       struct xfrm_sec_ctx *ctx;
+       char *ctx_str = NULL;
+       int str_len;
+
+       if (!polsec)
+               return 0;
 
-       BUG_ON(!x);
+       if (secid == 0)
+               return -EINVAL;
 
-       err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx, secid);
-       if (err == 0)
-               atomic_inc(&selinux_xfrm_refcount);
-       return err;
+       rc = security_sid_to_context(secid, &ctx_str, &str_len);
+       if (rc)
+               return rc;
+
+       ctx = kmalloc(sizeof(*ctx) + str_len, GFP_ATOMIC);
+       if (!ctx)
+               return -ENOMEM;
+
+       ctx->ctx_doi = XFRM_SC_DOI_LSM;
+       ctx->ctx_alg = XFRM_SC_ALG_SELINUX;
+       ctx->ctx_sid = secid;
+       ctx->ctx_len = str_len;
+       memcpy(ctx->ctx_str, ctx_str, str_len);
+       kfree(ctx_str);
+
+       x->security = ctx;
+       atomic_inc(&selinux_xfrm_refcount);
+       return 0;
 }
 
 /*
@@ -368,24 +347,15 @@ int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uct
  */
 void selinux_xfrm_state_free(struct xfrm_state *x)
 {
-       atomic_dec(&selinux_xfrm_refcount);
-       kfree(x->security);
+       selinux_xfrm_free(x->security);
 }
 
- /*
 * LSM hook implementation that authorizes deletion of labeled SAs.
 */
+/*
+ * LSM hook implementation that authorizes deletion of labeled SAs.
+ */
 int selinux_xfrm_state_delete(struct xfrm_state *x)
 {
-       const struct task_security_struct *tsec = current_security();
-       struct xfrm_sec_ctx *ctx = x->security;
-
-       if (!ctx)
-               return 0;
-
-       return avc_has_perm(tsec->sid, ctx->ctx_sid,
-                           SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT,
-                           NULL);
+       return selinux_xfrm_delete(x->security);
 }
 
 /*
@@ -395,14 +365,12 @@ int selinux_xfrm_state_delete(struct xfrm_state *x)
  * we need to check for unlabelled access since this may not have
  * gone thru the IPSec process.
  */
-int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb,
-                               struct common_audit_data *ad)
+int selinux_xfrm_sock_rcv_skb(u32 sk_sid, struct sk_buff *skb,
+                             struct common_audit_data *ad)
 {
-       int i, rc = 0;
-       struct sec_path *sp;
-       u32 sel_sid = SECINITSID_UNLABELED;
-
-       sp = skb->sp;
+       int i;
+       struct sec_path *sp = skb->sp;
+       u32 peer_sid = SECINITSID_UNLABELED;
 
        if (sp) {
                for (i = 0; i < sp->len; i++) {
@@ -410,23 +378,17 @@ int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb,
 
                        if (x && selinux_authorizable_xfrm(x)) {
                                struct xfrm_sec_ctx *ctx = x->security;
-                               sel_sid = ctx->ctx_sid;
+                               peer_sid = ctx->ctx_sid;
                                break;
                        }
                }
        }
 
-       /*
-        * This check even when there's no association involved is
-        * intended, according to Trent Jaeger, to make sure a
-        * process can't engage in non-ipsec communication unless
-        * explicitly allowed by policy.
-        */
-
-       rc = avc_has_perm(isec_sid, sel_sid, SECCLASS_ASSOCIATION,
-                         ASSOCIATION__RECVFROM, ad);
-
-       return rc;
+       /* This check even when there's no association involved is intended,
+        * according to Trent Jaeger, to make sure a process can't engage in
+        * non-IPsec communication unless explicitly allowed by policy. */
+       return avc_has_perm(sk_sid, peer_sid,
+                           SECCLASS_ASSOCIATION, ASSOCIATION__RECVFROM, ad);
 }
 
 /*
@@ -436,49 +398,38 @@ int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb,
  * If we do have a authorizable security association, then it has already been
  * checked in the selinux_xfrm_state_pol_flow_match hook above.
  */
-int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb,
-                                       struct common_audit_data *ad, u8 proto)
+int selinux_xfrm_postroute_last(u32 sk_sid, struct sk_buff *skb,
+                               struct common_audit_data *ad, u8 proto)
 {
        struct dst_entry *dst;
-       int rc = 0;
-
-       dst = skb_dst(skb);
-
-       if (dst) {
-               struct dst_entry *dst_test;
-
-               for (dst_test = dst; dst_test != NULL;
-                    dst_test = dst_test->child) {
-                       struct xfrm_state *x = dst_test->xfrm;
-
-                       if (x && selinux_authorizable_xfrm(x))
-                               goto out;
-               }
-       }
 
        switch (proto) {
        case IPPROTO_AH:
        case IPPROTO_ESP:
        case IPPROTO_COMP:
-               /*
-                * We should have already seen this packet once before
-                * it underwent xfrm(s). No need to subject it to the
-                * unlabeled check.
-                */
-               goto out;
+               /* We should have already seen this packet once before it
+                * underwent xfrm(s). No need to subject it to the unlabeled
+                * check. */
+               return 0;
        default:
                break;
        }
 
-       /*
-        * This check even when there's no association involved is
-        * intended, according to Trent Jaeger, to make sure a
-        * process can't engage in non-ipsec communication unless
-        * explicitly allowed by policy.
-        */
+       dst = skb_dst(skb);
+       if (dst) {
+               struct dst_entry *iter;
 
-       rc = avc_has_perm(isec_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION,
-                         ASSOCIATION__SENDTO, ad);
-out:
-       return rc;
+               for (iter = dst; iter != NULL; iter = iter->child) {
+                       struct xfrm_state *x = iter->xfrm;
+
+                       if (x && selinux_authorizable_xfrm(x))
+                               return 0;
+               }
+       }
+
+       /* This check even when there's no association involved is intended,
+        * according to Trent Jaeger, to make sure a process can't engage in
+        * non-IPsec communication unless explicitly allowed by policy. */
+       return avc_has_perm(sk_sid, SECINITSID_UNLABELED,
+                           SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, ad);
 }
index 3f7682a387b730b9c75fc6e547de98d512b46dbb..a113a779f00c7a1bac38b0823cdfb23fb967f172 100644 (file)
@@ -582,7 +582,7 @@ static void smack_inode_free_security(struct inode *inode)
  * Returns 0 if it all works out, -ENOMEM if there's no memory
  */
 static int smack_inode_init_security(struct inode *inode, struct inode *dir,
-                                    const struct qstr *qstr, char **name,
+                                    const struct qstr *qstr, const char **name,
                                     void **value, size_t *len)
 {
        struct inode_smack *issp = inode->i_security;
@@ -591,11 +591,8 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
        char *dsp = smk_of_inode(dir);
        int may;
 
-       if (name) {
-               *name = kstrdup(XATTR_SMACK_SUFFIX, GFP_NOFS);
-               if (*name == NULL)
-                       return -ENOMEM;
-       }
+       if (name)
+               *name = XATTR_SMACK_SUFFIX;
 
        if (value) {
                rcu_read_lock();
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 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..f5c2d1ff1a0904756a6a444eee7faf3406279d8d 100644 (file)
@@ -3724,7 +3724,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 +3734,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 +3889,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 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..04a69e3fca479e282495c7254010d93a26c5cac2 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
@@ -2573,15 +2575,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 +2712,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 +3782,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 +3820,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 +3896,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 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 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..d038a58bf9075b41cac2a6b377635d80674fafe4 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
@@ -198,6 +200,9 @@ config SND_SOC_AK4104
 config SND_SOC_AK4535
        tristate
 
+config SND_SOC_AK4554
+       tristate
+
 config SND_SOC_AK4641
        tristate
 
index 70fd8066f546e9cfc39dcb024f1efa6e5ea6bf1f..fab4086796a0f63fcd1d7ba3ea71304b075d76ef 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
@@ -138,6 +139,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
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;
 }
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 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 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..3168224bc1042b5c3d2fd5ac02cfe0192cb62a52 100644 (file)
@@ -225,15 +225,9 @@ 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 snd_soc_card *card;
        struct wm_adsp_alg_region region;
        struct wm_coeff_ctl_ops ops;
        struct wm_adsp *adsp;
@@ -378,7 +372,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 +394,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 +427,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 +449,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 +473,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 || !ctl->card)
                return -EINVAL;
 
        kcontrol = kzalloc(sizeof(*kcontrol), GFP_KERNEL);
@@ -525,14 +498,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(ctl->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(ctl->card,
+                                                 ctl->name);
+
+       list_add(&ctl->list, &adsp->ctl_list);
        return 0;
 
 err_kcontrol:
@@ -753,13 +729,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 +747,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,7 +773,7 @@ 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);
 }
 
@@ -842,7 +816,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 +840,7 @@ 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->card = codec->card;
        ctl->adsp = dsp;
 
        ctl->len = region->len;
@@ -882,7 +856,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);
@@ -1434,12 +1408,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 +1434,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:
@@ -1591,12 +1563,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 +1609,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 +1649,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..64087fb1cdec7801e8897f1e1ddd5f97f35b5342 100644 (file)
@@ -57,7 +57,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..3a79d01e8d036e8779b01864a1a5cbbf1e42d546 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.
@@ -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..9136625a3460f5c74f47be508d225cc60919339c 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;
 }
 
+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;
+};
+
 #ifdef CONFIG_SND_SOC_IMX_PCM_DMA
 int imx_pcm_dma_init(struct platform_device *pdev);
 void imx_pcm_dma_exit(struct platform_device *pdev);
@@ -47,10 +53,12 @@ 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);
+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 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..5e4ae0d
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * 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);
+       if (!sru_res ||
+           !adg_res ||
+           !ssi_res) {
+               dev_err(dev, "Not enough SRU/SSI/ADG platform resources.\n");
+               return -ENODEV;
+       }
+
+       gen->ops = &rsnd_gen1_ops;
+
+       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 (!gen->base[RSND_GEN1_SRU] ||
+           !gen->base[RSND_GEN1_ADG] ||
+           !gen->base[RSND_GEN1_SSI]) {
+               dev_err(dev, "SRU/SSI/ADG ioremap failed\n");
+               return -ENODEV;
+       }
+
+       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..9abb3b21f1fd35a7f59bbbcbb9f10c8112e29f05 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 (!data)
+               return -ENOMEM;
+
+       data->wlist.widgets[n - 1] = widget;
+       data->wlist.num_widgets = n;
+
+       kcontrol->private_data = 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. */
index 0b0a90787db64b010277005c5a7980f60d8fbdbc..0794acca46a39d433cdfee0d51d4aea25fc5ffe8 100644 (file)
@@ -39,13 +39,8 @@ bindir_relative = bin
 bindir = $(prefix)/$(bindir_relative)
 man_dir = $(prefix)/share/man
 man_dir_SQ = '$(subst ','\'',$(man_dir))'
-html_install = $(prefix)/share/kernelshark/html
-html_install_SQ = '$(subst ','\'',$(html_install))'
-img_install = $(prefix)/share/kernelshark/html/images
-img_install_SQ = '$(subst ','\'',$(img_install))'
 
-export man_dir man_dir_SQ html_install html_install_SQ INSTALL
-export img_install img_install_SQ
+export man_dir man_dir_SQ INSTALL
 export DESTDIR DESTDIR_SQ
 
 # copy a bit from Linux kbuild
@@ -76,10 +71,7 @@ $(if $(BUILD_OUTPUT),, \
 
 all: sub-make
 
-gui: force
-       $(call build_output, all_cmd)
-
-$(filter-out gui,$(MAKECMDGOALS)): sub-make
+$(MAKECMDGOALS): sub-make
 
 sub-make: force
        $(call build_output, $(MAKECMDGOALS))
@@ -189,6 +181,7 @@ $(obj)/%.o: $(src)/%.c
        $(Q)$(call do_compile)
 
 PEVENT_LIB_OBJS = event-parse.o trace-seq.o parse-filter.o parse-utils.o
+PEVENT_LIB_OBJS += kbuffer-parse.o
 
 ALL_OBJS = $(PEVENT_LIB_OBJS)
 
@@ -258,9 +251,6 @@ define check_deps
                $(RM) $@.$$$$
 endef
 
-$(gui_deps): ks_version.h
-$(non_gui_deps): tc_version.h
-
 $(all_deps): .%.d: $(src)/%.c
        $(Q)$(call check_deps)
 
@@ -300,7 +290,7 @@ define do_install
        $(INSTALL) $1 '$(DESTDIR_SQ)$2'
 endef
 
-install_lib: all_cmd install_plugins install_python
+install_lib: all_cmd
        $(Q)$(call do_install,$(LIB_FILE),$(bindir_SQ))
 
 install: install_lib
index 82b0606dcb8ab04ed08920abf9c2c193e4ee42bf..d1c2a6a4cd32b125a981dca6779abfce1b50967d 100644 (file)
@@ -5450,10 +5450,9 @@ int pevent_register_print_function(struct pevent *pevent,
  * If @id is >= 0, then it is used to find the event.
  * else @sys_name and @event_name are used.
  */
-int pevent_register_event_handler(struct pevent *pevent,
-                                 int id, char *sys_name, char *event_name,
-                                 pevent_event_handler_func func,
-                                 void *context)
+int pevent_register_event_handler(struct pevent *pevent, int id,
+                                 const char *sys_name, const char *event_name,
+                                 pevent_event_handler_func func, void *context)
 {
        struct event_format *event;
        struct event_handler *handle;
index 7be7e89533e4fed9979dae191cbb2aa808c45121..c37b2026d04a991b5d70db230db6a56d67320b99 100644 (file)
@@ -69,6 +69,7 @@ struct trace_seq {
 };
 
 void trace_seq_init(struct trace_seq *s);
+void trace_seq_reset(struct trace_seq *s);
 void trace_seq_destroy(struct trace_seq *s);
 
 extern int trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
@@ -399,6 +400,7 @@ struct pevent {
 
        int cpus;
        int long_size;
+       int page_size;
 
        struct cmdline *cmdlines;
        struct cmdline_list *cmdlist;
@@ -561,7 +563,8 @@ int pevent_print_num_field(struct trace_seq *s, const char *fmt,
                           struct event_format *event, const char *name,
                           struct pevent_record *record, int err);
 
-int pevent_register_event_handler(struct pevent *pevent, int id, char *sys_name, char *event_name,
+int pevent_register_event_handler(struct pevent *pevent, int id,
+                                 const char *sys_name, const char *event_name,
                                  pevent_event_handler_func func, void *context);
 int pevent_register_print_function(struct pevent *pevent,
                                   pevent_func_handler func,
@@ -619,6 +622,16 @@ static inline void pevent_set_long_size(struct pevent *pevent, int long_size)
        pevent->long_size = long_size;
 }
 
+static inline int pevent_get_page_size(struct pevent *pevent)
+{
+       return pevent->page_size;
+}
+
+static inline void pevent_set_page_size(struct pevent *pevent, int _page_size)
+{
+       pevent->page_size = _page_size;
+}
+
 static inline int pevent_is_file_bigendian(struct pevent *pevent)
 {
        return pevent->file_bigendian;
diff --git a/tools/lib/traceevent/kbuffer-parse.c b/tools/lib/traceevent/kbuffer-parse.c
new file mode 100644 (file)
index 0000000..dcc6652
--- /dev/null
@@ -0,0 +1,732 @@
+/*
+ * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License (not later!)
+ *
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "kbuffer.h"
+
+#define MISSING_EVENTS (1 << 31)
+#define MISSING_STORED (1 << 30)
+
+#define COMMIT_MASK ((1 << 27) - 1)
+
+enum {
+       KBUFFER_FL_HOST_BIG_ENDIAN      = (1<<0),
+       KBUFFER_FL_BIG_ENDIAN           = (1<<1),
+       KBUFFER_FL_LONG_8               = (1<<2),
+       KBUFFER_FL_OLD_FORMAT           = (1<<3),
+};
+
+#define ENDIAN_MASK (KBUFFER_FL_HOST_BIG_ENDIAN | KBUFFER_FL_BIG_ENDIAN)
+
+/** kbuffer
+ * @timestamp          - timestamp of current event
+ * @lost_events                - # of lost events between this subbuffer and previous
+ * @flags              - special flags of the kbuffer
+ * @subbuffer          - pointer to the sub-buffer page
+ * @data               - pointer to the start of data on the sub-buffer page
+ * @index              - index from @data to the @curr event data
+ * @curr               - offset from @data to the start of current event
+ *                        (includes metadata)
+ * @next               - offset from @data to the start of next event
+ * @size               - The size of data on @data
+ * @start              - The offset from @subbuffer where @data lives
+ *
+ * @read_4             - Function to read 4 raw bytes (may swap)
+ * @read_8             - Function to read 8 raw bytes (may swap)
+ * @read_long          - Function to read a long word (4 or 8 bytes with needed swap)
+ */
+struct kbuffer {
+       unsigned long long      timestamp;
+       long long               lost_events;
+       unsigned long           flags;
+       void                    *subbuffer;
+       void                    *data;
+       unsigned int            index;
+       unsigned int            curr;
+       unsigned int            next;
+       unsigned int            size;
+       unsigned int            start;
+
+       unsigned int (*read_4)(void *ptr);
+       unsigned long long (*read_8)(void *ptr);
+       unsigned long long (*read_long)(struct kbuffer *kbuf, void *ptr);
+       int (*next_event)(struct kbuffer *kbuf);
+};
+
+static void *zmalloc(size_t size)
+{
+       return calloc(1, size);
+}
+
+static int host_is_bigendian(void)
+{
+       unsigned char str[] = { 0x1, 0x2, 0x3, 0x4 };
+       unsigned int *ptr;
+
+       ptr = (unsigned int *)str;
+       return *ptr == 0x01020304;
+}
+
+static int do_swap(struct kbuffer *kbuf)
+{
+       return ((kbuf->flags & KBUFFER_FL_HOST_BIG_ENDIAN) + kbuf->flags) &
+               ENDIAN_MASK;
+}
+
+static unsigned long long __read_8(void *ptr)
+{
+       unsigned long long data = *(unsigned long long *)ptr;
+
+       return data;
+}
+
+static unsigned long long __read_8_sw(void *ptr)
+{
+       unsigned long long data = *(unsigned long long *)ptr;
+       unsigned long long swap;
+
+       swap = ((data & 0xffULL) << 56) |
+               ((data & (0xffULL << 8)) << 40) |
+               ((data & (0xffULL << 16)) << 24) |
+               ((data & (0xffULL << 24)) << 8) |
+               ((data & (0xffULL << 32)) >> 8) |
+               ((data & (0xffULL << 40)) >> 24) |
+               ((data & (0xffULL << 48)) >> 40) |
+               ((data & (0xffULL << 56)) >> 56);
+
+       return swap;
+}
+
+static unsigned int __read_4(void *ptr)
+{
+       unsigned int data = *(unsigned int *)ptr;
+
+       return data;
+}
+
+static unsigned int __read_4_sw(void *ptr)
+{
+       unsigned int data = *(unsigned int *)ptr;
+       unsigned int swap;
+
+       swap = ((data & 0xffULL) << 24) |
+               ((data & (0xffULL << 8)) << 8) |
+               ((data & (0xffULL << 16)) >> 8) |
+               ((data & (0xffULL << 24)) >> 24);
+
+       return swap;
+}
+
+static unsigned long long read_8(struct kbuffer *kbuf, void *ptr)
+{
+       return kbuf->read_8(ptr);
+}
+
+static unsigned int read_4(struct kbuffer *kbuf, void *ptr)
+{
+       return kbuf->read_4(ptr);
+}
+
+static unsigned long long __read_long_8(struct kbuffer *kbuf, void *ptr)
+{
+       return kbuf->read_8(ptr);
+}
+
+static unsigned long long __read_long_4(struct kbuffer *kbuf, void *ptr)
+{
+       return kbuf->read_4(ptr);
+}
+
+static unsigned long long read_long(struct kbuffer *kbuf, void *ptr)
+{
+       return kbuf->read_long(kbuf, ptr);
+}
+
+static int calc_index(struct kbuffer *kbuf, void *ptr)
+{
+       return (unsigned long)ptr - (unsigned long)kbuf->data;
+}
+
+static int __next_event(struct kbuffer *kbuf);
+
+/**
+ * kbuffer_alloc - allocat a new kbuffer
+ * @size;      enum to denote size of word
+ * @endian:    enum to denote endianness
+ *
+ * Allocates and returns a new kbuffer.
+ */
+struct kbuffer *
+kbuffer_alloc(enum kbuffer_long_size size, enum kbuffer_endian endian)
+{
+       struct kbuffer *kbuf;
+       int flags = 0;
+
+       switch (size) {
+       case KBUFFER_LSIZE_4:
+               break;
+       case KBUFFER_LSIZE_8:
+               flags |= KBUFFER_FL_LONG_8;
+               break;
+       default:
+               return NULL;
+       }
+
+       switch (endian) {
+       case KBUFFER_ENDIAN_LITTLE:
+               break;
+       case KBUFFER_ENDIAN_BIG:
+               flags |= KBUFFER_FL_BIG_ENDIAN;
+               break;
+       default:
+               return NULL;
+       }
+
+       kbuf = zmalloc(sizeof(*kbuf));
+       if (!kbuf)
+               return NULL;
+
+       kbuf->flags = flags;
+
+       if (host_is_bigendian())
+               kbuf->flags |= KBUFFER_FL_HOST_BIG_ENDIAN;
+
+       if (do_swap(kbuf)) {
+               kbuf->read_8 = __read_8_sw;
+               kbuf->read_4 = __read_4_sw;
+       } else {
+               kbuf->read_8 = __read_8;
+               kbuf->read_4 = __read_4;
+       }
+
+       if (kbuf->flags & KBUFFER_FL_LONG_8)
+               kbuf->read_long = __read_long_8;
+       else
+               kbuf->read_long = __read_long_4;
+
+       /* May be changed by kbuffer_set_old_format() */
+       kbuf->next_event = __next_event;
+
+       return kbuf;
+}
+
+/** kbuffer_free - free an allocated kbuffer
+ * @kbuf:      The kbuffer to free
+ *
+ * Can take NULL as a parameter.
+ */
+void kbuffer_free(struct kbuffer *kbuf)
+{
+       free(kbuf);
+}
+
+static unsigned int type4host(struct kbuffer *kbuf,
+                             unsigned int type_len_ts)
+{
+       if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN)
+               return (type_len_ts >> 29) & 3;
+       else
+               return type_len_ts & 3;
+}
+
+static unsigned int len4host(struct kbuffer *kbuf,
+                            unsigned int type_len_ts)
+{
+       if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN)
+               return (type_len_ts >> 27) & 7;
+       else
+               return (type_len_ts >> 2) & 7;
+}
+
+static unsigned int type_len4host(struct kbuffer *kbuf,
+                                 unsigned int type_len_ts)
+{
+       if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN)
+               return (type_len_ts >> 27) & ((1 << 5) - 1);
+       else
+               return type_len_ts & ((1 << 5) - 1);
+}
+
+static unsigned int ts4host(struct kbuffer *kbuf,
+                           unsigned int type_len_ts)
+{
+       if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN)
+               return type_len_ts & ((1 << 27) - 1);
+       else
+               return type_len_ts >> 5;
+}
+
+/*
+ * Linux 2.6.30 and earlier (not much ealier) had a different
+ * ring buffer format. It should be obsolete, but we handle it anyway.
+ */
+enum old_ring_buffer_type {
+       OLD_RINGBUF_TYPE_PADDING,
+       OLD_RINGBUF_TYPE_TIME_EXTEND,
+       OLD_RINGBUF_TYPE_TIME_STAMP,
+       OLD_RINGBUF_TYPE_DATA,
+};
+
+static unsigned int old_update_pointers(struct kbuffer *kbuf)
+{
+       unsigned long long extend;
+       unsigned int type_len_ts;
+       unsigned int type;
+       unsigned int len;
+       unsigned int delta;
+       unsigned int length;
+       void *ptr = kbuf->data + kbuf->curr;
+
+       type_len_ts = read_4(kbuf, ptr);
+       ptr += 4;
+
+       type = type4host(kbuf, type_len_ts);
+       len = len4host(kbuf, type_len_ts);
+       delta = ts4host(kbuf, type_len_ts);
+
+       switch (type) {
+       case OLD_RINGBUF_TYPE_PADDING:
+               kbuf->next = kbuf->size;
+               return 0;
+
+       case OLD_RINGBUF_TYPE_TIME_EXTEND:
+               extend = read_4(kbuf, ptr);
+               extend <<= TS_SHIFT;
+               extend += delta;
+               delta = extend;
+               ptr += 4;
+               break;
+
+       case OLD_RINGBUF_TYPE_TIME_STAMP:
+               /* should never happen! */
+               kbuf->curr = kbuf->size;
+               kbuf->next = kbuf->size;
+               kbuf->index = kbuf->size;
+               return -1;
+       default:
+               if (len)
+                       length = len * 4;
+               else {
+                       length = read_4(kbuf, ptr);
+                       length -= 4;
+                       ptr += 4;
+               }
+               break;
+       }
+
+       kbuf->timestamp += delta;
+       kbuf->index = calc_index(kbuf, ptr);
+       kbuf->next = kbuf->index + length;
+
+       return type;
+}
+
+static int __old_next_event(struct kbuffer *kbuf)
+{
+       int type;
+
+       do {
+               kbuf->curr = kbuf->next;
+               if (kbuf->next >= kbuf->size)
+                       return -1;
+               type = old_update_pointers(kbuf);
+       } while (type == OLD_RINGBUF_TYPE_TIME_EXTEND || type == OLD_RINGBUF_TYPE_PADDING);
+
+       return 0;
+}
+
+static unsigned int
+translate_data(struct kbuffer *kbuf, void *data, void **rptr,
+              unsigned long long *delta, int *length)
+{
+       unsigned long long extend;
+       unsigned int type_len_ts;
+       unsigned int type_len;
+
+       type_len_ts = read_4(kbuf, data);
+       data += 4;
+
+       type_len = type_len4host(kbuf, type_len_ts);
+       *delta = ts4host(kbuf, type_len_ts);
+
+       switch (type_len) {
+       case KBUFFER_TYPE_PADDING:
+               *length = read_4(kbuf, data);
+               data += *length;
+               break;
+
+       case KBUFFER_TYPE_TIME_EXTEND:
+               extend = read_4(kbuf, data);
+               data += 4;
+               extend <<= TS_SHIFT;
+               extend += *delta;
+               *delta = extend;
+               *length = 0;
+               break;
+
+       case KBUFFER_TYPE_TIME_STAMP:
+               data += 12;
+               *length = 0;
+               break;
+       case 0:
+               *length = read_4(kbuf, data) - 4;
+               *length = (*length + 3) & ~3;
+               data += 4;
+               break;
+       default:
+               *length = type_len * 4;
+               break;
+       }
+
+       *rptr = data;
+
+       return type_len;
+}
+
+static unsigned int update_pointers(struct kbuffer *kbuf)
+{
+       unsigned long long delta;
+       unsigned int type_len;
+       int length;
+       void *ptr = kbuf->data + kbuf->curr;
+
+       type_len = translate_data(kbuf, ptr, &ptr, &delta, &length);
+
+       kbuf->timestamp += delta;
+       kbuf->index = calc_index(kbuf, ptr);
+       kbuf->next = kbuf->index + length;
+
+       return type_len;
+}
+
+/**
+ * kbuffer_translate_data - read raw data to get a record
+ * @swap:      Set to 1 if bytes in words need to be swapped when read
+ * @data:      The raw data to read
+ * @size:      Address to store the size of the event data.
+ *
+ * Returns a pointer to the event data. To determine the entire
+ * record size (record metadata + data) just add the difference between
+ * @data and the returned value to @size.
+ */
+void *kbuffer_translate_data(int swap, void *data, unsigned int *size)
+{
+       unsigned long long delta;
+       struct kbuffer kbuf;
+       int type_len;
+       int length;
+       void *ptr;
+
+       if (swap) {
+               kbuf.read_8 = __read_8_sw;
+               kbuf.read_4 = __read_4_sw;
+               kbuf.flags = host_is_bigendian() ? 0 : KBUFFER_FL_BIG_ENDIAN;
+       } else {
+               kbuf.read_8 = __read_8;
+               kbuf.read_4 = __read_4;
+               kbuf.flags = host_is_bigendian() ? KBUFFER_FL_BIG_ENDIAN: 0;
+       }
+
+       type_len = translate_data(&kbuf, data, &ptr, &delta, &length);
+       switch (type_len) {
+       case KBUFFER_TYPE_PADDING:
+       case KBUFFER_TYPE_TIME_EXTEND:
+       case KBUFFER_TYPE_TIME_STAMP:
+               return NULL;
+       };
+
+       *size = length;
+
+       return ptr;
+}
+
+static int __next_event(struct kbuffer *kbuf)
+{
+       int type;
+
+       do {
+               kbuf->curr = kbuf->next;
+               if (kbuf->next >= kbuf->size)
+                       return -1;
+               type = update_pointers(kbuf);
+       } while (type == KBUFFER_TYPE_TIME_EXTEND || type == KBUFFER_TYPE_PADDING);
+
+       return 0;
+}
+
+static int next_event(struct kbuffer *kbuf)
+{
+       return kbuf->next_event(kbuf);
+}
+
+/**
+ * kbuffer_next_event - increment the current pointer
+ * @kbuf:      The kbuffer to read
+ * @ts:                Address to store the next record's timestamp (may be NULL to ignore)
+ *
+ * Increments the pointers into the subbuffer of the kbuffer to point to the
+ * next event so that the next kbuffer_read_event() will return a
+ * new event.
+ *
+ * Returns the data of the next event if a new event exists on the subbuffer,
+ * NULL otherwise.
+ */
+void *kbuffer_next_event(struct kbuffer *kbuf, unsigned long long *ts)
+{
+       int ret;
+
+       if (!kbuf || !kbuf->subbuffer)
+               return NULL;
+
+       ret = next_event(kbuf);
+       if (ret < 0)
+               return NULL;
+
+       if (ts)
+               *ts = kbuf->timestamp;
+
+       return kbuf->data + kbuf->index;
+}
+
+/**
+ * kbuffer_load_subbuffer - load a new subbuffer into the kbuffer
+ * @kbuf:      The kbuffer to load
+ * @subbuffer: The subbuffer to load into @kbuf.
+ *
+ * Load a new subbuffer (page) into @kbuf. This will reset all
+ * the pointers and update the @kbuf timestamp. The next read will
+ * return the first event on @subbuffer.
+ *
+ * Returns 0 on succes, -1 otherwise.
+ */
+int kbuffer_load_subbuffer(struct kbuffer *kbuf, void *subbuffer)
+{
+       unsigned long long flags;
+       void *ptr = subbuffer;
+
+       if (!kbuf || !subbuffer)
+               return -1;
+
+       kbuf->subbuffer = subbuffer;
+
+       kbuf->timestamp = read_8(kbuf, ptr);
+       ptr += 8;
+
+       kbuf->curr = 0;
+
+       if (kbuf->flags & KBUFFER_FL_LONG_8)
+               kbuf->start = 16;
+       else
+               kbuf->start = 12;
+
+       kbuf->data = subbuffer + kbuf->start;
+
+       flags = read_long(kbuf, ptr);
+       kbuf->size = (unsigned int)flags & COMMIT_MASK;
+
+       if (flags & MISSING_EVENTS) {
+               if (flags & MISSING_STORED) {
+                       ptr = kbuf->data + kbuf->size;
+                       kbuf->lost_events = read_long(kbuf, ptr);
+               } else
+                       kbuf->lost_events = -1;
+       } else
+               kbuf->lost_events = 0;
+
+       kbuf->index = 0;
+       kbuf->next = 0;
+
+       next_event(kbuf);
+
+       return 0;
+}
+
+/**
+ * kbuffer_read_event - read the next event in the kbuffer subbuffer
+ * @kbuf:      The kbuffer to read from
+ * @ts:                The address to store the timestamp of the event (may be NULL to ignore)
+ *
+ * Returns a pointer to the data part of the current event.
+ * NULL if no event is left on the subbuffer.
+ */
+void *kbuffer_read_event(struct kbuffer *kbuf, unsigned long long *ts)
+{
+       if (!kbuf || !kbuf->subbuffer)
+               return NULL;
+
+       if (kbuf->curr >= kbuf->size)
+               return NULL;
+
+       if (ts)
+               *ts = kbuf->timestamp;
+       return kbuf->data + kbuf->index;
+}
+
+/**
+ * kbuffer_timestamp - Return the timestamp of the current event
+ * @kbuf:      The kbuffer to read from
+ *
+ * Returns the timestamp of the current (next) event.
+ */
+unsigned long long kbuffer_timestamp(struct kbuffer *kbuf)
+{
+       return kbuf->timestamp;
+}
+
+/**
+ * kbuffer_read_at_offset - read the event that is at offset
+ * @kbuf:      The kbuffer to read from
+ * @offset:    The offset into the subbuffer
+ * @ts:                The address to store the timestamp of the event (may be NULL to ignore)
+ *
+ * The @offset must be an index from the @kbuf subbuffer beginning.
+ * If @offset is bigger than the stored subbuffer, NULL will be returned.
+ *
+ * Returns the data of the record that is at @offset. Note, @offset does
+ * not need to be the start of the record, the offset just needs to be
+ * in the record (or beginning of it).
+ *
+ * Note, the kbuf timestamp and pointers are updated to the
+ * returned record. That is, kbuffer_read_event() will return the same
+ * data and timestamp, and kbuffer_next_event() will increment from
+ * this record.
+ */
+void *kbuffer_read_at_offset(struct kbuffer *kbuf, int offset,
+                            unsigned long long *ts)
+{
+       void *data;
+
+       if (offset < kbuf->start)
+               offset = 0;
+       else
+               offset -= kbuf->start;
+
+       /* Reset the buffer */
+       kbuffer_load_subbuffer(kbuf, kbuf->subbuffer);
+
+       while (kbuf->curr < offset) {
+               data = kbuffer_next_event(kbuf, ts);
+               if (!data)
+                       break;
+       }
+
+       return data;
+}
+
+/**
+ * kbuffer_subbuffer_size - the size of the loaded subbuffer
+ * @kbuf:      The kbuffer to read from
+ *
+ * Returns the size of the subbuffer. Note, this size is
+ * where the last event resides. The stored subbuffer may actually be
+ * bigger due to padding and such.
+ */
+int kbuffer_subbuffer_size(struct kbuffer *kbuf)
+{
+       return kbuf->size;
+}
+
+/**
+ * kbuffer_curr_index - Return the index of the record
+ * @kbuf:      The kbuffer to read from
+ *
+ * Returns the index from the start of the data part of
+ * the subbuffer to the current location. Note this is not
+ * from the start of the subbuffer. An index of zero will
+ * point to the first record. Use kbuffer_curr_offset() for
+ * the actually offset (that can be used by kbuffer_read_at_offset())
+ */
+int kbuffer_curr_index(struct kbuffer *kbuf)
+{
+       return kbuf->curr;
+}
+
+/**
+ * kbuffer_curr_offset - Return the offset of the record
+ * @kbuf:      The kbuffer to read from
+ *
+ * Returns the offset from the start of the subbuffer to the
+ * current location.
+ */
+int kbuffer_curr_offset(struct kbuffer *kbuf)
+{
+       return kbuf->curr + kbuf->start;
+}
+
+/**
+ * kbuffer_event_size - return the size of the event data
+ * @kbuf:      The kbuffer to read
+ *
+ * Returns the size of the event data (the payload not counting
+ * the meta data of the record) of the current event.
+ */
+int kbuffer_event_size(struct kbuffer *kbuf)
+{
+       return kbuf->next - kbuf->index;
+}
+
+/**
+ * kbuffer_curr_size - return the size of the entire record
+ * @kbuf:      The kbuffer to read
+ *
+ * Returns the size of the entire record (meta data and payload)
+ * of the current event.
+ */
+int kbuffer_curr_size(struct kbuffer *kbuf)
+{
+       return kbuf->next - kbuf->curr;
+}
+
+/**
+ * kbuffer_missed_events - return the # of missed events from last event.
+ * @kbuf:      The kbuffer to read from
+ *
+ * Returns the # of missed events (if recorded) before the current
+ * event. Note, only events on the beginning of a subbuffer can
+ * have missed events, all other events within the buffer will be
+ * zero.
+ */
+int kbuffer_missed_events(struct kbuffer *kbuf)
+{
+       /* Only the first event can have missed events */
+       if (kbuf->curr)
+               return 0;
+
+       return kbuf->lost_events;
+}
+
+/**
+ * kbuffer_set_old_forma - set the kbuffer to use the old format parsing
+ * @kbuf:      The kbuffer to set
+ *
+ * This is obsolete (or should be). The first kernels to use the
+ * new ring buffer had a slightly different ring buffer format
+ * (2.6.30 and earlier). It is still somewhat supported by kbuffer,
+ * but should not be counted on in the future.
+ */
+void kbuffer_set_old_format(struct kbuffer *kbuf)
+{
+       kbuf->flags |= KBUFFER_FL_OLD_FORMAT;
+
+       kbuf->next_event = __old_next_event;
+}
diff --git a/tools/lib/traceevent/kbuffer.h b/tools/lib/traceevent/kbuffer.h
new file mode 100644 (file)
index 0000000..c831f64
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2012 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License (not later!)
+ *
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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 _KBUFFER_H
+#define _KBUFFER_H
+
+#ifndef TS_SHIFT
+#define TS_SHIFT               27
+#endif
+
+enum kbuffer_endian {
+       KBUFFER_ENDIAN_BIG,
+       KBUFFER_ENDIAN_LITTLE,
+};
+
+enum kbuffer_long_size {
+       KBUFFER_LSIZE_4,
+       KBUFFER_LSIZE_8,
+};
+
+enum {
+       KBUFFER_TYPE_PADDING            = 29,
+       KBUFFER_TYPE_TIME_EXTEND        = 30,
+       KBUFFER_TYPE_TIME_STAMP         = 31,
+};
+
+struct kbuffer;
+
+struct kbuffer *kbuffer_alloc(enum kbuffer_long_size size, enum kbuffer_endian endian);
+void kbuffer_free(struct kbuffer *kbuf);
+int kbuffer_load_subbuffer(struct kbuffer *kbuf, void *subbuffer);
+void *kbuffer_read_event(struct kbuffer *kbuf, unsigned long long *ts);
+void *kbuffer_next_event(struct kbuffer *kbuf, unsigned long long *ts);
+unsigned long long kbuffer_timestamp(struct kbuffer *kbuf);
+
+void *kbuffer_translate_data(int swap, void *data, unsigned int *size);
+
+void *kbuffer_read_at_offset(struct kbuffer *kbuf, int offset, unsigned long long *ts);
+
+int kbuffer_curr_index(struct kbuffer *kbuf);
+
+int kbuffer_curr_offset(struct kbuffer *kbuf);
+int kbuffer_curr_size(struct kbuffer *kbuf);
+int kbuffer_event_size(struct kbuffer *kbuf);
+int kbuffer_missed_events(struct kbuffer *kbuf);
+int kbuffer_subbuffer_size(struct kbuffer *kbuf);
+
+void kbuffer_set_old_format(struct kbuffer *kbuf);
+
+#endif /* _K_BUFFER_H */
index a57db805136a2c205c6284d65045c2cbd5ee471d..d7f2e68bc5b91d190e2ad5cd34388b45d957372a 100644 (file)
@@ -48,6 +48,19 @@ void trace_seq_init(struct trace_seq *s)
        s->buffer = malloc_or_die(s->buffer_size);
 }
 
+/**
+ * trace_seq_reset - re-initialize the trace_seq structure
+ * @s: a pointer to the trace_seq structure to reset
+ */
+void trace_seq_reset(struct trace_seq *s)
+{
+       if (!s)
+               return;
+       TRACE_SEQ_CHECK(s);
+       s->len = 0;
+       s->readpos = 0;
+}
+
 /**
  * trace_seq_destroy - free up memory of a trace_seq
  * @s: a pointer to the trace_seq to free the buffer
index 5b3123d5721f94286a62979a3aabad8c6c7a0e7f..fdfceee0ffd0ee3d046ca6bd5beef633fd619199 100644 (file)
@@ -3,17 +3,17 @@ perf-diff(1)
 
 NAME
 ----
-perf-diff - Read two perf.data files and display the differential profile
+perf-diff - Read perf.data files and display the differential profile
 
 SYNOPSIS
 --------
 [verse]
-'perf diff' [oldfile] [newfile]
+'perf diff' [baseline file] [data file1] [[data file2] ... ]
 
 DESCRIPTION
 -----------
-This command displays the performance difference amongst two perf.data files
-captured via perf record.
+This command displays the performance difference amongst two or more perf.data
+files captured via perf record.
 
 If no parameters are passed it will assume perf.data.old and perf.data.
 
@@ -75,8 +75,6 @@ OPTIONS
 -c::
 --compute::
         Differential computation selection - delta,ratio,wdiff (default is delta).
-        If '+' is specified as a first character, the output is sorted based
-        on the computation results.
         See COMPARISON METHODS section for more info.
 
 -p::
@@ -87,6 +85,63 @@ OPTIONS
 --formula::
         Show formula for given computation.
 
+-o::
+--order::
+       Specify compute sorting column number.
+
+COMPARISON
+----------
+The comparison is governed by the baseline file. The baseline perf.data
+file is iterated for samples. All other perf.data files specified on
+the command line are searched for the baseline sample pair. If the pair
+is found, specified computation is made and result is displayed.
+
+All samples from non-baseline perf.data files, that do not match any
+baseline entry, are displayed with empty space within baseline column
+and possible computation results (delta) in their related column.
+
+Example files samples:
+- file A with samples f1, f2, f3, f4,    f6
+- file B with samples     f2,     f4, f5
+- file C with samples f1, f2,         f5
+
+Example output:
+  x - computation takes place for pair
+  b - baseline sample percentage
+
+- perf diff A B C
+
+  baseline/A compute/B compute/C  samples
+  ---------------------------------------
+  b                    x          f1
+  b          x         x          f2
+  b                               f3
+  b          x                    f4
+  b                               f6
+             x         x          f5
+
+- perf diff B A C
+
+  baseline/B compute/A compute/C  samples
+  ---------------------------------------
+  b          x         x          f2
+  b          x                    f4
+  b                    x          f5
+             x         x          f1
+             x                    f3
+             x                    f6
+
+- perf diff C B A
+
+  baseline/C compute/B compute/A  samples
+  ---------------------------------------
+  b                    x          f1
+  b          x         x          f2
+  b          x                    f5
+                       x          f3
+             x         x          f4
+                       x          f6
+
 COMPARISON METHODS
 ------------------
 delta
@@ -96,7 +151,7 @@ If specified the 'Delta' column is displayed with value 'd' computed as:
   d = A->period_percent - B->period_percent
 
 with:
-  - A/B being matching hist entry from first/second file specified
+  - A/B being matching hist entry from data/baseline file specified
     (or perf.data/perf.data.old) respectively.
 
   - period_percent being the % of the hist entry period value within
@@ -109,24 +164,26 @@ If specified the 'Ratio' column is displayed with value 'r' computed as:
   r = A->period / B->period
 
 with:
-  - A/B being matching hist entry from first/second file specified
+  - A/B being matching hist entry from data/baseline file specified
     (or perf.data/perf.data.old) respectively.
 
   - period being the hist entry period value
 
-wdiff
-~~~~~
+wdiff:WEIGHT-B,WEIGHT-A
+~~~~~~~~~~~~~~~~~~~~~~~
 If specified the 'Weighted diff' column is displayed with value 'd' computed as:
 
    d = B->period * WEIGHT-A - A->period * WEIGHT-B
 
-  - A/B being matching hist entry from first/second file specified
+  - A/B being matching hist entry from data/baseline file specified
     (or perf.data/perf.data.old) respectively.
 
   - period being the hist entry period value
 
   - WEIGHT-A/WEIGHT-B being user suplied weights in the the '-c' option
     behind ':' separator like '-c wdiff:1,2'.
+    - WIEGHT-A being the weight of the data file
+    - WIEGHT-B being the weight of the baseline data file
 
 SEE ALSO
 --------
index d1e39dc8c81077071cc7e6a1976c0ef7028982e5..826f3d6d1d289ee34480ca977e097f7243e70719 100644 (file)
@@ -8,7 +8,7 @@ perf-list - List all symbolic event types
 SYNOPSIS
 --------
 [verse]
-'perf list' [hw|sw|cache|tracepoint|event_glob]
+'perf list' [hw|sw|cache|tracepoint|pmu|event_glob]
 
 DESCRIPTION
 -----------
@@ -104,6 +104,8 @@ To limit the list use:
   'subsys_glob:event_glob' to filter by tracepoint subsystems such as sched,
   block, etc.
 
+. 'pmu' to print the kernel supplied PMU events.
+
 . If none of the above is matched, it will apply the supplied glob to all
   events, printing the ones that match.
 
index 66dab7410c1d352f3583f541de5d1160cffa9085..2b8097ee39d83c194fd8393a0a1a3e2b67e40b65 100644 (file)
@@ -115,7 +115,7 @@ OPTIONS
 --dump-raw-trace::
         Dump raw trace in ASCII.
 
--g [type,min[,limit],order]::
+-g [type,min[,limit],order[,key]]::
 --call-graph::
         Display call chains using type, min percent threshold, optional print
        limit and order.
@@ -129,12 +129,21 @@ OPTIONS
        - callee: callee based call graph.
        - caller: inverted caller based call graph.
 
-       Default: fractal,0.5,callee.
+       key can be:
+       - function: compare on functions
+       - address: compare on individual code addresses
+
+       Default: fractal,0.5,callee,function.
 
 -G::
 --inverted::
         alias for inverted caller based call graph.
 
+--ignore-callees=<regex>::
+        Ignore callees of the function(s) matching the given regex.
+        This has the effect of collecting the callers of each such
+        function into one place in the call-graph tree.
+
 --pretty=<key>::
         Pretty printing style.  key: normal, raw
 
index 7fdd1909e37601c7bfeb074800433bec3e8aa4ca..58d6598a968679fb4c020f9d932443a57f9feee8 100644 (file)
@@ -155,6 +155,11 @@ Default is to monitor all CPUS.
 
        Default: fractal,0.5,callee.
 
+--ignore-callees=<regex>::
+        Ignore callees of the function(s) matching the given regex.
+        This has the effect of collecting the callers of each such
+        function into one place in the call-graph tree.
+
 --percent-limit::
        Do not show entries which have an overhead under that percent.
        (Default: 0).
index 641fccddb249964e30de988a056f229e8265283f..bfd12d02a304687872e282c235f98b793d8424a6 100644 (file)
@@ -124,7 +124,7 @@ strip-libs = $(filter-out -l%,$(1))
 ifneq ($(OUTPUT),)
   TE_PATH=$(OUTPUT)
 ifneq ($(subdir),)
-  LK_PATH=$(objtree)/lib/lk/
+  LK_PATH=$(OUTPUT)/../lib/lk/
 else
   LK_PATH=$(OUTPUT)
 endif
@@ -281,7 +281,7 @@ LIB_H += util/cpumap.h
 LIB_H += util/top.h
 LIB_H += $(ARCH_INCLUDE)
 LIB_H += util/cgroup.h
-LIB_H += $(TRACE_EVENT_DIR)event-parse.h
+LIB_H += $(LIB_INCLUDE)traceevent/event-parse.h
 LIB_H += util/target.h
 LIB_H += util/rblist.h
 LIB_H += util/intlist.h
@@ -389,6 +389,9 @@ LIB_OBJS += $(OUTPUT)tests/bp_signal.o
 LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o
 LIB_OBJS += $(OUTPUT)tests/task-exit.o
 LIB_OBJS += $(OUTPUT)tests/sw-clock.o
+ifeq ($(ARCH),x86)
+LIB_OBJS += $(OUTPUT)tests/perf-time-to-tsc.o
+endif
 
 BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
 BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
@@ -631,10 +634,10 @@ $(OUTPUT)util/parse-events.o: util/parse-events.c $(OUTPUT)PERF-CFLAGS
        $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-redundant-decls $<
 
 $(OUTPUT)util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
+       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow -Wno-undef -Wno-switch-default $<
 
 $(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o: scripts/perl/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $<
+       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs -Wno-undef -Wno-switch-default $<
 
 $(OUTPUT)util/scripting-engines/trace-event-python.o: util/scripting-engines/trace-event-python.c $(OUTPUT)PERF-CFLAGS
        $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
index 815841c04eb2f9b6db3ebeb3692711559d74e655..8801fe02f206a93a97d7f7cc8a56094dffa1d05c 100644 (file)
@@ -6,3 +6,5 @@ ifndef NO_LIBUNWIND
 LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind.o
 endif
 LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/tsc.o
+LIB_H += arch/$(ARCH)/util/tsc.h
diff --git a/tools/perf/arch/x86/util/tsc.c b/tools/perf/arch/x86/util/tsc.c
new file mode 100644 (file)
index 0000000..f111744
--- /dev/null
@@ -0,0 +1,59 @@
+#include <stdbool.h>
+#include <errno.h>
+
+#include <linux/perf_event.h>
+
+#include "../../perf.h"
+#include "../../util/types.h"
+#include "../../util/debug.h"
+#include "tsc.h"
+
+u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc)
+{
+       u64 time, quot, rem;
+
+       time = ns - tc->time_zero;
+       quot = time / tc->time_mult;
+       rem  = time % tc->time_mult;
+       return (quot << tc->time_shift) +
+              (rem << tc->time_shift) / tc->time_mult;
+}
+
+u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc)
+{
+       u64 quot, rem;
+
+       quot = cyc >> tc->time_shift;
+       rem  = cyc & ((1 << tc->time_shift) - 1);
+       return tc->time_zero + quot * tc->time_mult +
+              ((rem * tc->time_mult) >> tc->time_shift);
+}
+
+int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
+                            struct perf_tsc_conversion *tc)
+{
+       bool cap_usr_time_zero;
+       u32 seq;
+       int i = 0;
+
+       while (1) {
+               seq = pc->lock;
+               rmb();
+               tc->time_mult = pc->time_mult;
+               tc->time_shift = pc->time_shift;
+               tc->time_zero = pc->time_zero;
+               cap_usr_time_zero = pc->cap_usr_time_zero;
+               rmb();
+               if (pc->lock == seq && !(seq & 1))
+                       break;
+               if (++i > 10000) {
+                       pr_debug("failed to get perf_event_mmap_page lock\n");
+                       return -EINVAL;
+               }
+       }
+
+       if (!cap_usr_time_zero)
+               return -EOPNOTSUPP;
+
+       return 0;
+}
diff --git a/tools/perf/arch/x86/util/tsc.h b/tools/perf/arch/x86/util/tsc.h
new file mode 100644 (file)
index 0000000..a24dec8
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef TOOLS_PERF_ARCH_X86_UTIL_TSC_H__
+#define TOOLS_PERF_ARCH_X86_UTIL_TSC_H__
+
+#include "../../util/types.h"
+
+struct perf_tsc_conversion {
+       u16 time_shift;
+       u32 time_mult;
+       u64 time_zero;
+};
+
+struct perf_event_mmap_page;
+
+int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
+                            struct perf_tsc_conversion *tc);
+
+u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc);
+u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc);
+
+#endif /* TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ */
index 25fd3f1966f193e50ee60d12802d0538f8e18693..8cdca43016b250109d8bdd3ea7568eb13229a125 100644 (file)
@@ -117,6 +117,8 @@ static void alloc_mem(void **dst, void **src, size_t length)
        *src = zalloc(length);
        if (!*src)
                die("memory allocation failed - maybe length is too large?\n");
+       /* Make sure to always replace the zero pages even if MMAP_THRESH is crossed */
+       memset(*src, 0, length);
 }
 
 static u64 do_memcpy_cycle(memcpy_t fn, size_t len, bool prefault)
index 0aac5f3e594d87674af00d9a5ef6172d05c16baf..93de3ac177c57cf284aad97e80ce68d74aa21ae9 100644 (file)
 #include "util/util.h"
 
 #include <stdlib.h>
+#include <math.h>
 
-static char const *input_old = "perf.data.old",
-                 *input_new = "perf.data";
-static char      diff__default_sort_order[] = "dso,symbol";
-static bool  force;
+/* Diff command specific HPP columns. */
+enum {
+       PERF_HPP_DIFF__BASELINE,
+       PERF_HPP_DIFF__PERIOD,
+       PERF_HPP_DIFF__PERIOD_BASELINE,
+       PERF_HPP_DIFF__DELTA,
+       PERF_HPP_DIFF__RATIO,
+       PERF_HPP_DIFF__WEIGHTED_DIFF,
+       PERF_HPP_DIFF__FORMULA,
+
+       PERF_HPP_DIFF__MAX_INDEX
+};
+
+struct diff_hpp_fmt {
+       struct perf_hpp_fmt      fmt;
+       int                      idx;
+       char                    *header;
+       int                      header_width;
+};
+
+struct data__file {
+       struct perf_session     *session;
+       const char              *file;
+       int                      idx;
+       struct hists            *hists;
+       struct diff_hpp_fmt      fmt[PERF_HPP_DIFF__MAX_INDEX];
+};
+
+static struct data__file *data__files;
+static int data__files_cnt;
+
+#define data__for_each_file_start(i, d, s)     \
+       for (i = s, d = &data__files[s];        \
+            i < data__files_cnt;               \
+            i++, d = &data__files[i])
+
+#define data__for_each_file(i, d) data__for_each_file_start(i, d, 0)
+#define data__for_each_file_new(i, d) data__for_each_file_start(i, d, 1)
+
+static char diff__default_sort_order[] = "dso,symbol";
+static bool force;
 static bool show_period;
 static bool show_formula;
 static bool show_baseline_only;
-static bool sort_compute;
+static unsigned int sort_compute;
 
 static s64 compute_wdiff_w1;
 static s64 compute_wdiff_w2;
@@ -46,6 +84,47 @@ const char *compute_names[COMPUTE_MAX] = {
 
 static int compute;
 
+static int compute_2_hpp[COMPUTE_MAX] = {
+       [COMPUTE_DELTA]         = PERF_HPP_DIFF__DELTA,
+       [COMPUTE_RATIO]         = PERF_HPP_DIFF__RATIO,
+       [COMPUTE_WEIGHTED_DIFF] = PERF_HPP_DIFF__WEIGHTED_DIFF,
+};
+
+#define MAX_COL_WIDTH 70
+
+static struct header_column {
+       const char *name;
+       int width;
+} columns[PERF_HPP_DIFF__MAX_INDEX] = {
+       [PERF_HPP_DIFF__BASELINE] = {
+               .name  = "Baseline",
+       },
+       [PERF_HPP_DIFF__PERIOD] = {
+               .name  = "Period",
+               .width = 14,
+       },
+       [PERF_HPP_DIFF__PERIOD_BASELINE] = {
+               .name  = "Base period",
+               .width = 14,
+       },
+       [PERF_HPP_DIFF__DELTA] = {
+               .name  = "Delta",
+               .width = 7,
+       },
+       [PERF_HPP_DIFF__RATIO] = {
+               .name  = "Ratio",
+               .width = 14,
+       },
+       [PERF_HPP_DIFF__WEIGHTED_DIFF] = {
+               .name  = "Weighted diff",
+               .width = 14,
+       },
+       [PERF_HPP_DIFF__FORMULA] = {
+               .name  = "Formula",
+               .width = MAX_COL_WIDTH,
+       }
+};
+
 static int setup_compute_opt_wdiff(char *opt)
 {
        char *w1_str = opt;
@@ -109,13 +188,6 @@ static int setup_compute(const struct option *opt, const char *str,
                return 0;
        }
 
-       if (*str == '+') {
-               sort_compute = true;
-               cstr = (char *) ++str;
-               if (!*str)
-                       return 0;
-       }
-
        option = strchr(str, ':');
        if (option) {
                unsigned len = option++ - str;
@@ -145,42 +217,42 @@ static int setup_compute(const struct option *opt, const char *str,
        return -EINVAL;
 }
 
-double perf_diff__period_percent(struct hist_entry *he, u64 period)
+static double period_percent(struct hist_entry *he, u64 period)
 {
        u64 total = he->hists->stats.total_period;
        return (period * 100.0) / total;
 }
 
-double perf_diff__compute_delta(struct hist_entry *he, struct hist_entry *pair)
+static double compute_delta(struct hist_entry *he, struct hist_entry *pair)
 {
-       double new_percent = perf_diff__period_percent(he, he->stat.period);
-       double old_percent = perf_diff__period_percent(pair, pair->stat.period);
+       double old_percent = period_percent(he, he->stat.period);
+       double new_percent = period_percent(pair, pair->stat.period);
 
-       he->diff.period_ratio_delta = new_percent - old_percent;
-       he->diff.computed = true;
-       return he->diff.period_ratio_delta;
+       pair->diff.period_ratio_delta = new_percent - old_percent;
+       pair->diff.computed = true;
+       return pair->diff.period_ratio_delta;
 }
 
-double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair)
+static double compute_ratio(struct hist_entry *he, struct hist_entry *pair)
 {
-       double new_period = he->stat.period;
-       double old_period = pair->stat.period;
+       double old_period = he->stat.period ?: 1;
+       double new_period = pair->stat.period;
 
-       he->diff.computed = true;
-       he->diff.period_ratio = new_period / old_period;
-       return he->diff.period_ratio;
+       pair->diff.computed = true;
+       pair->diff.period_ratio = new_period / old_period;
+       return pair->diff.period_ratio;
 }
 
-s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair)
+static s64 compute_wdiff(struct hist_entry *he, struct hist_entry *pair)
 {
-       u64 new_period = he->stat.period;
-       u64 old_period = pair->stat.period;
+       u64 old_period = he->stat.period;
+       u64 new_period = pair->stat.period;
 
-       he->diff.computed = true;
-       he->diff.wdiff = new_period * compute_wdiff_w2 -
-                        old_period * compute_wdiff_w1;
+       pair->diff.computed = true;
+       pair->diff.wdiff = new_period * compute_wdiff_w2 -
+                          old_period * compute_wdiff_w1;
 
-       return he->diff.wdiff;
+       return pair->diff.wdiff;
 }
 
 static int formula_delta(struct hist_entry *he, struct hist_entry *pair,
@@ -189,15 +261,15 @@ static int formula_delta(struct hist_entry *he, struct hist_entry *pair,
        return scnprintf(buf, size,
                         "(%" PRIu64 " * 100 / %" PRIu64 ") - "
                         "(%" PRIu64 " * 100 / %" PRIu64 ")",
-                         he->stat.period, he->hists->stats.total_period,
-                         pair->stat.period, pair->hists->stats.total_period);
+                         pair->stat.period, pair->hists->stats.total_period,
+                         he->stat.period, he->hists->stats.total_period);
 }
 
 static int formula_ratio(struct hist_entry *he, struct hist_entry *pair,
                         char *buf, size_t size)
 {
-       double new_period = he->stat.period;
-       double old_period = pair->stat.period;
+       double old_period = he->stat.period;
+       double new_period = pair->stat.period;
 
        return scnprintf(buf, size, "%.0F / %.0F", new_period, old_period);
 }
@@ -205,16 +277,16 @@ static int formula_ratio(struct hist_entry *he, struct hist_entry *pair,
 static int formula_wdiff(struct hist_entry *he, struct hist_entry *pair,
                         char *buf, size_t size)
 {
-       u64 new_period = he->stat.period;
-       u64 old_period = pair->stat.period;
+       u64 old_period = he->stat.period;
+       u64 new_period = pair->stat.period;
 
        return scnprintf(buf, size,
                  "(%" PRIu64 " * " "%" PRId64 ") - (%" PRIu64 " * " "%" PRId64 ")",
                  new_period, compute_wdiff_w2, old_period, compute_wdiff_w1);
 }
 
-int perf_diff__formula(struct hist_entry *he, struct hist_entry *pair,
-                      char *buf, size_t size)
+static int formula_fprintf(struct hist_entry *he, struct hist_entry *pair,
+                          char *buf, size_t size)
 {
        switch (compute) {
        case COMPUTE_DELTA:
@@ -299,6 +371,29 @@ static void perf_evlist__collapse_resort(struct perf_evlist *evlist)
        }
 }
 
+static struct hist_entry*
+get_pair_data(struct hist_entry *he, struct data__file *d)
+{
+       if (hist_entry__has_pairs(he)) {
+               struct hist_entry *pair;
+
+               list_for_each_entry(pair, &he->pairs.head, pairs.node)
+                       if (pair->hists == d->hists)
+                               return pair;
+       }
+
+       return NULL;
+}
+
+static struct hist_entry*
+get_pair_fmt(struct hist_entry *he, struct diff_hpp_fmt *dfmt)
+{
+       void *ptr = dfmt - dfmt->idx;
+       struct data__file *d = container_of(ptr, struct data__file, fmt);
+
+       return get_pair_data(he, d);
+}
+
 static void hists__baseline_only(struct hists *hists)
 {
        struct rb_root *root;
@@ -333,22 +428,24 @@ static void hists__precompute(struct hists *hists)
 
        next = rb_first(root);
        while (next != NULL) {
-               struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node_in);
-               struct hist_entry *pair = hist_entry__next_pair(he);
+               struct hist_entry *he, *pair;
 
+               he   = rb_entry(next, struct hist_entry, rb_node_in);
                next = rb_next(&he->rb_node_in);
+
+               pair = get_pair_data(he, &data__files[sort_compute]);
                if (!pair)
                        continue;
 
                switch (compute) {
                case COMPUTE_DELTA:
-                       perf_diff__compute_delta(he, pair);
+                       compute_delta(he, pair);
                        break;
                case COMPUTE_RATIO:
-                       perf_diff__compute_ratio(he, pair);
+                       compute_ratio(he, pair);
                        break;
                case COMPUTE_WEIGHTED_DIFF:
-                       perf_diff__compute_wdiff(he, pair);
+                       compute_wdiff(he, pair);
                        break;
                default:
                        BUG_ON(1);
@@ -367,7 +464,7 @@ static int64_t cmp_doubles(double l, double r)
 }
 
 static int64_t
-hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
+__hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
                        int c)
 {
        switch (c) {
@@ -399,6 +496,36 @@ hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
        return 0;
 }
 
+static int64_t
+hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
+                       int c)
+{
+       bool pairs_left  = hist_entry__has_pairs(left);
+       bool pairs_right = hist_entry__has_pairs(right);
+       struct hist_entry *p_right, *p_left;
+
+       if (!pairs_left && !pairs_right)
+               return 0;
+
+       if (!pairs_left || !pairs_right)
+               return pairs_left ? -1 : 1;
+
+       p_left  = get_pair_data(left,  &data__files[sort_compute]);
+       p_right = get_pair_data(right, &data__files[sort_compute]);
+
+       if (!p_left && !p_right)
+               return 0;
+
+       if (!p_left || !p_right)
+               return p_left ? -1 : 1;
+
+       /*
+        * We have 2 entries of same kind, let's
+        * make the data comparison.
+        */
+       return __hist_entry__cmp_compute(p_left, p_right, c);
+}
+
 static void insert_hist_entry_by_compute(struct rb_root *root,
                                         struct hist_entry *he,
                                         int c)
@@ -448,75 +575,121 @@ static void hists__compute_resort(struct hists *hists)
        }
 }
 
-static void hists__process(struct hists *old, struct hists *new)
+static void hists__process(struct hists *hists)
 {
-       hists__match(new, old);
-
        if (show_baseline_only)
-               hists__baseline_only(new);
-       else
-               hists__link(new, old);
+               hists__baseline_only(hists);
 
        if (sort_compute) {
-               hists__precompute(new);
-               hists__compute_resort(new);
+               hists__precompute(hists);
+               hists__compute_resort(hists);
        } else {
-               hists__output_resort(new);
+               hists__output_resort(hists);
        }
 
-       hists__fprintf(new, true, 0, 0, 0, stdout);
+       hists__fprintf(hists, true, 0, 0, 0, stdout);
 }
 
-static int __cmd_diff(void)
+static void data__fprintf(void)
 {
-       int ret, i;
-#define older (session[0])
-#define newer (session[1])
-       struct perf_session *session[2];
-       struct perf_evlist *evlist_new, *evlist_old;
-       struct perf_evsel *evsel;
+       struct data__file *d;
+       int i;
+
+       fprintf(stdout, "# Data files:\n");
+
+       data__for_each_file(i, d)
+               fprintf(stdout, "#  [%d] %s %s\n",
+                       d->idx, d->file,
+                       !d->idx ? "(Baseline)" : "");
+
+       fprintf(stdout, "#\n");
+}
+
+static void data_process(void)
+{
+       struct perf_evlist *evlist_base = data__files[0].session->evlist;
+       struct perf_evsel *evsel_base;
        bool first = true;
 
-       older = perf_session__new(input_old, O_RDONLY, force, false,
-                                 &tool);
-       newer = perf_session__new(input_new, O_RDONLY, force, false,
-                                 &tool);
-       if (session[0] == NULL || session[1] == NULL)
-               return -ENOMEM;
+       list_for_each_entry(evsel_base, &evlist_base->entries, node) {
+               struct data__file *d;
+               int i;
 
-       for (i = 0; i < 2; ++i) {
-               ret = perf_session__process_events(session[i], &tool);
-               if (ret)
-                       goto out_delete;
-       }
+               data__for_each_file_new(i, d) {
+                       struct perf_evlist *evlist = d->session->evlist;
+                       struct perf_evsel *evsel;
 
-       evlist_old = older->evlist;
-       evlist_new = newer->evlist;
+                       evsel = evsel_match(evsel_base, evlist);
+                       if (!evsel)
+                               continue;
 
-       perf_evlist__collapse_resort(evlist_old);
-       perf_evlist__collapse_resort(evlist_new);
+                       d->hists = &evsel->hists;
 
-       list_for_each_entry(evsel, &evlist_new->entries, node) {
-               struct perf_evsel *evsel_old;
+                       hists__match(&evsel_base->hists, &evsel->hists);
 
-               evsel_old = evsel_match(evsel, evlist_old);
-               if (!evsel_old)
-                       continue;
+                       if (!show_baseline_only)
+                               hists__link(&evsel_base->hists,
+                                           &evsel->hists);
+               }
 
                fprintf(stdout, "%s# Event '%s'\n#\n", first ? "" : "\n",
-                       perf_evsel__name(evsel));
+                       perf_evsel__name(evsel_base));
 
                first = false;
 
-               hists__process(&evsel_old->hists, &evsel->hists);
+               if (verbose || data__files_cnt > 2)
+                       data__fprintf();
+
+               hists__process(&evsel_base->hists);
+       }
+}
+
+static void data__free(struct data__file *d)
+{
+       int col;
+
+       for (col = 0; col < PERF_HPP_DIFF__MAX_INDEX; col++) {
+               struct diff_hpp_fmt *fmt = &d->fmt[col];
+
+               free(fmt->header);
        }
+}
 
-out_delete:
-       for (i = 0; i < 2; ++i)
-               perf_session__delete(session[i]);
+static int __cmd_diff(void)
+{
+       struct data__file *d;
+       int ret = -EINVAL, i;
+
+       data__for_each_file(i, d) {
+               d->session = perf_session__new(d->file, O_RDONLY, force,
+                                              false, &tool);
+               if (!d->session) {
+                       pr_err("Failed to open %s\n", d->file);
+                       ret = -ENOMEM;
+                       goto out_delete;
+               }
+
+               ret = perf_session__process_events(d->session, &tool);
+               if (ret) {
+                       pr_err("Failed to process %s\n", d->file);
+                       goto out_delete;
+               }
+
+               perf_evlist__collapse_resort(d->session->evlist);
+       }
+
+       data_process();
+
+ out_delete:
+       data__for_each_file(i, d) {
+               if (d->session)
+                       perf_session__delete(d->session);
+
+               data__free(d);
+       }
+
+       free(data__files);
        return ret;
-#undef older
-#undef newer
 }
 
 static const char * const diff_usage[] = {
@@ -555,61 +728,310 @@ static const struct option options[] = {
                   "columns '.' is reserved."),
        OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
                    "Look for files with symbols relative to this directory"),
+       OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."),
        OPT_END()
 };
 
-static void ui_init(void)
+static double baseline_percent(struct hist_entry *he)
 {
-       /*
-        * Display baseline/delta/ratio
-        * formula/periods columns.
-        */
-       perf_hpp__column_enable(PERF_HPP__BASELINE);
+       struct hists *hists = he->hists;
+       return 100.0 * he->stat.period / hists->stats.total_period;
+}
 
-       switch (compute) {
-       case COMPUTE_DELTA:
-               perf_hpp__column_enable(PERF_HPP__DELTA);
+static int hpp__color_baseline(struct perf_hpp_fmt *fmt,
+                              struct perf_hpp *hpp, struct hist_entry *he)
+{
+       struct diff_hpp_fmt *dfmt =
+               container_of(fmt, struct diff_hpp_fmt, fmt);
+       double percent = baseline_percent(he);
+       char pfmt[20] = " ";
+
+       if (!he->dummy) {
+               scnprintf(pfmt, 20, "%%%d.2f%%%%", dfmt->header_width - 1);
+               return percent_color_snprintf(hpp->buf, hpp->size,
+                                             pfmt, percent);
+       } else
+               return scnprintf(hpp->buf, hpp->size, "%*s",
+                                dfmt->header_width, pfmt);
+}
+
+static int hpp__entry_baseline(struct hist_entry *he, char *buf, size_t size)
+{
+       double percent = baseline_percent(he);
+       const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
+       int ret = 0;
+
+       if (!he->dummy)
+               ret = scnprintf(buf, size, fmt, percent);
+
+       return ret;
+}
+
+static void
+hpp__entry_unpair(struct hist_entry *he, int idx, char *buf, size_t size)
+{
+       switch (idx) {
+       case PERF_HPP_DIFF__PERIOD_BASELINE:
+               scnprintf(buf, size, "%" PRIu64, he->stat.period);
                break;
-       case COMPUTE_RATIO:
-               perf_hpp__column_enable(PERF_HPP__RATIO);
+
+       default:
                break;
-       case COMPUTE_WEIGHTED_DIFF:
-               perf_hpp__column_enable(PERF_HPP__WEIGHTED_DIFF);
+       }
+}
+
+static void
+hpp__entry_pair(struct hist_entry *he, struct hist_entry *pair,
+               int idx, char *buf, size_t size)
+{
+       double diff;
+       double ratio;
+       s64 wdiff;
+
+       switch (idx) {
+       case PERF_HPP_DIFF__DELTA:
+               if (pair->diff.computed)
+                       diff = pair->diff.period_ratio_delta;
+               else
+                       diff = compute_delta(he, pair);
+
+               if (fabs(diff) >= 0.01)
+                       scnprintf(buf, size, "%+4.2F%%", diff);
+               break;
+
+       case PERF_HPP_DIFF__RATIO:
+               /* No point for ratio number if we are dummy.. */
+               if (he->dummy)
+                       break;
+
+               if (pair->diff.computed)
+                       ratio = pair->diff.period_ratio;
+               else
+                       ratio = compute_ratio(he, pair);
+
+               if (ratio > 0.0)
+                       scnprintf(buf, size, "%14.6F", ratio);
+               break;
+
+       case PERF_HPP_DIFF__WEIGHTED_DIFF:
+               /* No point for wdiff number if we are dummy.. */
+               if (he->dummy)
+                       break;
+
+               if (pair->diff.computed)
+                       wdiff = pair->diff.wdiff;
+               else
+                       wdiff = compute_wdiff(he, pair);
+
+               if (wdiff != 0)
+                       scnprintf(buf, size, "%14ld", wdiff);
+               break;
+
+       case PERF_HPP_DIFF__FORMULA:
+               formula_fprintf(he, pair, buf, size);
+               break;
+
+       case PERF_HPP_DIFF__PERIOD:
+               scnprintf(buf, size, "%" PRIu64, pair->stat.period);
                break;
+
        default:
                BUG_ON(1);
        };
+}
+
+static void
+__hpp__entry_global(struct hist_entry *he, struct diff_hpp_fmt *dfmt,
+                   char *buf, size_t size)
+{
+       struct hist_entry *pair = get_pair_fmt(he, dfmt);
+       int idx = dfmt->idx;
+
+       /* baseline is special */
+       if (idx == PERF_HPP_DIFF__BASELINE)
+               hpp__entry_baseline(he, buf, size);
+       else {
+               if (pair)
+                       hpp__entry_pair(he, pair, idx, buf, size);
+               else
+                       hpp__entry_unpair(he, idx, buf, size);
+       }
+}
+
+static int hpp__entry_global(struct perf_hpp_fmt *_fmt, struct perf_hpp *hpp,
+                            struct hist_entry *he)
+{
+       struct diff_hpp_fmt *dfmt =
+               container_of(_fmt, struct diff_hpp_fmt, fmt);
+       char buf[MAX_COL_WIDTH] = " ";
+
+       __hpp__entry_global(he, dfmt, buf, MAX_COL_WIDTH);
+
+       if (symbol_conf.field_sep)
+               return scnprintf(hpp->buf, hpp->size, "%s", buf);
+       else
+               return scnprintf(hpp->buf, hpp->size, "%*s",
+                                dfmt->header_width, buf);
+}
+
+static int hpp__header(struct perf_hpp_fmt *fmt,
+                      struct perf_hpp *hpp)
+{
+       struct diff_hpp_fmt *dfmt =
+               container_of(fmt, struct diff_hpp_fmt, fmt);
 
-       if (show_formula)
-               perf_hpp__column_enable(PERF_HPP__FORMULA);
+       BUG_ON(!dfmt->header);
+       return scnprintf(hpp->buf, hpp->size, dfmt->header);
+}
 
-       if (show_period) {
-               perf_hpp__column_enable(PERF_HPP__PERIOD);
-               perf_hpp__column_enable(PERF_HPP__PERIOD_BASELINE);
+static int hpp__width(struct perf_hpp_fmt *fmt,
+                     struct perf_hpp *hpp __maybe_unused)
+{
+       struct diff_hpp_fmt *dfmt =
+               container_of(fmt, struct diff_hpp_fmt, fmt);
+
+       BUG_ON(dfmt->header_width <= 0);
+       return dfmt->header_width;
+}
+
+static void init_header(struct data__file *d, struct diff_hpp_fmt *dfmt)
+{
+#define MAX_HEADER_NAME 100
+       char buf_indent[MAX_HEADER_NAME];
+       char buf[MAX_HEADER_NAME];
+       const char *header = NULL;
+       int width = 0;
+
+       BUG_ON(dfmt->idx >= PERF_HPP_DIFF__MAX_INDEX);
+       header = columns[dfmt->idx].name;
+       width  = columns[dfmt->idx].width;
+
+       /* Only our defined HPP fmts should appear here. */
+       BUG_ON(!header);
+
+       if (data__files_cnt > 2)
+               scnprintf(buf, MAX_HEADER_NAME, "%s/%d", header, d->idx);
+
+#define NAME (data__files_cnt > 2 ? buf : header)
+       dfmt->header_width = width;
+       width = (int) strlen(NAME);
+       if (dfmt->header_width < width)
+               dfmt->header_width = width;
+
+       scnprintf(buf_indent, MAX_HEADER_NAME, "%*s",
+                 dfmt->header_width, NAME);
+
+       dfmt->header = strdup(buf_indent);
+#undef MAX_HEADER_NAME
+#undef NAME
+}
+
+static void data__hpp_register(struct data__file *d, int idx)
+{
+       struct diff_hpp_fmt *dfmt = &d->fmt[idx];
+       struct perf_hpp_fmt *fmt = &dfmt->fmt;
+
+       dfmt->idx = idx;
+
+       fmt->header = hpp__header;
+       fmt->width  = hpp__width;
+       fmt->entry  = hpp__entry_global;
+
+       /* TODO more colors */
+       if (idx == PERF_HPP_DIFF__BASELINE)
+               fmt->color = hpp__color_baseline;
+
+       init_header(d, dfmt);
+       perf_hpp__column_register(fmt);
+}
+
+static void ui_init(void)
+{
+       struct data__file *d;
+       int i;
+
+       data__for_each_file(i, d) {
+
+               /*
+                * Baseline or compute realted columns:
+                *
+                *   PERF_HPP_DIFF__BASELINE
+                *   PERF_HPP_DIFF__DELTA
+                *   PERF_HPP_DIFF__RATIO
+                *   PERF_HPP_DIFF__WEIGHTED_DIFF
+                */
+               data__hpp_register(d, i ? compute_2_hpp[compute] :
+                                         PERF_HPP_DIFF__BASELINE);
+
+               /*
+                * And the rest:
+                *
+                * PERF_HPP_DIFF__FORMULA
+                * PERF_HPP_DIFF__PERIOD
+                * PERF_HPP_DIFF__PERIOD_BASELINE
+                */
+               if (show_formula && i)
+                       data__hpp_register(d, PERF_HPP_DIFF__FORMULA);
+
+               if (show_period)
+                       data__hpp_register(d, i ? PERF_HPP_DIFF__PERIOD :
+                                                 PERF_HPP_DIFF__PERIOD_BASELINE);
        }
 }
 
-int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
+static int data_init(int argc, const char **argv)
 {
-       sort_order = diff__default_sort_order;
-       argc = parse_options(argc, argv, options, diff_usage, 0);
+       struct data__file *d;
+       static const char *defaults[] = {
+               "perf.data.old",
+               "perf.data",
+       };
+       bool use_default = true;
+       int i;
+
+       data__files_cnt = 2;
+
        if (argc) {
-               if (argc > 2)
-                       usage_with_options(diff_usage, options);
-               if (argc == 2) {
-                       input_old = argv[0];
-                       input_new = argv[1];
-               } else
-                       input_new = argv[0];
+               if (argc == 1)
+                       defaults[1] = argv[0];
+               else {
+                       data__files_cnt = argc;
+                       use_default = false;
+               }
        } else if (symbol_conf.default_guest_vmlinux_name ||
                   symbol_conf.default_guest_kallsyms) {
-               input_old = "perf.data.host";
-               input_new = "perf.data.guest";
+               defaults[0] = "perf.data.host";
+               defaults[1] = "perf.data.guest";
        }
 
+       if (sort_compute >= (unsigned int) data__files_cnt) {
+               pr_err("Order option out of limit.\n");
+               return -EINVAL;
+       }
+
+       data__files = zalloc(sizeof(*data__files) * data__files_cnt);
+       if (!data__files)
+               return -ENOMEM;
+
+       data__for_each_file(i, d) {
+               d->file = use_default ? defaults[i] : argv[i];
+               d->idx  = i;
+       }
+
+       return 0;
+}
+
+int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
+{
+       sort_order = diff__default_sort_order;
+       argc = parse_options(argc, argv, options, diff_usage, 0);
+
        if (symbol__init() < 0)
                return -1;
 
+       if (data_init(argc, argv) < 0)
+               return -1;
+
        ui_init();
 
        if (setup_sorting() < 0)
index 84ad6abe42586a3bcb6d04aa5696cae6bf59b043..1d8de2e4a40740bf38297ed5163ef1cc679f7c01 100644 (file)
@@ -38,8 +38,7 @@ struct event_entry {
 };
 
 static int perf_event__repipe_synth(struct perf_tool *tool,
-                                   union perf_event *event,
-                                   struct machine *machine __maybe_unused)
+                                   union perf_event *event)
 {
        struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
        uint32_t size;
@@ -65,39 +64,28 @@ static int perf_event__repipe_op2_synth(struct perf_tool *tool,
                                        struct perf_session *session
                                        __maybe_unused)
 {
-       return perf_event__repipe_synth(tool, event, NULL);
+       return perf_event__repipe_synth(tool, event);
 }
 
-static int perf_event__repipe_event_type_synth(struct perf_tool *tool,
-                                              union perf_event *event)
-{
-       return perf_event__repipe_synth(tool, event, NULL);
-}
-
-static int perf_event__repipe_tracing_data_synth(union perf_event *event,
-                                                struct perf_session *session
-                                                __maybe_unused)
-{
-       return perf_event__repipe_synth(NULL, event, NULL);
-}
-
-static int perf_event__repipe_attr(union perf_event *event,
-                                  struct perf_evlist **pevlist __maybe_unused)
+static int perf_event__repipe_attr(struct perf_tool *tool,
+                                  union perf_event *event,
+                                  struct perf_evlist **pevlist)
 {
        int ret;
-       ret = perf_event__process_attr(event, pevlist);
+
+       ret = perf_event__process_attr(tool, event, pevlist);
        if (ret)
                return ret;
 
-       return perf_event__repipe_synth(NULL, event, NULL);
+       return perf_event__repipe_synth(tool, event);
 }
 
 static int perf_event__repipe(struct perf_tool *tool,
                              union perf_event *event,
                              struct perf_sample *sample __maybe_unused,
-                             struct machine *machine)
+                             struct machine *machine __maybe_unused)
 {
-       return perf_event__repipe_synth(tool, event, machine);
+       return perf_event__repipe_synth(tool, event);
 }
 
 typedef int (*inject_handler)(struct perf_tool *tool,
@@ -119,7 +107,7 @@ static int perf_event__repipe_sample(struct perf_tool *tool,
 
        build_id__mark_dso_hit(tool, event, sample, evsel, machine);
 
-       return perf_event__repipe_synth(tool, event, machine);
+       return perf_event__repipe_synth(tool, event);
 }
 
 static int perf_event__repipe_mmap(struct perf_tool *tool,
@@ -148,13 +136,14 @@ static int perf_event__repipe_fork(struct perf_tool *tool,
        return err;
 }
 
-static int perf_event__repipe_tracing_data(union perf_event *event,
+static int perf_event__repipe_tracing_data(struct perf_tool *tool,
+                                          union perf_event *event,
                                           struct perf_session *session)
 {
        int err;
 
-       perf_event__repipe_synth(NULL, event, NULL);
-       err = perf_event__process_tracing_data(event, session);
+       perf_event__repipe_synth(tool, event);
+       err = perf_event__process_tracing_data(tool, event, session);
 
        return err;
 }
@@ -407,8 +396,8 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
                        .throttle       = perf_event__repipe,
                        .unthrottle     = perf_event__repipe,
                        .attr           = perf_event__repipe_attr,
-                       .event_type     = perf_event__repipe_event_type_synth,
-                       .tracing_data   = perf_event__repipe_tracing_data_synth,
+                       .tracing_data   = perf_event__repipe_op2_synth,
+                       .finished_round = perf_event__repipe_op2_synth,
                        .build_id       = perf_event__repipe_op2_synth,
                },
                .input_name  = "-",
index 0259502638b47341cbd5c191391864b8f4df7dcf..b49f5c58e152df8d57806c94a91daa43ff96a5a1 100644 (file)
@@ -313,7 +313,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
                return -1;
        }
 
-       dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
+       dump_printf(" ... thread: %s:%d\n", thread->comm, thread->tid);
 
        if (evsel->handler.func != NULL) {
                tracepoint_handler f = evsel->handler.func;
index 1948eceb517a6dcf18c974552f08d4ba1c515461..e79f423cc3022fff357e132d11d573a66f5ad7a6 100644 (file)
@@ -13,6 +13,7 @@
 
 #include "util/parse-events.h"
 #include "util/cache.h"
+#include "util/pmu.h"
 
 int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
 {
@@ -37,6 +38,8 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
                        else if (strcmp(argv[i], "cache") == 0 ||
                                 strcmp(argv[i], "hwcache") == 0)
                                print_hwcache_events(NULL, false);
+                       else if (strcmp(argv[i], "pmu") == 0)
+                               print_pmu_events(NULL, false);
                        else if (strcmp(argv[i], "--raw-dump") == 0)
                                print_events(NULL, true);
                        else {
index ecca62e27b28f87a8a6c6d6aadf2515b1267f07b..a41ac41546c962df3e0801b230f06b4aa9730c7a 100644 (file)
@@ -474,13 +474,6 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
                        goto out_delete_session;
                }
 
-               err = perf_event__synthesize_event_types(tool, process_synthesized_event,
-                                                        machine);
-               if (err < 0) {
-                       pr_err("Couldn't synthesize event_types.\n");
-                       goto out_delete_session;
-               }
-
                if (have_tracepoints(&evsel_list->entries)) {
                        /*
                         * FIXME err <= 0 here actually means that
@@ -904,7 +897,6 @@ const struct option record_options[] = {
 int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
 {
        int err = -ENOMEM;
-       struct perf_evsel *pos;
        struct perf_evlist *evsel_list;
        struct perf_record *rec = &record;
        char errbuf[BUFSIZ];
@@ -968,11 +960,6 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
        if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0)
                usage_with_options(record_usage, record_options);
 
-       list_for_each_entry(pos, &evsel_list->entries, node) {
-               if (perf_header__push_event(pos->attr.config, perf_evsel__name(pos)))
-                       goto out_free_fd;
-       }
-
        if (rec->opts.user_interval != ULLONG_MAX)
                rec->opts.default_interval = rec->opts.user_interval;
        if (rec->opts.user_freq != UINT_MAX)
index 3662047cc6b1bcd881c8ca833988b2007cc66869..d785d89ed226a8cd8047b7159386450e559bc686 100644 (file)
@@ -89,7 +89,7 @@ static int perf_report__add_mem_hist_entry(struct perf_tool *tool,
        if ((sort__has_parent || symbol_conf.use_callchain) &&
            sample->callchain) {
                err = machine__resolve_callchain(machine, evsel, al->thread,
-                                                sample, &parent);
+                                                sample, &parent, al);
                if (err)
                        return err;
        }
@@ -180,7 +180,7 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
        if ((sort__has_parent || symbol_conf.use_callchain)
            && sample->callchain) {
                err = machine__resolve_callchain(machine, evsel, al->thread,
-                                                sample, &parent);
+                                                sample, &parent, al);
                if (err)
                        return err;
        }
@@ -254,7 +254,7 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,
 
        if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
                err = machine__resolve_callchain(machine, evsel, al->thread,
-                                                sample, &parent);
+                                                sample, &parent, al);
                if (err)
                        return err;
        }
@@ -497,7 +497,7 @@ static int __cmd_report(struct perf_report *rep)
                ret = perf_session__cpu_bitmap(session, rep->cpu_list,
                                               rep->cpu_bitmap);
                if (ret)
-                       goto out_delete;
+                       return ret;
        }
 
        if (use_browser <= 0)
@@ -508,11 +508,11 @@ static int __cmd_report(struct perf_report *rep)
 
        ret = perf_report__setup_sample_type(rep);
        if (ret)
-               goto out_delete;
+               return ret;
 
        ret = perf_session__process_events(session, &rep->tool);
        if (ret)
-               goto out_delete;
+               return ret;
 
        kernel_map = session->machines.host.vmlinux_maps[MAP__FUNCTION];
        kernel_kmap = map__kmap(kernel_map);
@@ -547,7 +547,7 @@ static int __cmd_report(struct perf_report *rep)
 
        if (dump_trace) {
                perf_session__fprintf_nr_events(session, stdout);
-               goto out_delete;
+               return 0;
        }
 
        nr_samples = 0;
@@ -572,7 +572,7 @@ static int __cmd_report(struct perf_report *rep)
 
        if (nr_samples == 0) {
                ui__error("The %s file has no samples!\n", session->filename);
-               goto out_delete;
+               return 0;
        }
 
        list_for_each_entry(pos, &session->evlist->entries, node)
@@ -598,19 +598,6 @@ static int __cmd_report(struct perf_report *rep)
        } else
                perf_evlist__tty_browse_hists(session->evlist, rep, help);
 
-out_delete:
-       /*
-        * Speed up the exit process, for large files this can
-        * take quite a while.
-        *
-        * XXX Enable this when using valgrind or if we ever
-        * librarize this command.
-        *
-        * Also experiment with obstacks to see how much speed
-        * up we'll get here.
-        *
-        * perf_session__delete(session);
-        */
        return ret;
 }
 
@@ -680,12 +667,23 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
        }
 
        /* get the call chain order */
-       if (!strcmp(tok2, "caller"))
+       if (!strncmp(tok2, "caller", strlen("caller")))
                callchain_param.order = ORDER_CALLER;
-       else if (!strcmp(tok2, "callee"))
+       else if (!strncmp(tok2, "callee", strlen("callee")))
                callchain_param.order = ORDER_CALLEE;
        else
                return -1;
+
+       /* Get the sort key */
+       tok2 = strtok(NULL, ",");
+       if (!tok2)
+               goto setup;
+       if (!strncmp(tok2, "function", strlen("function")))
+               callchain_param.key = CCKEY_FUNCTION;
+       else if (!strncmp(tok2, "address", strlen("address")))
+               callchain_param.key = CCKEY_ADDRESS;
+       else
+               return -1;
 setup:
        if (callchain_register_param(&callchain_param) < 0) {
                fprintf(stderr, "Can't register callchain params\n");
@@ -694,6 +692,24 @@ setup:
        return 0;
 }
 
+int
+report_parse_ignore_callees_opt(const struct option *opt __maybe_unused,
+                               const char *arg, int unset __maybe_unused)
+{
+       if (arg) {
+               int err = regcomp(&ignore_callees_regex, arg, REG_EXTENDED);
+               if (err) {
+                       char buf[BUFSIZ];
+                       regerror(err, &ignore_callees_regex, buf, sizeof(buf));
+                       pr_err("Invalid --ignore-callees regex: %s\n%s", arg, buf);
+                       return -1;
+               }
+               have_ignore_callees = 1;
+       }
+
+       return 0;
+}
+
 static int
 parse_branch_mode(const struct option *opt __maybe_unused,
                  const char *str __maybe_unused, int unset)
@@ -736,7 +752,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
                        .lost            = perf_event__process_lost,
                        .read            = process_read_event,
                        .attr            = perf_event__process_attr,
-                       .event_type      = perf_event__process_event_type,
                        .tracing_data    = perf_event__process_tracing_data,
                        .build_id        = perf_event__process_build_id,
                        .ordered_samples = true,
@@ -780,10 +795,13 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
        OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
                    "Only display entries with parent-match"),
        OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order",
-                    "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit and callchain order. "
-                    "Default: fractal,0.5,callee", &parse_callchain_opt, callchain_default_opt),
+                    "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address). "
+                    "Default: fractal,0.5,callee,function", &parse_callchain_opt, callchain_default_opt),
        OPT_BOOLEAN('G', "inverted", &report.inverted_callchain,
                    "alias for inverted call graph"),
+       OPT_CALLBACK(0, "ignore-callees", NULL, "regex",
+                  "ignore callees of these functions in call graphs",
+                  report_parse_ignore_callees_opt),
        OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
                   "only consider symbols in these dsos"),
        OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
@@ -853,7 +871,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
                setup_browser(true);
        else {
                use_browser = 0;
-               perf_hpp__column_enable(PERF_HPP__OVERHEAD);
                perf_hpp__init();
        }
 
@@ -931,14 +948,6 @@ repeat:
        if (parent_pattern != default_parent_pattern) {
                if (sort_dimension__add("parent") < 0)
                        goto error;
-
-               /*
-                * Only show the parent fields if we explicitly
-                * sort that way. If we only use parent machinery
-                * for filtering, we don't want it.
-                */
-               if (!strstr(sort_order, "parent"))
-                       sort_parent.elide = 1;
        }
 
        if (argc) {
index fed9ae432c166d2f8d179bfb8a1fd15123112a7f..948183adb6e51b1a9db1103ddb72fca1bfc6cee6 100644 (file)
@@ -1075,7 +1075,7 @@ static int latency_migrate_task_event(struct perf_sched *sched,
        if (!atoms) {
                if (thread_atoms_insert(sched, migrant))
                        return -1;
-               register_pid(sched, migrant->pid, migrant->comm);
+               register_pid(sched, migrant->tid, migrant->comm);
                atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid);
                if (!atoms) {
                        pr_err("migration-event: Internal tree error");
@@ -1115,7 +1115,7 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_
        sched->all_runtime += work_list->total_runtime;
        sched->all_count   += work_list->nb_atoms;
 
-       ret = printf("  %s:%d ", work_list->thread->comm, work_list->thread->pid);
+       ret = printf("  %s:%d ", work_list->thread->comm, work_list->thread->tid);
 
        for (i = 0; i < 24 - ret; i++)
                printf(" ");
@@ -1131,9 +1131,9 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_
 
 static int pid_cmp(struct work_atoms *l, struct work_atoms *r)
 {
-       if (l->thread->pid < r->thread->pid)
+       if (l->thread->tid < r->thread->tid)
                return -1;
-       if (l->thread->pid > r->thread->pid)
+       if (l->thread->tid > r->thread->tid)
                return 1;
 
        return 0;
@@ -1321,7 +1321,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
                        printf("*");
 
                if (sched->curr_thread[cpu]) {
-                       if (sched->curr_thread[cpu]->pid)
+                       if (sched->curr_thread[cpu]->tid)
                                printf("%2s ", sched->curr_thread[cpu]->shortname);
                        else
                                printf(".  ");
@@ -1332,7 +1332,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
        printf("  %12.6f secs ", (double)timestamp/1e9);
        if (new_shortname) {
                printf("%s => %s:%d\n",
-                       sched_in->shortname, sched_in->comm, sched_in->pid);
+                       sched_in->shortname, sched_in->comm, sched_in->tid);
        } else {
                printf("\n");
        }
@@ -1662,28 +1662,29 @@ static int __cmd_record(int argc, const char **argv)
        return cmd_record(i, rec_argv, NULL);
 }
 
+static const char default_sort_order[] = "avg, max, switch, runtime";
+static struct perf_sched sched = {
+       .tool = {
+               .sample          = perf_sched__process_tracepoint_sample,
+               .comm            = perf_event__process_comm,
+               .lost            = perf_event__process_lost,
+               .fork            = perf_event__process_fork,
+               .ordered_samples = true,
+       },
+       .cmp_pid              = LIST_HEAD_INIT(sched.cmp_pid),
+       .sort_list            = LIST_HEAD_INIT(sched.sort_list),
+       .start_work_mutex     = PTHREAD_MUTEX_INITIALIZER,
+       .work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER,
+       .curr_pid             = { [0 ... MAX_CPUS - 1] = -1 },
+       .sort_order           = default_sort_order,
+       .replay_repeat        = 10,
+       .profile_cpu          = -1,
+       .next_shortname1      = 'A',
+       .next_shortname2      = '0',
+};
+
 int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
 {
-       const char default_sort_order[] = "avg, max, switch, runtime";
-       struct perf_sched sched = {
-               .tool = {
-                       .sample          = perf_sched__process_tracepoint_sample,
-                       .comm            = perf_event__process_comm,
-                       .lost            = perf_event__process_lost,
-                       .fork            = perf_event__process_fork,
-                       .ordered_samples = true,
-               },
-               .cmp_pid              = LIST_HEAD_INIT(sched.cmp_pid),
-               .sort_list            = LIST_HEAD_INIT(sched.sort_list),
-               .start_work_mutex     = PTHREAD_MUTEX_INITIALIZER,
-               .work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER,
-               .curr_pid             = { [0 ... MAX_CPUS - 1] = -1 },
-               .sort_order           = default_sort_order,
-               .replay_repeat        = 10,
-               .profile_cpu          = -1,
-               .next_shortname1      = 'A',
-               .next_shortname2      = '0',
-       };
        const struct option latency_options[] = {
        OPT_STRING('s', "sort", &sched.sort_order, "key[,key2...]",
                   "sort by key(s): runtime, switch, avg, max"),
index 92d4658f56fb55a93415dbccb441c552724b0402..1cad370146738b85536efa2a2de9c979d87e4963 100644 (file)
@@ -24,6 +24,7 @@ static u64                    last_timestamp;
 static u64                     nr_unordered;
 extern const struct option     record_options[];
 static bool                    no_callchain;
+static bool                    latency_format;
 static bool                    system_wide;
 static const char              *cpu_list;
 static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
@@ -396,10 +397,10 @@ static void print_sample_bts(union perf_event *event,
 
 static void process_event(union perf_event *event, struct perf_sample *sample,
                          struct perf_evsel *evsel, struct machine *machine,
-                         struct addr_location *al)
+                         struct thread *thread,
+                         struct addr_location *al __maybe_unused)
 {
        struct perf_event_attr *attr = &evsel->attr;
-       struct thread *thread = al->thread;
 
        if (output[attr->type].fields == 0)
                return;
@@ -510,7 +511,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
        if (cpu_list && !test_bit(sample->cpu, cpu_bitmap))
                return 0;
 
-       scripting_ops->process_event(event, sample, evsel, machine, &al);
+       scripting_ops->process_event(event, sample, evsel, machine, thread, &al);
 
        evsel->hists.stats.total_period += sample->period;
        return 0;
@@ -523,7 +524,6 @@ static struct perf_tool perf_script = {
        .exit            = perf_event__process_exit,
        .fork            = perf_event__process_fork,
        .attr            = perf_event__process_attr,
-       .event_type      = perf_event__process_event_type,
        .tracing_data    = perf_event__process_tracing_data,
        .build_id        = perf_event__process_build_id,
        .ordered_samples = true,
index 4536a92b18f3196d9fa532ad193184d3d39b7af8..c2e02319347abd86c74f6ab0b44c37106c0fb238 100644 (file)
@@ -12,6 +12,8 @@
  * of the License.
  */
 
+#include <traceevent/event-parse.h>
+
 #include "builtin.h"
 
 #include "util/util.h"
@@ -19,6 +21,7 @@
 #include "util/color.h"
 #include <linux/list.h>
 #include "util/cache.h"
+#include "util/evlist.h"
 #include "util/evsel.h"
 #include <linux/rbtree.h>
 #include "util/symbol.h"
@@ -328,25 +331,6 @@ struct wakeup_entry {
        int   success;
 };
 
-/*
- * trace_flag_type is an enumeration that holds different
- * states when a trace occurs. These are:
- *  IRQS_OFF            - interrupts were disabled
- *  IRQS_NOSUPPORT      - arch does not support irqs_disabled_flags
- *  NEED_RESCED         - reschedule is requested
- *  HARDIRQ             - inside an interrupt handler
- *  SOFTIRQ             - inside a softirq handler
- */
-enum trace_flag_type {
-       TRACE_FLAG_IRQS_OFF             = 0x01,
-       TRACE_FLAG_IRQS_NOSUPPORT       = 0x02,
-       TRACE_FLAG_NEED_RESCHED         = 0x04,
-       TRACE_FLAG_HARDIRQ              = 0x08,
-       TRACE_FLAG_SOFTIRQ              = 0x10,
-};
-
-
-
 struct sched_switch {
        struct trace_entry te;
        char prev_comm[TASK_COMM_LEN];
@@ -479,6 +463,8 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te)
        }
 }
 
+typedef int (*tracepoint_handler)(struct perf_evsel *evsel,
+                                 struct perf_sample *sample);
 
 static int process_sample_event(struct perf_tool *tool __maybe_unused,
                                union perf_event *event __maybe_unused,
@@ -486,8 +472,6 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
                                struct perf_evsel *evsel,
                                struct machine *machine __maybe_unused)
 {
-       struct trace_entry *te;
-
        if (evsel->attr.sample_type & PERF_SAMPLE_TIME) {
                if (!first_time || first_time > sample->time)
                        first_time = sample->time;
@@ -495,69 +479,90 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
                        last_time = sample->time;
        }
 
-       te = (void *)sample->raw_data;
-       if ((evsel->attr.sample_type & PERF_SAMPLE_RAW) && sample->raw_size > 0) {
-               char *event_str;
-#ifdef SUPPORT_OLD_POWER_EVENTS
-               struct power_entry_old *peo;
-               peo = (void *)te;
-#endif
-               /*
-                * FIXME: use evsel, its already mapped from id to perf_evsel,
-                * remove perf_header__find_event infrastructure bits.
-                * Mapping all these "power:cpu_idle" strings to the tracepoint
-                * ID and then just comparing against evsel->attr.config.
-                *
-                * e.g.:
-                *
-                * if (evsel->attr.config == power_cpu_idle_id)
-                */
-               event_str = perf_header__find_event(te->type);
-
-               if (!event_str)
-                       return 0;
-
-               if (sample->cpu > numcpus)
-                       numcpus = sample->cpu;
-
-               if (strcmp(event_str, "power:cpu_idle") == 0) {
-                       struct power_processor_entry *ppe = (void *)te;
-                       if (ppe->state == (u32)PWR_EVENT_EXIT)
-                               c_state_end(ppe->cpu_id, sample->time);
-                       else
-                               c_state_start(ppe->cpu_id, sample->time,
-                                             ppe->state);
-               }
-               else if (strcmp(event_str, "power:cpu_frequency") == 0) {
-                       struct power_processor_entry *ppe = (void *)te;
-                       p_state_change(ppe->cpu_id, sample->time, ppe->state);
-               }
+       if (sample->cpu > numcpus)
+               numcpus = sample->cpu;
+
+       if (evsel->handler.func != NULL) {
+               tracepoint_handler f = evsel->handler.func;
+               return f(evsel, sample);
+       }
+
+       return 0;
+}
+
+static int
+process_sample_cpu_idle(struct perf_evsel *evsel __maybe_unused,
+                       struct perf_sample *sample)
+{
+       struct power_processor_entry *ppe = sample->raw_data;
+
+       if (ppe->state == (u32) PWR_EVENT_EXIT)
+               c_state_end(ppe->cpu_id, sample->time);
+       else
+               c_state_start(ppe->cpu_id, sample->time, ppe->state);
+       return 0;
+}
+
+static int
+process_sample_cpu_frequency(struct perf_evsel *evsel __maybe_unused,
+                            struct perf_sample *sample)
+{
+       struct power_processor_entry *ppe = sample->raw_data;
+
+       p_state_change(ppe->cpu_id, sample->time, ppe->state);
+       return 0;
+}
+
+static int
+process_sample_sched_wakeup(struct perf_evsel *evsel __maybe_unused,
+                           struct perf_sample *sample)
+{
+       struct trace_entry *te = sample->raw_data;
+
+       sched_wakeup(sample->cpu, sample->time, sample->pid, te);
+       return 0;
+}
 
-               else if (strcmp(event_str, "sched:sched_wakeup") == 0)
-                       sched_wakeup(sample->cpu, sample->time, sample->pid, te);
+static int
+process_sample_sched_switch(struct perf_evsel *evsel __maybe_unused,
+                           struct perf_sample *sample)
+{
+       struct trace_entry *te = sample->raw_data;
 
-               else if (strcmp(event_str, "sched:sched_switch") == 0)
-                       sched_switch(sample->cpu, sample->time, te);
+       sched_switch(sample->cpu, sample->time, te);
+       return 0;
+}
 
 #ifdef SUPPORT_OLD_POWER_EVENTS
-               if (use_old_power_events) {
-                       if (strcmp(event_str, "power:power_start") == 0)
-                               c_state_start(peo->cpu_id, sample->time,
-                                             peo->value);
-
-                       else if (strcmp(event_str, "power:power_end") == 0)
-                               c_state_end(sample->cpu, sample->time);
-
-                       else if (strcmp(event_str,
-                                       "power:power_frequency") == 0)
-                               p_state_change(peo->cpu_id, sample->time,
-                                              peo->value);
-               }
-#endif
-       }
+static int
+process_sample_power_start(struct perf_evsel *evsel __maybe_unused,
+                          struct perf_sample *sample)
+{
+       struct power_entry_old *peo = sample->raw_data;
+
+       c_state_start(peo->cpu_id, sample->time, peo->value);
        return 0;
 }
 
+static int
+process_sample_power_end(struct perf_evsel *evsel __maybe_unused,
+                        struct perf_sample *sample)
+{
+       c_state_end(sample->cpu, sample->time);
+       return 0;
+}
+
+static int
+process_sample_power_frequency(struct perf_evsel *evsel __maybe_unused,
+                              struct perf_sample *sample)
+{
+       struct power_entry_old *peo = sample->raw_data;
+
+       p_state_change(peo->cpu_id, sample->time, peo->value);
+       return 0;
+}
+#endif /* SUPPORT_OLD_POWER_EVENTS */
+
 /*
  * After the last sample we need to wrap up the current C/P state
  * and close out each CPU for these.
@@ -974,6 +979,17 @@ static int __cmd_timechart(const char *output_name)
                .sample          = process_sample_event,
                .ordered_samples = true,
        };
+       const struct perf_evsel_str_handler power_tracepoints[] = {
+               { "power:cpu_idle",             process_sample_cpu_idle },
+               { "power:cpu_frequency",        process_sample_cpu_frequency },
+               { "sched:sched_wakeup",         process_sample_sched_wakeup },
+               { "sched:sched_switch",         process_sample_sched_switch },
+#ifdef SUPPORT_OLD_POWER_EVENTS
+               { "power:power_start",          process_sample_power_start },
+               { "power:power_end",            process_sample_power_end },
+               { "power:power_frequency",      process_sample_power_frequency },
+#endif
+       };
        struct perf_session *session = perf_session__new(input_name, O_RDONLY,
                                                         0, false, &perf_timechart);
        int ret = -EINVAL;
@@ -984,6 +1000,12 @@ static int __cmd_timechart(const char *output_name)
        if (!perf_session__has_traces(session, "timechart record"))
                goto out_delete;
 
+       if (perf_session__set_tracepoints_handlers(session,
+                                                  power_tracepoints)) {
+               pr_err("Initializing session tracepoint handlers failed\n");
+               goto out_delete;
+       }
+
        ret = perf_session__process_events(session, &perf_timechart);
        if (ret)
                goto out_delete;
index e06c4f8693306827df06134a765d615ce27ae1cc..bbf46357277714a5fcdede5a170a9a05a9ab507b 100644 (file)
@@ -40,6 +40,7 @@
 #include "util/xyarray.h"
 #include "util/sort.h"
 #include "util/intlist.h"
+#include "arch/common.h"
 
 #include "util/debug.h"
 
@@ -772,8 +773,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
                    sample->callchain) {
                        err = machine__resolve_callchain(machine, evsel,
                                                         al.thread, sample,
-                                                        &parent);
-
+                                                        &parent, &al);
                        if (err)
                                return;
                }
@@ -939,6 +939,12 @@ static int __cmd_top(struct perf_top *top)
        if (top->session == NULL)
                return -ENOMEM;
 
+       if (!objdump_path) {
+               ret = perf_session_env__lookup_objdump(&top->session->header.env);
+               if (ret)
+                       goto out_delete;
+       }
+
        ret = perf_top__setup_sample_type(top);
        if (ret)
                goto out_delete;
@@ -1102,6 +1108,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
        OPT_CALLBACK_DEFAULT('G', "call-graph", &top.record_opts,
                             "mode[,dump_size]", record_callchain_help,
                             &parse_callchain_opt, "fp"),
+       OPT_CALLBACK(0, "ignore-callees", NULL, "regex",
+                  "ignore callees of these functions in call graphs",
+                  report_parse_ignore_callees_opt),
        OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
                    "Show a column with the sum of periods"),
        OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
@@ -1114,6 +1123,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
                    "Interleave source code with assembly code (default)"),
        OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw,
                    "Display raw encoding of assembly instructions (default)"),
+       OPT_STRING(0, "objdump", &objdump_path, "path",
+                   "objdump binary to use for disassembly and annotations"),
        OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
                   "Specify disassembler style (e.g. -M intel for intel syntax)"),
        OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"),
index ab3ed4af1466433755cb5946ed10c23928f336b7..0e4b67f6bbd10468e09911a82766156c91c15777 100644 (file)
@@ -1,3 +1,4 @@
+#include <traceevent/event-parse.h>
 #include "builtin.h"
 #include "util/color.h"
 #include "util/evlist.h"
@@ -5,7 +6,6 @@
 #include "util/thread.h"
 #include "util/parse-options.h"
 #include "util/thread_map.h"
-#include "event-parse.h"
 
 #include <libaudit.h>
 #include <stdlib.h>
@@ -142,7 +142,7 @@ static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thre
        printed += fprintf_duration(duration, fp);
 
        if (trace->multiple_threads)
-               printed += fprintf(fp, "%d ", thread->pid);
+               printed += fprintf(fp, "%d ", thread->tid);
 
        return printed;
 }
@@ -593,7 +593,7 @@ static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
                        color = PERF_COLOR_YELLOW;
 
                printed += color_fprintf(fp, color, "%20s", thread->comm);
-               printed += fprintf(fp, " - %-5d :%11lu   [", thread->pid, ttrace->nr_events);
+               printed += fprintf(fp, " - %-5d :%11lu   [", thread->tid, ttrace->nr_events);
                printed += color_fprintf(fp, color, "%5.1f%%", ratio);
                printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
        }
index b5d9238cb181d893d515b941e8726f4ea5abc818..214e17e97e5c7ba5aa25545b465b8994ac666afc 100644 (file)
@@ -46,6 +46,8 @@ ifneq ($(obj-perf),)
 obj-perf := $(abspath $(obj-perf))/
 endif
 
+LIB_INCLUDE := $(srctree)/tools/lib/
+
 # include ARCH specific config
 -include $(src-perf)/arch/$(ARCH)/Makefile
 
@@ -121,8 +123,7 @@ endif
 
 CFLAGS += -I$(src-perf)/util
 CFLAGS += -I$(src-perf)
-CFLAGS += -I$(TRACE_EVENT_DIR)
-CFLAGS += -I$(srctree)/tools/lib/
+CFLAGS += -I$(LIB_INCLUDE)
 
 CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
 
index 35b45f1466b52e1ac934c99ccc1af1447539ce30..b7b4049fabbb33740cb0c99ceb867194b8c0c354 100644 (file)
@@ -93,6 +93,12 @@ static struct test {
                .desc = "Test software clock events have valid period values",
                .func = test__sw_clock_freq,
        },
+#if defined(__x86_64__) || defined(__i386__)
+       {
+               .desc = "Test converting perf time to TSC",
+               .func = test__perf_time_to_tsc,
+       },
+#endif
        {
                .func = NULL,
        },
index 5eaffa2de9c5816399a2b455f25857fec46a9613..dffe0551acaa717add54e96bfb864c8fbf6cf2d6 100644 (file)
 #include "symbol.h"
 #include "tests.h"
 
-#define TEST_ASSERT_VAL(text, cond) \
-do { \
-       if (!(cond)) { \
-               pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
-               return -1; \
-       } \
-} while (0)
-
 static char *test_file(int size)
 {
        static char buf_templ[] = "/tmp/test-XXXXXX";
index a5d2fcc5ae35a0c81098bc6798d88ec01c85c18c..9b98c1554833ede7de9bdc8d7d312352ea863486 100644 (file)
@@ -1,6 +1,6 @@
+#include <traceevent/event-parse.h>
 #include "evsel.h"
 #include "tests.h"
-#include "event-parse.h"
 
 static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name,
                                  int size, bool should_be_signed)
@@ -49,7 +49,7 @@ int test__perf_evsel__tp_sched_test(void)
        if (perf_evsel__test_field(evsel, "prev_prio", 4, true))
                ret = -1;
 
-       if (perf_evsel__test_field(evsel, "prev_state", 8, true))
+       if (perf_evsel__test_field(evsel, "prev_state", sizeof(long), true))
                ret = -1;
 
        if (perf_evsel__test_field(evsel, "next_comm", 16, true))
index c441a28751283579652f01017aed8243e44c6246..2ca0abf1b2b6090165a4ccdb091729da4e7a1c48 100644 (file)
@@ -1,6 +1,8 @@
 PERF := .
 MK   := Makefile
 
+has = $(shell which $1 2>/dev/null)
+
 # standard single make variable specified
 make_clean_all      := clean all
 make_python_perf_so := python/perf.so
@@ -25,6 +27,13 @@ make_help           := help
 make_doc            := doc
 make_perf_o         := perf.o
 make_util_map_o     := util/map.o
+make_install        := install
+make_install_bin    := install-bin
+make_install_doc    := install-doc
+make_install_man    := install-man
+make_install_html   := install-html
+make_install_info   := install-info
+make_install_pdf    := install-pdf
 
 # all the NO_* variable combined
 make_minimal        := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1
@@ -50,14 +59,27 @@ run += make_no_backtrace
 run += make_no_libnuma
 run += make_no_libaudit
 run += make_no_libbionic
-run += make_tags
-run += make_cscope
 run += make_help
 run += make_doc
 run += make_perf_o
 run += make_util_map_o
+run += make_install
+run += make_install_bin
+# FIXME 'install-*' commented out till they're fixed
+# run += make_install_doc
+# run += make_install_man
+# run += make_install_html
+# run += make_install_info
+# run += make_install_pdf
 run += make_minimal
 
+ifneq ($(call has,ctags),)
+run += make_tags
+endif
+ifneq ($(call has,cscope),)
+run += make_cscope
+endif
+
 # $(run_O) contains same portion of $(run) tests with '_O' attached
 # to distinguish O=... tests
 run_O := $(addsuffix _O,$(run))
@@ -84,6 +106,31 @@ test_make_python_perf_so := test -f $(PERF)/python/perf.so
 test_make_perf_o     := test -f $(PERF)/perf.o
 test_make_util_map_o := test -f $(PERF)/util/map.o
 
+test_make_install       := test -x $$TMP_DEST/bin/perf
+test_make_install_O     := $(test_make_install)
+test_make_install_bin   := $(test_make_install)
+test_make_install_bin_O := $(test_make_install)
+
+# FIXME nothing gets installed
+test_make_install_man    := test -f $$TMP_DEST/share/man/man1/perf.1
+test_make_install_man_O  := $(test_make_install_man)
+
+# FIXME nothing gets installed
+test_make_install_doc    := $(test_ok)
+test_make_install_doc_O  := $(test_ok)
+
+# FIXME nothing gets installed
+test_make_install_html   := $(test_ok)
+test_make_install_html_O := $(test_ok)
+
+# FIXME nothing gets installed
+test_make_install_info   := $(test_ok)
+test_make_install_info_O := $(test_ok)
+
+# FIXME nothing gets installed
+test_make_install_pdf    := $(test_ok)
+test_make_install_pdf_O  := $(test_ok)
+
 # Kbuild tests only
 #test_make_python_perf_so_O := test -f $$TMP/tools/perf/python/perf.so
 #test_make_perf_o_O         := test -f $$TMP/tools/perf/perf.o
@@ -95,7 +142,7 @@ test_make_util_map_o_O := true
 test_default = test -x $(PERF)/perf
 test = $(if $(test_$1),$(test_$1),$(test_default))
 
-test_default_O = test -x $$TMP/perf
+test_default_O = test -x $$TMP_O/perf
 test_O = $(if $(test_$1),$(test_$1),$(test_default_O))
 
 all:
@@ -111,23 +158,27 @@ clean := @(cd $(PERF); make -s -f $(MK) clean >/dev/null)
 
 $(run):
        $(call clean)
-       @cmd="cd $(PERF) && make -f $(MK) $($@)"; \
+       @TMP_DEST=$$(mktemp -d); \
+       cmd="cd $(PERF) && make -f $(MK) DESTDIR=$$TMP_DEST $($@)"; \
        echo "- $@: $$cmd" && echo $$cmd > $@ && \
        ( eval $$cmd ) >> $@ 2>&1; \
        echo "  test: $(call test,$@)"; \
        $(call test,$@) && \
-       rm -f $@
+       rm -f $@ \
+       rm -rf $$TMP_DEST
 
 $(run_O):
        $(call clean)
-       @TMP=$$(mktemp -d); \
-       cmd="cd $(PERF) && make -f $(MK) $($(patsubst %_O,%,$@)) O=$$TMP"; \
+       @TMP_O=$$(mktemp -d); \
+       TMP_DEST=$$(mktemp -d); \
+       cmd="cd $(PERF) && make -f $(MK) O=$$TMP_O DESTDIR=$$TMP_DEST $($(patsubst %_O,%,$@))"; \
        echo "- $@: $$cmd" && echo $$cmd > $@ && \
        ( eval $$cmd ) >> $@ 2>&1 && \
        echo "  test: $(call test_O,$@)"; \
        $(call test_O,$@) && \
        rm -f $@ && \
-       rm -rf $$TMP
+       rm -rf $$TMP_O \
+       rm -rf $$TMP_DEST
 
 all: $(run) $(run_O)
        @echo OK
index 0275bab4ea9e83e95cf76d7408dc3649a5ccee4d..344c844ffc1e6639ff4ed0e831b4ec9e9fccc8af 100644 (file)
@@ -7,14 +7,6 @@
 #include "tests.h"
 #include <linux/hw_breakpoint.h>
 
-#define TEST_ASSERT_VAL(text, cond) \
-do { \
-       if (!(cond)) { \
-               pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
-               return -1; \
-       } \
-} while (0)
-
 #define PERF_TP_SAMPLE_TYPE (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | \
                             PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD)
 
@@ -1254,24 +1246,20 @@ static int test_events(struct evlist_test *events, unsigned cnt)
 
 static int test_term(struct terms_test *t)
 {
-       struct list_head *terms;
+       struct list_head terms;
        int ret;
 
-       terms = malloc(sizeof(*terms));
-       if (!terms)
-               return -ENOMEM;
-
-       INIT_LIST_HEAD(terms);
+       INIT_LIST_HEAD(&terms);
 
-       ret = parse_events_terms(terms, t->str);
+       ret = parse_events_terms(&terms, t->str);
        if (ret) {
                pr_debug("failed to parse terms '%s', err %d\n",
                         t->str , ret);
                return ret;
        }
 
-       ret = t->check(terms);
-       parse_events__free_terms(terms);
+       ret = t->check(&terms);
+       parse_events__free_terms(&terms);
 
        return ret;
 }
diff --git a/tools/perf/tests/perf-time-to-tsc.c b/tools/perf/tests/perf-time-to-tsc.c
new file mode 100644 (file)
index 0000000..0ab61b1
--- /dev/null
@@ -0,0 +1,177 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <sys/prctl.h>
+
+#include "parse-events.h"
+#include "evlist.h"
+#include "evsel.h"
+#include "thread_map.h"
+#include "cpumap.h"
+#include "tests.h"
+
+#include "../arch/x86/util/tsc.h"
+
+#define CHECK__(x) {                           \
+       while ((x) < 0) {                       \
+               pr_debug(#x " failed!\n");      \
+               goto out_err;                   \
+       }                                       \
+}
+
+#define CHECK_NOT_NULL__(x) {                  \
+       while ((x) == NULL) {                   \
+               pr_debug(#x " failed!\n");      \
+               goto out_err;                   \
+       }                                       \
+}
+
+static u64 rdtsc(void)
+{
+       unsigned int low, high;
+
+       asm volatile("rdtsc" : "=a" (low), "=d" (high));
+
+       return low | ((u64)high) << 32;
+}
+
+/**
+ * test__perf_time_to_tsc - test converting perf time to TSC.
+ *
+ * This function implements a test that checks that the conversion of perf time
+ * to and from TSC is consistent with the order of events.  If the test passes
+ * %0 is returned, otherwise %-1 is returned.  If TSC conversion is not
+ * supported then then the test passes but " (not supported)" is printed.
+ */
+int test__perf_time_to_tsc(void)
+{
+       struct perf_record_opts opts = {
+               .mmap_pages          = UINT_MAX,
+               .user_freq           = UINT_MAX,
+               .user_interval       = ULLONG_MAX,
+               .freq                = 4000,
+               .target              = {
+                       .uses_mmap   = true,
+               },
+               .sample_time         = true,
+       };
+       struct thread_map *threads = NULL;
+       struct cpu_map *cpus = NULL;
+       struct perf_evlist *evlist = NULL;
+       struct perf_evsel *evsel = NULL;
+       int err = -1, ret, i;
+       const char *comm1, *comm2;
+       struct perf_tsc_conversion tc;
+       struct perf_event_mmap_page *pc;
+       union perf_event *event;
+       u64 test_tsc, comm1_tsc, comm2_tsc;
+       u64 test_time, comm1_time = 0, comm2_time = 0;
+
+       threads = thread_map__new(-1, getpid(), UINT_MAX);
+       CHECK_NOT_NULL__(threads);
+
+       cpus = cpu_map__new(NULL);
+       CHECK_NOT_NULL__(cpus);
+
+       evlist = perf_evlist__new();
+       CHECK_NOT_NULL__(evlist);
+
+       perf_evlist__set_maps(evlist, cpus, threads);
+
+       CHECK__(parse_events(evlist, "cycles:u"));
+
+       perf_evlist__config(evlist, &opts);
+
+       evsel = perf_evlist__first(evlist);
+
+       evsel->attr.comm = 1;
+       evsel->attr.disabled = 1;
+       evsel->attr.enable_on_exec = 0;
+
+       CHECK__(perf_evlist__open(evlist));
+
+       CHECK__(perf_evlist__mmap(evlist, UINT_MAX, false));
+
+       pc = evlist->mmap[0].base;
+       ret = perf_read_tsc_conversion(pc, &tc);
+       if (ret) {
+               if (ret == -EOPNOTSUPP) {
+                       fprintf(stderr, " (not supported)");
+                       return 0;
+               }
+               goto out_err;
+       }
+
+       perf_evlist__enable(evlist);
+
+       comm1 = "Test COMM 1";
+       CHECK__(prctl(PR_SET_NAME, (unsigned long)comm1, 0, 0, 0));
+
+       test_tsc = rdtsc();
+
+       comm2 = "Test COMM 2";
+       CHECK__(prctl(PR_SET_NAME, (unsigned long)comm2, 0, 0, 0));
+
+       perf_evlist__disable(evlist);
+
+       for (i = 0; i < evlist->nr_mmaps; i++) {
+               while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
+                       struct perf_sample sample;
+
+                       if (event->header.type != PERF_RECORD_COMM ||
+                           (pid_t)event->comm.pid != getpid() ||
+                           (pid_t)event->comm.tid != getpid())
+                               continue;
+
+                       if (strcmp(event->comm.comm, comm1) == 0) {
+                               CHECK__(perf_evsel__parse_sample(evsel, event,
+                                                                &sample));
+                               comm1_time = sample.time;
+                       }
+                       if (strcmp(event->comm.comm, comm2) == 0) {
+                               CHECK__(perf_evsel__parse_sample(evsel, event,
+                                                                &sample));
+                               comm2_time = sample.time;
+                       }
+               }
+       }
+
+       if (!comm1_time || !comm2_time)
+               goto out_err;
+
+       test_time = tsc_to_perf_time(test_tsc, &tc);
+       comm1_tsc = perf_time_to_tsc(comm1_time, &tc);
+       comm2_tsc = perf_time_to_tsc(comm2_time, &tc);
+
+       pr_debug("1st event perf time %"PRIu64" tsc %"PRIu64"\n",
+                comm1_time, comm1_tsc);
+       pr_debug("rdtsc          time %"PRIu64" tsc %"PRIu64"\n",
+                test_time, test_tsc);
+       pr_debug("2nd event perf time %"PRIu64" tsc %"PRIu64"\n",
+                comm2_time, comm2_tsc);
+
+       if (test_time <= comm1_time ||
+           test_time >= comm2_time)
+               goto out_err;
+
+       if (test_tsc <= comm1_tsc ||
+           test_tsc >= comm2_tsc)
+               goto out_err;
+
+       err = 0;
+
+out_err:
+       if (evlist) {
+               perf_evlist__disable(evlist);
+               perf_evlist__munmap(evlist);
+               perf_evlist__close(evlist);
+               perf_evlist__delete(evlist);
+       }
+       if (cpus)
+               cpu_map__delete(cpus);
+       if (threads)
+               thread_map__delete(threads);
+
+       return err;
+}
index dd7feae2d37b83248fa8279891953503a69d3aec..d22202aa16e93078a8dc769b94b0af9bbde4fc60 100644 (file)
@@ -1,6 +1,14 @@
 #ifndef TESTS_H
 #define TESTS_H
 
+#define TEST_ASSERT_VAL(text, cond)                                     \
+do {                                                                    \
+       if (!(cond)) {                                                   \
+               pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
+               return -1;                                               \
+       }                                                                \
+} while (0)
+
 enum {
        TEST_OK   =  0,
        TEST_FAIL = -1,
@@ -27,5 +35,6 @@ int test__bp_signal(void);
 int test__bp_signal_overflow(void);
 int test__task_exit(void);
 int test__sw_clock_freq(void);
+int test__perf_time_to_tsc(void);
 
 #endif /* TESTS_H */
index 7b4c4d26d1baed24e2c5999d76457616c78c5d91..add15392c62220cf6bfa56d7ff3069a8528cf574 100644 (file)
@@ -139,11 +139,18 @@ next_pair:
                                 * _really_ have a problem.
                                 */
                                s64 skew = sym->end - pair->end;
-                               if (llabs(skew) < page_size)
-                                       continue;
+                               if (llabs(skew) >= page_size)
+                                       pr_debug("%#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n",
+                                                sym->start, sym->name, sym->end, pair->end);
+
+                               /*
+                                * Do not count this as a failure, because we
+                                * could really find a case where it's not
+                                * possible to get proper function end from
+                                * kallsyms.
+                                */
+                               continue;
 
-                               pr_debug("%#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n",
-                                        sym->start, sym->name, sym->end, pair->end);
                        } else {
                                struct rb_node *nnd;
 detour:
index fc0bd3843d34a1675cb2ada755c307e3c50c2771..7ef36c360471e3f2ccef82d4bd2a4e4fb684eb14 100644 (file)
@@ -685,8 +685,10 @@ static u64 __hpp_get_##_field(struct hist_entry *he)                       \
        return he->stat._field;                                         \
 }                                                                      \
                                                                        \
-static int hist_browser__hpp_color_##_type(struct perf_hpp *hpp,       \
-                                          struct hist_entry *he)       \
+static int                                                             \
+hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
+                               struct perf_hpp *hpp,                   \
+                               struct hist_entry *he)                  \
 {                                                                      \
        return __hpp__color_fmt(hpp, he, __hpp_get_##_field, _cb);      \
 }
@@ -701,8 +703,6 @@ __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us, NULL)
 
 void hist_browser__init_hpp(void)
 {
-       perf_hpp__column_enable(PERF_HPP__OVERHEAD);
-
        perf_hpp__init();
 
        perf_hpp__format[PERF_HPP__OVERHEAD].color =
@@ -762,9 +762,9 @@ static int hist_browser__show_entry(struct hist_browser *browser,
                        first = false;
 
                        if (fmt->color) {
-                               width -= fmt->color(&hpp, entry);
+                               width -= fmt->color(fmt, &hpp, entry);
                        } else {
-                               width -= fmt->entry(&hpp, entry);
+                               width -= fmt->entry(fmt, &hpp, entry);
                                slsmg_printf("%s", s);
                        }
                }
@@ -1256,7 +1256,7 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,
                printed += scnprintf(bf + printed, size - printed,
                                    ", Thread: %s(%d)",
                                    (thread->comm_set ? thread->comm : ""),
-                                   thread->pid);
+                                   thread->tid);
        if (dso)
                printed += scnprintf(bf + printed, size - printed,
                                    ", DSO: %s", dso->short_name);
@@ -1579,7 +1579,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
                    asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
                             (browser->hists->thread_filter ? "out of" : "into"),
                             (thread->comm_set ? thread->comm : ""),
-                            thread->pid) > 0)
+                            thread->tid) > 0)
                        zoom_thread = nr_options++;
 
                if (dso != NULL &&
@@ -1702,7 +1702,7 @@ zoom_out_thread:
                        } else {
                                ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
                                                   thread->comm_set ? thread->comm : "",
-                                                  thread->pid);
+                                                  thread->tid);
                                browser->hists->thread_filter = thread;
                                sort_thread.elide = true;
                                pstack__push(fstack, &browser->hists->thread_filter);
index 9708dd5fb8f32f993d5e6ea3eca6ce2e3e546888..cb2ed1980147c0f3ffeda4547880fe18809a9031 100644 (file)
@@ -91,7 +91,8 @@ static u64 he_get_##_field(struct hist_entry *he)                             \
        return he->stat._field;                                                 \
 }                                                                              \
                                                                                \
-static int perf_gtk__hpp_color_##_type(struct perf_hpp *hpp,                   \
+static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,        \
+                                      struct perf_hpp *hpp,                    \
                                       struct hist_entry *he)                   \
 {                                                                              \
        return __hpp__color_fmt(hpp, he, he_get_##_field);                      \
@@ -124,6 +125,81 @@ void perf_gtk__init_hpp(void)
                                perf_gtk__hpp_color_overhead_guest_us;
 }
 
+static void callchain_list__sym_name(struct callchain_list *cl,
+                                    char *bf, size_t bfsize)
+{
+       if (cl->ms.sym)
+               scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
+       else
+               scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
+}
+
+static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store,
+                                   GtkTreeIter *parent, int col, u64 total)
+{
+       struct rb_node *nd;
+       bool has_single_node = (rb_first(root) == rb_last(root));
+
+       for (nd = rb_first(root); nd; nd = rb_next(nd)) {
+               struct callchain_node *node;
+               struct callchain_list *chain;
+               GtkTreeIter iter, new_parent;
+               bool need_new_parent;
+               double percent;
+               u64 hits, child_total;
+
+               node = rb_entry(nd, struct callchain_node, rb_node);
+
+               hits = callchain_cumul_hits(node);
+               percent = 100.0 * hits / total;
+
+               new_parent = *parent;
+               need_new_parent = !has_single_node && (node->val_nr > 1);
+
+               list_for_each_entry(chain, &node->val, list) {
+                       char buf[128];
+
+                       gtk_tree_store_append(store, &iter, &new_parent);
+
+                       scnprintf(buf, sizeof(buf), "%5.2f%%", percent);
+                       gtk_tree_store_set(store, &iter, 0, buf, -1);
+
+                       callchain_list__sym_name(chain, buf, sizeof(buf));
+                       gtk_tree_store_set(store, &iter, col, buf, -1);
+
+                       if (need_new_parent) {
+                               /*
+                                * Only show the top-most symbol in a callchain
+                                * if it's not the only callchain.
+                                */
+                               new_parent = iter;
+                               need_new_parent = false;
+                       }
+               }
+
+               if (callchain_param.mode == CHAIN_GRAPH_REL)
+                       child_total = node->children_hit;
+               else
+                       child_total = total;
+
+               /* Now 'iter' contains info of the last callchain_list */
+               perf_gtk__add_callchain(&node->rb_root, store, &iter, col,
+                                       child_total);
+       }
+}
+
+static void on_row_activated(GtkTreeView *view, GtkTreePath *path,
+                            GtkTreeViewColumn *col __maybe_unused,
+                            gpointer user_data __maybe_unused)
+{
+       bool expanded = gtk_tree_view_row_expanded(view, path);
+
+       if (expanded)
+               gtk_tree_view_collapse_row(view, path);
+       else
+               gtk_tree_view_expand_row(view, path, FALSE);
+}
+
 static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
                                 float min_pcnt)
 {
@@ -131,10 +207,11 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
        GType col_types[MAX_COLUMNS];
        GtkCellRenderer *renderer;
        struct sort_entry *se;
-       GtkListStore *store;
+       GtkTreeStore *store;
        struct rb_node *nd;
        GtkWidget *view;
        int col_idx;
+       int sym_col = -1;
        int nr_cols;
        char s[512];
 
@@ -153,10 +230,13 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
                if (se->elide)
                        continue;
 
+               if (se == &sort_sym)
+                       sym_col = nr_cols;
+
                col_types[nr_cols++] = G_TYPE_STRING;
        }
 
-       store = gtk_list_store_newv(nr_cols, col_types);
+       store = gtk_tree_store_newv(nr_cols, col_types);
 
        view = gtk_tree_view_new();
 
@@ -165,7 +245,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
        col_idx = 0;
 
        perf_hpp__for_each_format(fmt) {
-               fmt->header(&hpp);
+               fmt->header(fmt, &hpp);
 
                gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
                                                            -1, ltrim(s),
@@ -183,6 +263,18 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
                                                            col_idx++, NULL);
        }
 
+       for (col_idx = 0; col_idx < nr_cols; col_idx++) {
+               GtkTreeViewColumn *column;
+
+               column = gtk_tree_view_get_column(GTK_TREE_VIEW(view), col_idx);
+               gtk_tree_view_column_set_resizable(column, TRUE);
+
+               if (col_idx == sym_col) {
+                       gtk_tree_view_set_expander_column(GTK_TREE_VIEW(view),
+                                                         column);
+               }
+       }
+
        gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
 
        g_object_unref(GTK_TREE_MODEL(store));
@@ -199,17 +291,17 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
                if (percent < min_pcnt)
                        continue;
 
-               gtk_list_store_append(store, &iter);
+               gtk_tree_store_append(store, &iter, NULL);
 
                col_idx = 0;
 
                perf_hpp__for_each_format(fmt) {
                        if (fmt->color)
-                               fmt->color(&hpp, h);
+                               fmt->color(fmt, &hpp, h);
                        else
-                               fmt->entry(&hpp, h);
+                               fmt->entry(fmt, &hpp, h);
 
-                       gtk_list_store_set(store, &iter, col_idx++, s, -1);
+                       gtk_tree_store_set(store, &iter, col_idx++, s, -1);
                }
 
                list_for_each_entry(se, &hist_entry__sort_list, list) {
@@ -219,10 +311,26 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
                        se->se_snprintf(h, s, ARRAY_SIZE(s),
                                        hists__col_len(hists, se->se_width_idx));
 
-                       gtk_list_store_set(store, &iter, col_idx++, s, -1);
+                       gtk_tree_store_set(store, &iter, col_idx++, s, -1);
+               }
+
+               if (symbol_conf.use_callchain && sort__has_sym) {
+                       u64 total;
+
+                       if (callchain_param.mode == CHAIN_GRAPH_REL)
+                               total = h->stat.period;
+                       else
+                               total = hists->stats.total_period;
+
+                       perf_gtk__add_callchain(&h->sorted_chain, store, &iter,
+                                               sym_col, total);
                }
        }
 
+       gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), TRUE);
+
+       g_signal_connect(view, "row-activated",
+                        G_CALLBACK(on_row_activated), NULL);
        gtk_container_add(GTK_CONTAINER(window), view);
 }
 
index 4bf91b09d62db6684c9e66c985810303b3950af1..0a193281eba85ec12bbed36d85803b51d7d24464 100644 (file)
@@ -1,4 +1,5 @@
 #include <math.h>
+#include <linux/compiler.h>
 
 #include "../util/hist.h"
 #include "../util/util.h"
@@ -79,7 +80,8 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
 }
 
 #define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width)          \
-static int hpp__header_##_type(struct perf_hpp *hpp)                   \
+static int hpp__header_##_type(struct perf_hpp_fmt *fmt __maybe_unused,        \
+                              struct perf_hpp *hpp)                    \
 {                                                                      \
        int len = _min_width;                                           \
                                                                        \
@@ -92,7 +94,8 @@ static int hpp__header_##_type(struct perf_hpp *hpp)                  \
 }
 
 #define __HPP_WIDTH_FN(_type, _min_width, _unit_width)                         \
-static int hpp__width_##_type(struct perf_hpp *hpp __maybe_unused)     \
+static int hpp__width_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
+                             struct perf_hpp *hpp __maybe_unused)      \
 {                                                                      \
        int len = _min_width;                                           \
                                                                        \
@@ -110,14 +113,16 @@ static u64 he_get_##_field(struct hist_entry *he)                         \
        return he->stat._field;                                                 \
 }                                                                              \
                                                                                \
-static int hpp__color_##_type(struct perf_hpp *hpp, struct hist_entry *he)     \
+static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,         \
+                             struct perf_hpp *hpp, struct hist_entry *he)      \
 {                                                                              \
        return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%",                 \
                          (hpp_snprint_fn)percent_color_snprintf, true);        \
 }
 
 #define __HPP_ENTRY_PERCENT_FN(_type, _field)                                  \
-static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he)     \
+static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused,                \
+                             struct perf_hpp *hpp, struct hist_entry *he)      \
 {                                                                              \
        const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%";         \
        return __hpp__fmt(hpp, he, he_get_##_field, fmt,                        \
@@ -130,7 +135,8 @@ static u64 he_get_raw_##_field(struct hist_entry *he)                               \
        return he->stat._field;                                                 \
 }                                                                              \
                                                                                \
-static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he)     \
+static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused,                \
+                             struct perf_hpp *hpp, struct hist_entry *he)      \
 {                                                                              \
        const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64;    \
        return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt, scnprintf, false); \
@@ -157,196 +163,6 @@ HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8)
 HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12)
 HPP_RAW_FNS(period, "Period", period, 12, 12)
 
-
-static int hpp__header_baseline(struct perf_hpp *hpp)
-{
-       return scnprintf(hpp->buf, hpp->size, "Baseline");
-}
-
-static int hpp__width_baseline(struct perf_hpp *hpp __maybe_unused)
-{
-       return 8;
-}
-
-static double baseline_percent(struct hist_entry *he)
-{
-       struct hist_entry *pair = hist_entry__next_pair(he);
-       struct hists *pair_hists = pair ? pair->hists : NULL;
-       double percent = 0.0;
-
-       if (pair) {
-               u64 total_period = pair_hists->stats.total_period;
-               u64 base_period  = pair->stat.period;
-
-               percent = 100.0 * base_period / total_period;
-       }
-
-       return percent;
-}
-
-static int hpp__color_baseline(struct perf_hpp *hpp, struct hist_entry *he)
-{
-       double percent = baseline_percent(he);
-
-       if (hist_entry__has_pairs(he) || symbol_conf.field_sep)
-               return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
-       else
-               return scnprintf(hpp->buf, hpp->size, "        ");
-}
-
-static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he)
-{
-       double percent = baseline_percent(he);
-       const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%";
-
-       if (hist_entry__has_pairs(he) || symbol_conf.field_sep)
-               return scnprintf(hpp->buf, hpp->size, fmt, percent);
-       else
-               return scnprintf(hpp->buf, hpp->size, "            ");
-}
-
-static int hpp__header_period_baseline(struct perf_hpp *hpp)
-{
-       const char *fmt = symbol_conf.field_sep ? "%s" : "%12s";
-
-       return scnprintf(hpp->buf, hpp->size, fmt, "Period Base");
-}
-
-static int hpp__width_period_baseline(struct perf_hpp *hpp __maybe_unused)
-{
-       return 12;
-}
-
-static int hpp__entry_period_baseline(struct perf_hpp *hpp, struct hist_entry *he)
-{
-       struct hist_entry *pair = hist_entry__next_pair(he);
-       u64 period = pair ? pair->stat.period : 0;
-       const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64;
-
-       return scnprintf(hpp->buf, hpp->size, fmt, period);
-}
-
-static int hpp__header_delta(struct perf_hpp *hpp)
-{
-       const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
-
-       return scnprintf(hpp->buf, hpp->size, fmt, "Delta");
-}
-
-static int hpp__width_delta(struct perf_hpp *hpp __maybe_unused)
-{
-       return 7;
-}
-
-static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he)
-{
-       struct hist_entry *pair = hist_entry__next_pair(he);
-       const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s";
-       char buf[32] = " ";
-       double diff = 0.0;
-
-       if (pair) {
-               if (he->diff.computed)
-                       diff = he->diff.period_ratio_delta;
-               else
-                       diff = perf_diff__compute_delta(he, pair);
-       } else
-               diff = perf_diff__period_percent(he, he->stat.period);
-
-       if (fabs(diff) >= 0.01)
-               scnprintf(buf, sizeof(buf), "%+4.2F%%", diff);
-
-       return scnprintf(hpp->buf, hpp->size, fmt, buf);
-}
-
-static int hpp__header_ratio(struct perf_hpp *hpp)
-{
-       const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
-
-       return scnprintf(hpp->buf, hpp->size, fmt, "Ratio");
-}
-
-static int hpp__width_ratio(struct perf_hpp *hpp __maybe_unused)
-{
-       return 14;
-}
-
-static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he)
-{
-       struct hist_entry *pair = hist_entry__next_pair(he);
-       const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
-       char buf[32] = " ";
-       double ratio = 0.0;
-
-       if (pair) {
-               if (he->diff.computed)
-                       ratio = he->diff.period_ratio;
-               else
-                       ratio = perf_diff__compute_ratio(he, pair);
-       }
-
-       if (ratio > 0.0)
-               scnprintf(buf, sizeof(buf), "%+14.6F", ratio);
-
-       return scnprintf(hpp->buf, hpp->size, fmt, buf);
-}
-
-static int hpp__header_wdiff(struct perf_hpp *hpp)
-{
-       const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
-
-       return scnprintf(hpp->buf, hpp->size, fmt, "Weighted diff");
-}
-
-static int hpp__width_wdiff(struct perf_hpp *hpp __maybe_unused)
-{
-       return 14;
-}
-
-static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he)
-{
-       struct hist_entry *pair = hist_entry__next_pair(he);
-       const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
-       char buf[32] = " ";
-       s64 wdiff = 0;
-
-       if (pair) {
-               if (he->diff.computed)
-                       wdiff = he->diff.wdiff;
-               else
-                       wdiff = perf_diff__compute_wdiff(he, pair);
-       }
-
-       if (wdiff != 0)
-               scnprintf(buf, sizeof(buf), "%14ld", wdiff);
-
-       return scnprintf(hpp->buf, hpp->size, fmt, buf);
-}
-
-static int hpp__header_formula(struct perf_hpp *hpp)
-{
-       const char *fmt = symbol_conf.field_sep ? "%s" : "%70s";
-
-       return scnprintf(hpp->buf, hpp->size, fmt, "Formula");
-}
-
-static int hpp__width_formula(struct perf_hpp *hpp __maybe_unused)
-{
-       return 70;
-}
-
-static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he)
-{
-       struct hist_entry *pair = hist_entry__next_pair(he);
-       const char *fmt = symbol_conf.field_sep ? "%s" : "%-70s";
-       char buf[96] = " ";
-
-       if (pair)
-               perf_diff__formula(he, pair, buf, sizeof(buf));
-
-       return scnprintf(hpp->buf, hpp->size, fmt, buf);
-}
-
 #define HPP__COLOR_PRINT_FNS(_name)                    \
        {                                               \
                .header = hpp__header_ ## _name,        \
@@ -363,19 +179,13 @@ static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he)
        }
 
 struct perf_hpp_fmt perf_hpp__format[] = {
-       HPP__COLOR_PRINT_FNS(baseline),
        HPP__COLOR_PRINT_FNS(overhead),
        HPP__COLOR_PRINT_FNS(overhead_sys),
        HPP__COLOR_PRINT_FNS(overhead_us),
        HPP__COLOR_PRINT_FNS(overhead_guest_sys),
        HPP__COLOR_PRINT_FNS(overhead_guest_us),
        HPP__PRINT_FNS(samples),
-       HPP__PRINT_FNS(period),
-       HPP__PRINT_FNS(period_baseline),
-       HPP__PRINT_FNS(delta),
-       HPP__PRINT_FNS(ratio),
-       HPP__PRINT_FNS(wdiff),
-       HPP__PRINT_FNS(formula)
+       HPP__PRINT_FNS(period)
 };
 
 LIST_HEAD(perf_hpp__list);
@@ -396,6 +206,8 @@ LIST_HEAD(perf_hpp__list);
 
 void perf_hpp__init(void)
 {
+       perf_hpp__column_enable(PERF_HPP__OVERHEAD);
+
        if (symbol_conf.show_cpu_utilization) {
                perf_hpp__column_enable(PERF_HPP__OVERHEAD_SYS);
                perf_hpp__column_enable(PERF_HPP__OVERHEAD_US);
@@ -424,46 +236,6 @@ void perf_hpp__column_enable(unsigned col)
        perf_hpp__column_register(&perf_hpp__format[col]);
 }
 
-static inline void advance_hpp(struct perf_hpp *hpp, int inc)
-{
-       hpp->buf  += inc;
-       hpp->size -= inc;
-}
-
-int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
-                               bool color)
-{
-       const char *sep = symbol_conf.field_sep;
-       struct perf_hpp_fmt *fmt;
-       char *start = hpp->buf;
-       int ret;
-       bool first = true;
-
-       if (symbol_conf.exclude_other && !he->parent)
-               return 0;
-
-       perf_hpp__for_each_format(fmt) {
-               /*
-                * If there's no field_sep, we still need
-                * to display initial '  '.
-                */
-               if (!sep || !first) {
-                       ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: "  ");
-                       advance_hpp(hpp, ret);
-               } else
-                       first = false;
-
-               if (color && fmt->color)
-                       ret = fmt->color(hpp, he);
-               else
-                       ret = fmt->entry(hpp, he);
-
-               advance_hpp(hpp, ret);
-       }
-
-       return hpp->buf - start;
-}
-
 int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size,
                              struct hists *hists)
 {
@@ -499,7 +271,7 @@ unsigned int hists__sort_list_width(struct hists *hists)
                if (i)
                        ret += 2;
 
-               ret += fmt->width(&dummy_hpp);
+               ret += fmt->width(fmt, &dummy_hpp);
        }
 
        list_for_each_entry(se, &hist_entry__sort_list, list)
index ae6a789cb0f62780a9fa088f7fe99939c798ef2d..47d9a571f261da9c65e36aa82f8dbdb70a838acc 100644 (file)
@@ -30,7 +30,6 @@ void setup_browser(bool fallback_to_pager)
                if (fallback_to_pager)
                        setup_pager();
 
-               perf_hpp__column_enable(PERF_HPP__OVERHEAD);
                perf_hpp__init();
                break;
        }
index ae7a75432249fe6fba3f7d4c45e8865200261ba1..5b4fb330f656d71f929f197c06387389dbc2dfed 100644 (file)
@@ -308,6 +308,47 @@ static size_t hist_entry__callchain_fprintf(struct hist_entry *he,
        return hist_entry_callchain__fprintf(he, total_period, left_margin, fp);
 }
 
+static inline void advance_hpp(struct perf_hpp *hpp, int inc)
+{
+       hpp->buf  += inc;
+       hpp->size -= inc;
+}
+
+static int hist_entry__period_snprintf(struct perf_hpp *hpp,
+                                      struct hist_entry *he,
+                                      bool color)
+{
+       const char *sep = symbol_conf.field_sep;
+       struct perf_hpp_fmt *fmt;
+       char *start = hpp->buf;
+       int ret;
+       bool first = true;
+
+       if (symbol_conf.exclude_other && !he->parent)
+               return 0;
+
+       perf_hpp__for_each_format(fmt) {
+               /*
+                * If there's no field_sep, we still need
+                * to display initial '  '.
+                */
+               if (!sep || !first) {
+                       ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: "  ");
+                       advance_hpp(hpp, ret);
+               } else
+                       first = false;
+
+               if (color && fmt->color)
+                       ret = fmt->color(fmt, hpp, he);
+               else
+                       ret = fmt->entry(fmt, hpp, he);
+
+               advance_hpp(hpp, ret);
+       }
+
+       return hpp->buf - start;
+}
+
 static int hist_entry__fprintf(struct hist_entry *he, size_t size,
                               struct hists *hists, FILE *fp)
 {
@@ -365,7 +406,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
                else
                        first = false;
 
-               fmt->header(&dummy_hpp);
+               fmt->header(fmt, &dummy_hpp);
                fprintf(fp, "%s", bf);
        }
 
@@ -410,7 +451,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
                else
                        first = false;
 
-               width = fmt->width(&dummy_hpp);
+               width = fmt->width(fmt, &dummy_hpp);
                for (i = 0; i < width; i++)
                        fprintf(fp, ".");
        }
index 42b6a632fe7b75bb297433e9ad9962814e5016d9..4fee33b229b0f8a67b664edbc2f092dc0bc0d235 100644 (file)
@@ -15,6 +15,7 @@
 #include <errno.h>
 #include <math.h>
 
+#include "hist.h"
 #include "util.h"
 #include "callchain.h"
 
@@ -327,7 +328,8 @@ append_chain(struct callchain_node *root,
        /*
         * Lookup in the current node
         * If we have a symbol, then compare the start to match
-        * anywhere inside a function.
+        * anywhere inside a function, unless function
+        * mode is disabled.
         */
        list_for_each_entry(cnode, &root->val, list) {
                struct callchain_cursor_node *node;
@@ -339,7 +341,8 @@ append_chain(struct callchain_node *root,
 
                sym = node->sym;
 
-               if (cnode->ms.sym && sym) {
+               if (cnode->ms.sym && sym &&
+                   callchain_param.key == CCKEY_FUNCTION) {
                        if (cnode->ms.sym->start != sym->start)
                                break;
                } else if (cnode->ip != node->ip)
index 3ee9f67d5af0bed457cb7ae22d5efe99ccdbfd8f..812d5a0ff2bcf7da3ce89315e6ad130a173adf10 100644 (file)
@@ -41,12 +41,18 @@ struct callchain_param;
 typedef void (*sort_chain_func_t)(struct rb_root *, struct callchain_root *,
                                 u64, struct callchain_param *);
 
+enum chain_key {
+       CCKEY_FUNCTION,
+       CCKEY_ADDRESS
+};
+
 struct callchain_param {
        enum chain_mode         mode;
        u32                     print_limit;
        double                  min_percent;
        sort_chain_func_t       sort;
        enum chain_order        order;
+       enum chain_key          key;
 };
 
 struct callchain_list {
index 9bed02e5fb3d9b35182a10fbc9e9de6b236a5e22..b123bb9d6f55ec2307f97f10acf43b8a56b38701 100644 (file)
@@ -41,7 +41,7 @@ static inline int cpu_map__nr(const struct cpu_map *map)
        return map ? map->nr : 1;
 }
 
-static inline bool cpu_map__all(const struct cpu_map *map)
+static inline bool cpu_map__empty(const struct cpu_map *map)
 {
        return map ? map->map[0] == -1 : true;
 }
index 5cd13d768cecee1a630ca51715dba4b6d8f19f0b..95412705d0d2f84016ecb64bf09457200260f357 100644 (file)
@@ -686,7 +686,7 @@ int perf_event__preprocess_sample(const union perf_event *event,
            !strlist__has_entry(symbol_conf.comm_list, thread->comm))
                goto out_filtered;
 
-       dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
+       dump_printf(" ... thread: %s:%d\n", thread->comm, thread->tid);
        /*
         * Have we already created the kernel maps for this machine?
         *
index 181389535c0cf787e83bba1a75deb7346b19aab3..1ebb8fb0178cf7a599595ab8d23aa9cb883f197d 100644 (file)
@@ -116,7 +116,7 @@ struct build_id_event {
 enum perf_user_event_type { /* above any possible kernel type */
        PERF_RECORD_USER_TYPE_START             = 64,
        PERF_RECORD_HEADER_ATTR                 = 64,
-       PERF_RECORD_HEADER_EVENT_TYPE           = 65,
+       PERF_RECORD_HEADER_EVENT_TYPE           = 65, /* depreceated */
        PERF_RECORD_HEADER_TRACING_DATA         = 66,
        PERF_RECORD_HEADER_BUILD_ID             = 67,
        PERF_RECORD_FINISHED_ROUND              = 68,
index 8065ce8fa9a5cdaea730e55667b7c5ed1d9b77f9..42ea4e947eb827ddd8e0ac490e0f2aa0a3d7630d 100644 (file)
@@ -403,16 +403,20 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
        return event;
 }
 
+static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx)
+{
+       if (evlist->mmap[idx].base != NULL) {
+               munmap(evlist->mmap[idx].base, evlist->mmap_len);
+               evlist->mmap[idx].base = NULL;
+       }
+}
+
 void perf_evlist__munmap(struct perf_evlist *evlist)
 {
        int i;
 
-       for (i = 0; i < evlist->nr_mmaps; i++) {
-               if (evlist->mmap[i].base != NULL) {
-                       munmap(evlist->mmap[i].base, evlist->mmap_len);
-                       evlist->mmap[i].base = NULL;
-               }
-       }
+       for (i = 0; i < evlist->nr_mmaps; i++)
+               __perf_evlist__munmap(evlist, i);
 
        free(evlist->mmap);
        evlist->mmap = NULL;
@@ -421,7 +425,7 @@ void perf_evlist__munmap(struct perf_evlist *evlist)
 static int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
 {
        evlist->nr_mmaps = cpu_map__nr(evlist->cpus);
-       if (cpu_map__all(evlist->cpus))
+       if (cpu_map__empty(evlist->cpus))
                evlist->nr_mmaps = thread_map__nr(evlist->threads);
        evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap));
        return evlist->mmap != NULL ? 0 : -ENOMEM;
@@ -477,12 +481,8 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int m
        return 0;
 
 out_unmap:
-       for (cpu = 0; cpu < nr_cpus; cpu++) {
-               if (evlist->mmap[cpu].base != NULL) {
-                       munmap(evlist->mmap[cpu].base, evlist->mmap_len);
-                       evlist->mmap[cpu].base = NULL;
-               }
-       }
+       for (cpu = 0; cpu < nr_cpus; cpu++)
+               __perf_evlist__munmap(evlist, cpu);
        return -1;
 }
 
@@ -517,12 +517,8 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in
        return 0;
 
 out_unmap:
-       for (thread = 0; thread < nr_threads; thread++) {
-               if (evlist->mmap[thread].base != NULL) {
-                       munmap(evlist->mmap[thread].base, evlist->mmap_len);
-                       evlist->mmap[thread].base = NULL;
-               }
-       }
+       for (thread = 0; thread < nr_threads; thread++)
+               __perf_evlist__munmap(evlist, thread);
        return -1;
 }
 
@@ -573,7 +569,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
                        return -ENOMEM;
        }
 
-       if (cpu_map__all(cpus))
+       if (cpu_map__empty(cpus))
                return perf_evlist__mmap_per_thread(evlist, prot, mask);
 
        return perf_evlist__mmap_per_cpu(evlist, prot, mask);
@@ -838,7 +834,7 @@ out_close_ready_pipe:
 int perf_evlist__start_workload(struct perf_evlist *evlist)
 {
        if (evlist->workload.cork_fd > 0) {
-               char bf;
+               char bf = 0;
                int ret;
                /*
                 * Remove the cork, let it rip!
index c9c7494506a1e7bfddde46ca242f0d583f2500e3..8bed0c1a1399c4dabbb4efc52595927c1425a5ee 100644 (file)
@@ -9,17 +9,17 @@
 
 #include <byteswap.h>
 #include <linux/bitops.h>
-#include "asm/bug.h"
 #include <lk/debugfs.h>
-#include "event-parse.h"
+#include <traceevent/event-parse.h>
+#include <linux/hw_breakpoint.h>
+#include <linux/perf_event.h>
+#include "asm/bug.h"
 #include "evsel.h"
 #include "evlist.h"
 #include "util.h"
 #include "cpumap.h"
 #include "thread_map.h"
 #include "target.h"
-#include <linux/hw_breakpoint.h>
-#include <linux/perf_event.h>
 #include "perf_regs.h"
 
 static struct {
@@ -1482,7 +1482,7 @@ out:
 bool perf_evsel__fallback(struct perf_evsel *evsel, int err,
                          char *msg, size_t msgsize)
 {
-       if ((err == ENOENT || err == ENXIO) &&
+       if ((err == ENOENT || err == ENXIO || err == ENODEV) &&
            evsel->attr.type   == PERF_TYPE_HARDWARE &&
            evsel->attr.config == PERF_COUNT_HW_CPU_CYCLES) {
                /*
index a4dafbee2511546a97b9b9c63cb84fe76e0d19eb..f558f83769af1a7e7b9fe0780ab4c6b4793f260c 100644 (file)
 
 static bool no_buildid_cache = false;
 
-static int trace_event_count;
-static struct perf_trace_event_type *trace_events;
-
 static u32 header_argc;
 static const char **header_argv;
 
-int perf_header__push_event(u64 id, const char *name)
-{
-       struct perf_trace_event_type *nevents;
-
-       if (strlen(name) > MAX_EVENT_NAME)
-               pr_warning("Event %s will be truncated\n", name);
-
-       nevents = realloc(trace_events, (trace_event_count + 1) * sizeof(*trace_events));
-       if (nevents == NULL)
-               return -ENOMEM;
-       trace_events = nevents;
-
-       memset(&trace_events[trace_event_count], 0, sizeof(struct perf_trace_event_type));
-       trace_events[trace_event_count].event_id = id;
-       strncpy(trace_events[trace_event_count].name, name, MAX_EVENT_NAME - 1);
-       trace_event_count++;
-       return 0;
-}
-
-char *perf_header__find_event(u64 id)
-{
-       int i;
-       for (i = 0 ; i < trace_event_count; i++) {
-               if (trace_events[i].event_id == id)
-                       return trace_events[i].name;
-       }
-       return NULL;
-}
-
 /*
  * magic2 = "PERFILE2"
  * must be a numerical value to let the endianness
@@ -2257,7 +2225,7 @@ static int perf_header__adds_write(struct perf_header *header,
 
        sec_size = sizeof(*feat_sec) * nr_sections;
 
-       sec_start = header->data_offset + header->data_size;
+       sec_start = header->feat_offset;
        lseek(fd, sec_start + sec_size, SEEK_SET);
 
        for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) {
@@ -2304,6 +2272,7 @@ int perf_session__write_header(struct perf_session *session,
        struct perf_file_attr   f_attr;
        struct perf_header *header = &session->header;
        struct perf_evsel *evsel;
+       u64 attr_offset;
        int err;
 
        lseek(fd, sizeof(f_header), SEEK_SET);
@@ -2317,7 +2286,7 @@ int perf_session__write_header(struct perf_session *session,
                }
        }
 
-       header->attr_offset = lseek(fd, 0, SEEK_CUR);
+       attr_offset = lseek(fd, 0, SEEK_CUR);
 
        list_for_each_entry(evsel, &evlist->entries, node) {
                f_attr = (struct perf_file_attr){
@@ -2334,17 +2303,8 @@ int perf_session__write_header(struct perf_session *session,
                }
        }
 
-       header->event_offset = lseek(fd, 0, SEEK_CUR);
-       header->event_size = trace_event_count * sizeof(struct perf_trace_event_type);
-       if (trace_events) {
-               err = do_write(fd, trace_events, header->event_size);
-               if (err < 0) {
-                       pr_debug("failed to write perf header events\n");
-                       return err;
-               }
-       }
-
        header->data_offset = lseek(fd, 0, SEEK_CUR);
+       header->feat_offset = header->data_offset + header->data_size;
 
        if (at_exit) {
                err = perf_header__adds_write(header, evlist, fd);
@@ -2357,17 +2317,14 @@ int perf_session__write_header(struct perf_session *session,
                .size      = sizeof(f_header),
                .attr_size = sizeof(f_attr),
                .attrs = {
-                       .offset = header->attr_offset,
+                       .offset = attr_offset,
                        .size   = evlist->nr_entries * sizeof(f_attr),
                },
                .data = {
                        .offset = header->data_offset,
                        .size   = header->data_size,
                },
-               .event_types = {
-                       .offset = header->event_offset,
-                       .size   = header->event_size,
-               },
+               /* event_types is ignored, store zeros */
        };
 
        memcpy(&f_header.adds_features, &header->adds_features, sizeof(header->adds_features));
@@ -2417,7 +2374,7 @@ int perf_header__process_sections(struct perf_header *header, int fd,
 
        sec_size = sizeof(*feat_sec) * nr_sections;
 
-       lseek(fd, header->data_offset + header->data_size, SEEK_SET);
+       lseek(fd, header->feat_offset, SEEK_SET);
 
        err = perf_header__getbuffer64(header, fd, feat_sec, sec_size);
        if (err < 0)
@@ -2523,6 +2480,7 @@ static int check_magic_endian(u64 magic, uint64_t hdr_sz,
        /* check for legacy format */
        ret = memcmp(&magic, __perf_magic1, sizeof(magic));
        if (ret == 0) {
+               ph->version = PERF_HEADER_VERSION_1;
                pr_debug("legacy perf.data format\n");
                if (is_pipe)
                        return try_all_pipe_abis(hdr_sz, ph);
@@ -2544,6 +2502,7 @@ static int check_magic_endian(u64 magic, uint64_t hdr_sz,
                return -1;
 
        ph->needs_swap = true;
+       ph->version = PERF_HEADER_VERSION_2;
 
        return 0;
 }
@@ -2614,10 +2573,9 @@ int perf_file_header__read(struct perf_file_header *header,
        memcpy(&ph->adds_features, &header->adds_features,
               sizeof(ph->adds_features));
 
-       ph->event_offset = header->event_types.offset;
-       ph->event_size   = header->event_types.size;
        ph->data_offset  = header->data.offset;
        ph->data_size    = header->data.size;
+       ph->feat_offset  = header->data.offset + header->data.size;
        return 0;
 }
 
@@ -2666,19 +2624,17 @@ static int perf_file_header__read_pipe(struct perf_pipe_file_header *header,
        return 0;
 }
 
-static int perf_header__read_pipe(struct perf_session *session, int fd)
+static int perf_header__read_pipe(struct perf_session *session)
 {
        struct perf_header *header = &session->header;
        struct perf_pipe_file_header f_header;
 
-       if (perf_file_header__read_pipe(&f_header, header, fd,
+       if (perf_file_header__read_pipe(&f_header, header, session->fd,
                                        session->repipe) < 0) {
                pr_debug("incompatible file format\n");
                return -EINVAL;
        }
 
-       session->fd = fd;
-
        return 0;
 }
 
@@ -2772,20 +2728,21 @@ static int perf_evlist__prepare_tracepoint_events(struct perf_evlist *evlist,
        return 0;
 }
 
-int perf_session__read_header(struct perf_session *session, int fd)
+int perf_session__read_header(struct perf_session *session)
 {
        struct perf_header *header = &session->header;
        struct perf_file_header f_header;
        struct perf_file_attr   f_attr;
        u64                     f_id;
        int nr_attrs, nr_ids, i, j;
+       int fd = session->fd;
 
        session->evlist = perf_evlist__new();
        if (session->evlist == NULL)
                return -ENOMEM;
 
        if (session->fd_pipe)
-               return perf_header__read_pipe(session, fd);
+               return perf_header__read_pipe(session);
 
        if (perf_file_header__read(&f_header, header, fd) < 0)
                return -EINVAL;
@@ -2839,22 +2796,9 @@ int perf_session__read_header(struct perf_session *session, int fd)
 
        symbol_conf.nr_events = nr_attrs;
 
-       if (f_header.event_types.size) {
-               lseek(fd, f_header.event_types.offset, SEEK_SET);
-               trace_events = malloc(f_header.event_types.size);
-               if (trace_events == NULL)
-                       return -ENOMEM;
-               if (perf_header__getbuffer64(header, fd, trace_events,
-                                            f_header.event_types.size))
-                       goto out_errno;
-               trace_event_count =  f_header.event_types.size / sizeof(struct perf_trace_event_type);
-       }
-
        perf_header__process_sections(header, fd, &session->pevent,
                                      perf_file_section__process);
 
-       lseek(fd, header->data_offset, SEEK_SET);
-
        if (perf_evlist__prepare_tracepoint_events(session->evlist,
                                                   session->pevent))
                goto out_delete_evlist;
@@ -2922,7 +2866,8 @@ int perf_event__synthesize_attrs(struct perf_tool *tool,
        return err;
 }
 
-int perf_event__process_attr(union perf_event *event,
+int perf_event__process_attr(struct perf_tool *tool __maybe_unused,
+                            union perf_event *event,
                             struct perf_evlist **pevlist)
 {
        u32 i, ids, n_ids;
@@ -2961,64 +2906,6 @@ int perf_event__process_attr(union perf_event *event,
        return 0;
 }
 
-int perf_event__synthesize_event_type(struct perf_tool *tool,
-                                     u64 event_id, char *name,
-                                     perf_event__handler_t process,
-                                     struct machine *machine)
-{
-       union perf_event ev;
-       size_t size = 0;
-       int err = 0;
-
-       memset(&ev, 0, sizeof(ev));
-
-       ev.event_type.event_type.event_id = event_id;
-       memset(ev.event_type.event_type.name, 0, MAX_EVENT_NAME);
-       strncpy(ev.event_type.event_type.name, name, MAX_EVENT_NAME - 1);
-
-       ev.event_type.header.type = PERF_RECORD_HEADER_EVENT_TYPE;
-       size = strlen(ev.event_type.event_type.name);
-       size = PERF_ALIGN(size, sizeof(u64));
-       ev.event_type.header.size = sizeof(ev.event_type) -
-               (sizeof(ev.event_type.event_type.name) - size);
-
-       err = process(tool, &ev, NULL, machine);
-
-       return err;
-}
-
-int perf_event__synthesize_event_types(struct perf_tool *tool,
-                                      perf_event__handler_t process,
-                                      struct machine *machine)
-{
-       struct perf_trace_event_type *type;
-       int i, err = 0;
-
-       for (i = 0; i < trace_event_count; i++) {
-               type = &trace_events[i];
-
-               err = perf_event__synthesize_event_type(tool, type->event_id,
-                                                       type->name, process,
-                                                       machine);
-               if (err) {
-                       pr_debug("failed to create perf header event type\n");
-                       return err;
-               }
-       }
-
-       return err;
-}
-
-int perf_event__process_event_type(struct perf_tool *tool __maybe_unused,
-                                  union perf_event *event)
-{
-       if (perf_header__push_event(event->event_type.event_type.event_id,
-                                   event->event_type.event_type.name) < 0)
-               return -ENOMEM;
-
-       return 0;
-}
-
 int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd,
                                        struct perf_evlist *evlist,
                                        perf_event__handler_t process)
@@ -3065,7 +2952,8 @@ int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd,
        return aligned_size;
 }
 
-int perf_event__process_tracing_data(union perf_event *event,
+int perf_event__process_tracing_data(struct perf_tool *tool __maybe_unused,
+                                    union perf_event *event,
                                     struct perf_session *session)
 {
        ssize_t size_read, padding, size = event->tracing_data.size;
index 16a3e83c584e7a08003f6c7803fdf7cf8a99246f..307c9aed972ed0d6403fe58da4d9edae4109abdf 100644 (file)
@@ -34,6 +34,11 @@ enum {
        HEADER_FEAT_BITS        = 256,
 };
 
+enum perf_header_version {
+       PERF_HEADER_VERSION_1,
+       PERF_HEADER_VERSION_2,
+};
+
 struct perf_file_section {
        u64 offset;
        u64 size;
@@ -45,6 +50,7 @@ struct perf_file_header {
        u64                             attr_size;
        struct perf_file_section        attrs;
        struct perf_file_section        data;
+       /* event_types is ignored */
        struct perf_file_section        event_types;
        DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
 };
@@ -84,28 +90,24 @@ struct perf_session_env {
 };
 
 struct perf_header {
-       bool                    needs_swap;
-       s64                     attr_offset;
-       u64                     data_offset;
-       u64                     data_size;
-       u64                     event_offset;
-       u64                     event_size;
+       enum perf_header_version        version;
+       bool                            needs_swap;
+       u64                             data_offset;
+       u64                             data_size;
+       u64                             feat_offset;
        DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
-       struct perf_session_env env;
+       struct perf_session_env         env;
 };
 
 struct perf_evlist;
 struct perf_session;
 
-int perf_session__read_header(struct perf_session *session, int fd);
+int perf_session__read_header(struct perf_session *session);
 int perf_session__write_header(struct perf_session *session,
                               struct perf_evlist *evlist,
                               int fd, bool at_exit);
 int perf_header__write_pipe(int fd);
 
-int perf_header__push_event(u64 id, const char *name);
-char *perf_header__find_event(u64 id);
-
 void perf_header__set_feat(struct perf_header *header, int feat);
 void perf_header__clear_feat(struct perf_header *header, int feat);
 bool perf_header__has_feat(const struct perf_header *header, int feat);
@@ -130,22 +132,14 @@ int perf_event__synthesize_attr(struct perf_tool *tool,
 int perf_event__synthesize_attrs(struct perf_tool *tool,
                                 struct perf_session *session,
                                 perf_event__handler_t process);
-int perf_event__process_attr(union perf_event *event, struct perf_evlist **pevlist);
-
-int perf_event__synthesize_event_type(struct perf_tool *tool,
-                                     u64 event_id, char *name,
-                                     perf_event__handler_t process,
-                                     struct machine *machine);
-int perf_event__synthesize_event_types(struct perf_tool *tool,
-                                      perf_event__handler_t process,
-                                      struct machine *machine);
-int perf_event__process_event_type(struct perf_tool *tool,
-                                  union perf_event *event);
+int perf_event__process_attr(struct perf_tool *tool, union perf_event *event,
+                            struct perf_evlist **pevlist);
 
 int perf_event__synthesize_tracing_data(struct perf_tool *tool,
                                        int fd, struct perf_evlist *evlist,
                                        perf_event__handler_t process);
-int perf_event__process_tracing_data(union perf_event *event,
+int perf_event__process_tracing_data(struct perf_tool *tool,
+                                    union perf_event *event,
                                     struct perf_session *session);
 
 int perf_event__synthesize_build_id(struct perf_tool *tool,
index b11a6cfdb414981c3f94814f8e4aa79aa83b8784..46a0d35a05e1f21aae097e7a67cea89bfe9ecddf 100644 (file)
@@ -24,7 +24,8 @@ enum hist_filter {
 struct callchain_param callchain_param = {
        .mode   = CHAIN_GRAPH_REL,
        .min_percent = 0.5,
-       .order  = ORDER_CALLEE
+       .order  = ORDER_CALLEE,
+       .key    = CCKEY_FUNCTION
 };
 
 u16 hists__col_len(struct hists *hists, enum hist_column col)
@@ -912,6 +913,7 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
                rb_link_node(&he->rb_node_in, parent, p);
                rb_insert_color(&he->rb_node_in, root);
                hists__inc_nr_entries(hists, he);
+               he->dummy = true;
        }
 out:
        return he;
index 2d3790fd99bb13f34c616524c712966d3dcf5963..1329b6b6ffe61b0f5fb97d8582a837f554b3c752 100644 (file)
@@ -141,10 +141,12 @@ struct perf_hpp {
 };
 
 struct perf_hpp_fmt {
-       int (*header)(struct perf_hpp *hpp);
-       int (*width)(struct perf_hpp *hpp);
-       int (*color)(struct perf_hpp *hpp, struct hist_entry *he);
-       int (*entry)(struct perf_hpp *hpp, struct hist_entry *he);
+       int (*header)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp);
+       int (*width)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp);
+       int (*color)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
+                    struct hist_entry *he);
+       int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
+                    struct hist_entry *he);
 
        struct list_head list;
 };
@@ -157,7 +159,7 @@ extern struct list_head perf_hpp__list;
 extern struct perf_hpp_fmt perf_hpp__format[];
 
 enum {
-       PERF_HPP__BASELINE,
+       /* Matches perf_hpp__format array. */
        PERF_HPP__OVERHEAD,
        PERF_HPP__OVERHEAD_SYS,
        PERF_HPP__OVERHEAD_US,
@@ -165,11 +167,6 @@ enum {
        PERF_HPP__OVERHEAD_GUEST_US,
        PERF_HPP__SAMPLES,
        PERF_HPP__PERIOD,
-       PERF_HPP__PERIOD_BASELINE,
-       PERF_HPP__DELTA,
-       PERF_HPP__RATIO,
-       PERF_HPP__WEIGHTED_DIFF,
-       PERF_HPP__FORMULA,
 
        PERF_HPP__MAX_INDEX
 };
@@ -177,8 +174,6 @@ enum {
 void perf_hpp__init(void);
 void perf_hpp__column_register(struct perf_hpp_fmt *format);
 void perf_hpp__column_enable(unsigned col);
-int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
-                               bool color);
 
 struct perf_evlist;
 
@@ -245,11 +240,4 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused,
 #endif
 
 unsigned int hists__sort_list_width(struct hists *self);
-
-double perf_diff__compute_delta(struct hist_entry *he, struct hist_entry *pair);
-double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair);
-s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair);
-int perf_diff__formula(struct hist_entry *he, struct hist_entry *pair,
-                      char *buf, size_t size);
-double perf_diff__period_percent(struct hist_entry *he, u64 period);
 #endif /* __PERF_HIST_H */
index 6f19c548ecc0bc96680a6a529ee844b829578396..97a80073822669accc928265fcf4b052c2e5c9cb 100644 (file)
@@ -1,3 +1,4 @@
 #include <string.h>
 
 void *memdup(const void *src, size_t len);
+int str_append(char **s, int *len, const char *a);
index b2ecad6ec46b1c87e9f2decc4b790cf497fa7933..f9f9d6381b9a8cf36fb3c23b11cbedf29fb45e9e 100644 (file)
@@ -233,7 +233,7 @@ void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size)
        return;
 }
 
-static struct thread *__machine__findnew_thread(struct machine *machine, pid_t pid,
+static struct thread *__machine__findnew_thread(struct machine *machine, pid_t tid,
                                                bool create)
 {
        struct rb_node **p = &machine->threads.rb_node;
@@ -241,23 +241,23 @@ static struct thread *__machine__findnew_thread(struct machine *machine, pid_t p
        struct thread *th;
 
        /*
-        * Font-end cache - PID lookups come in blocks,
+        * Front-end cache - TID lookups come in blocks,
         * so most of the time we dont have to look up
         * the full rbtree:
         */
-       if (machine->last_match && machine->last_match->pid == pid)
+       if (machine->last_match && machine->last_match->tid == tid)
                return machine->last_match;
 
        while (*p != NULL) {
                parent = *p;
                th = rb_entry(parent, struct thread, rb_node);
 
-               if (th->pid == pid) {
+               if (th->tid == tid) {
                        machine->last_match = th;
                        return th;
                }
 
-               if (pid < th->pid)
+               if (tid < th->tid)
                        p = &(*p)->rb_left;
                else
                        p = &(*p)->rb_right;
@@ -266,7 +266,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine, pid_t p
        if (!create)
                return NULL;
 
-       th = thread__new(pid);
+       th = thread__new(tid);
        if (th != NULL) {
                rb_link_node(&th->rb_node, parent, p);
                rb_insert_color(&th->rb_node, &machine->threads);
@@ -276,14 +276,14 @@ static struct thread *__machine__findnew_thread(struct machine *machine, pid_t p
        return th;
 }
 
-struct thread *machine__findnew_thread(struct machine *machine, pid_t pid)
+struct thread *machine__findnew_thread(struct machine *machine, pid_t tid)
 {
-       return __machine__findnew_thread(machine, pid, true);
+       return __machine__findnew_thread(machine, tid, true);
 }
 
-struct thread *machine__find_thread(struct machine *machine, pid_t pid)
+struct thread *machine__find_thread(struct machine *machine, pid_t tid)
 {
-       return __machine__findnew_thread(machine, pid, false);
+       return __machine__findnew_thread(machine, tid, false);
 }
 
 int machine__process_comm_event(struct machine *machine, union perf_event *event)
@@ -1058,11 +1058,10 @@ int machine__process_event(struct machine *machine, union perf_event *event)
        return ret;
 }
 
-static bool symbol__match_parent_regex(struct symbol *sym)
+static bool symbol__match_regex(struct symbol *sym, regex_t *regex)
 {
-       if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
+       if (sym->name && !regexec(regex, sym->name, 0, NULL, 0))
                return 1;
-
        return 0;
 }
 
@@ -1159,8 +1158,8 @@ struct branch_info *machine__resolve_bstack(struct machine *machine,
 static int machine__resolve_callchain_sample(struct machine *machine,
                                             struct thread *thread,
                                             struct ip_callchain *chain,
-                                            struct symbol **parent)
-
+                                            struct symbol **parent,
+                                            struct addr_location *root_al)
 {
        u8 cpumode = PERF_RECORD_MISC_USER;
        unsigned int i;
@@ -1211,8 +1210,15 @@ static int machine__resolve_callchain_sample(struct machine *machine,
                                           MAP__FUNCTION, ip, &al, NULL);
                if (al.sym != NULL) {
                        if (sort__has_parent && !*parent &&
-                           symbol__match_parent_regex(al.sym))
+                           symbol__match_regex(al.sym, &parent_regex))
                                *parent = al.sym;
+                       else if (have_ignore_callees && root_al &&
+                         symbol__match_regex(al.sym, &ignore_callees_regex)) {
+                               /* Treat this symbol as the root,
+                                  forgetting its callees. */
+                               *root_al = al;
+                               callchain_cursor_reset(&callchain_cursor);
+                       }
                        if (!symbol_conf.use_callchain)
                                break;
                }
@@ -1237,15 +1243,13 @@ int machine__resolve_callchain(struct machine *machine,
                               struct perf_evsel *evsel,
                               struct thread *thread,
                               struct perf_sample *sample,
-                              struct symbol **parent)
-
+                              struct symbol **parent,
+                              struct addr_location *root_al)
 {
        int ret;
 
-       callchain_cursor_reset(&callchain_cursor);
-
        ret = machine__resolve_callchain_sample(machine, thread,
-                                               sample->callchain, parent);
+                                               sample->callchain, parent, root_al);
        if (ret)
                return ret;
 
index 77940680f1fca29f1e89fd1f7ea8885f3b0e3390..5bb6244194d5c02d44d18522807fa192f301cb3a 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/rbtree.h>
 #include "map.h"
 
+struct addr_location;
 struct branch_stack;
 struct perf_evsel;
 struct perf_sample;
@@ -36,7 +37,7 @@ struct map *machine__kernel_map(struct machine *machine, enum map_type type)
        return machine->vmlinux_maps[type];
 }
 
-struct thread *machine__find_thread(struct machine *machine, pid_t pid);
+struct thread *machine__find_thread(struct machine *machine, pid_t tid);
 
 int machine__process_comm_event(struct machine *machine, union perf_event *event);
 int machine__process_exit_event(struct machine *machine, union perf_event *event);
@@ -83,7 +84,8 @@ int machine__resolve_callchain(struct machine *machine,
                               struct perf_evsel *evsel,
                               struct thread *thread,
                               struct perf_sample *sample,
-                              struct symbol **parent);
+                              struct symbol **parent,
+                              struct addr_location *root_al);
 
 /*
  * Default guest kernel is defined by parameter --guestkallsyms
@@ -99,7 +101,7 @@ static inline bool machine__is_host(struct machine *machine)
        return machine ? machine->pid == HOST_KERNEL_ID : false;
 }
 
-struct thread *machine__findnew_thread(struct machine *machine, pid_t pid);
+struct thread *machine__findnew_thread(struct machine *machine, pid_t tid);
 
 size_t machine__fprintf(struct machine *machine, FILE *fp);
 
index 995fc25db8c61c401a150b6813869047a7ccc7c3..2c460ede0a69de878b71d187ec74b59568117d92 100644 (file)
@@ -6,7 +6,7 @@
 #include "parse-options.h"
 #include "parse-events.h"
 #include "exec_cmd.h"
-#include "string.h"
+#include "linux/string.h"
 #include "symbol.h"
 #include "cache.h"
 #include "header.h"
@@ -217,6 +217,29 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
        return NULL;
 }
 
+struct tracepoint_path *tracepoint_name_to_path(const char *name)
+{
+       struct tracepoint_path *path = zalloc(sizeof(*path));
+       char *str = strchr(name, ':');
+
+       if (path == NULL || str == NULL) {
+               free(path);
+               return NULL;
+       }
+
+       path->system = strndup(name, str - name);
+       path->name = strdup(str+1);
+
+       if (path->system == NULL || path->name == NULL) {
+               free(path->system);
+               free(path->name);
+               free(path);
+               path = NULL;
+       }
+
+       return path;
+}
+
 const char *event_type(int type)
 {
        switch (type) {
@@ -241,40 +264,29 @@ const char *event_type(int type)
 
 
 
-static int __add_event(struct list_head **_list, int *idx,
+static int __add_event(struct list_head *list, int *idx,
                       struct perf_event_attr *attr,
                       char *name, struct cpu_map *cpus)
 {
        struct perf_evsel *evsel;
-       struct list_head *list = *_list;
-
-       if (!list) {
-               list = malloc(sizeof(*list));
-               if (!list)
-                       return -ENOMEM;
-               INIT_LIST_HEAD(list);
-       }
 
        event_attr_init(attr);
 
        evsel = perf_evsel__new(attr, (*idx)++);
-       if (!evsel) {
-               free(list);
+       if (!evsel)
                return -ENOMEM;
-       }
 
        evsel->cpus = cpus;
        if (name)
                evsel->name = strdup(name);
        list_add_tail(&evsel->node, list);
-       *_list = list;
        return 0;
 }
 
-static int add_event(struct list_head **_list, int *idx,
+static int add_event(struct list_head *list, int *idx,
                     struct perf_event_attr *attr, char *name)
 {
-       return __add_event(_list, idx, attr, name, NULL);
+       return __add_event(list, idx, attr, name, NULL);
 }
 
 static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size)
@@ -295,7 +307,7 @@ static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES]
        return -1;
 }
 
-int parse_events_add_cache(struct list_head **list, int *idx,
+int parse_events_add_cache(struct list_head *list, int *idx,
                           char *type, char *op_result1, char *op_result2)
 {
        struct perf_event_attr attr;
@@ -356,31 +368,21 @@ int parse_events_add_cache(struct list_head **list, int *idx,
        return add_event(list, idx, &attr, name);
 }
 
-static int add_tracepoint(struct list_head **listp, int *idx,
+static int add_tracepoint(struct list_head *list, int *idx,
                          char *sys_name, char *evt_name)
 {
        struct perf_evsel *evsel;
-       struct list_head *list = *listp;
-
-       if (!list) {
-               list = malloc(sizeof(*list));
-               if (!list)
-                       return -ENOMEM;
-               INIT_LIST_HEAD(list);
-       }
 
        evsel = perf_evsel__newtp(sys_name, evt_name, (*idx)++);
-       if (!evsel) {
-               free(list);
+       if (!evsel)
                return -ENOMEM;
-       }
 
        list_add_tail(&evsel->node, list);
-       *listp = list;
+
        return 0;
 }
 
-static int add_tracepoint_multi_event(struct list_head **list, int *idx,
+static int add_tracepoint_multi_event(struct list_head *list, int *idx,
                                      char *sys_name, char *evt_name)
 {
        char evt_path[MAXPATHLEN];
@@ -412,7 +414,7 @@ static int add_tracepoint_multi_event(struct list_head **list, int *idx,
        return ret;
 }
 
-static int add_tracepoint_event(struct list_head **list, int *idx,
+static int add_tracepoint_event(struct list_head *list, int *idx,
                                char *sys_name, char *evt_name)
 {
        return strpbrk(evt_name, "*?") ?
@@ -420,7 +422,7 @@ static int add_tracepoint_event(struct list_head **list, int *idx,
               add_tracepoint(list, idx, sys_name, evt_name);
 }
 
-static int add_tracepoint_multi_sys(struct list_head **list, int *idx,
+static int add_tracepoint_multi_sys(struct list_head *list, int *idx,
                                    char *sys_name, char *evt_name)
 {
        struct dirent *events_ent;
@@ -452,7 +454,7 @@ static int add_tracepoint_multi_sys(struct list_head **list, int *idx,
        return ret;
 }
 
-int parse_events_add_tracepoint(struct list_head **list, int *idx,
+int parse_events_add_tracepoint(struct list_head *list, int *idx,
                                char *sys, char *event)
 {
        int ret;
@@ -507,7 +509,7 @@ do {                                        \
        return 0;
 }
 
-int parse_events_add_breakpoint(struct list_head **list, int *idx,
+int parse_events_add_breakpoint(struct list_head *list, int *idx,
                                void *ptr, char *type)
 {
        struct perf_event_attr attr;
@@ -588,7 +590,7 @@ static int config_attr(struct perf_event_attr *attr,
        return 0;
 }
 
-int parse_events_add_numeric(struct list_head **list, int *idx,
+int parse_events_add_numeric(struct list_head *list, int *idx,
                             u32 type, u64 config,
                             struct list_head *head_config)
 {
@@ -621,7 +623,7 @@ static char *pmu_event_name(struct list_head *head_terms)
        return NULL;
 }
 
-int parse_events_add_pmu(struct list_head **list, int *idx,
+int parse_events_add_pmu(struct list_head *list, int *idx,
                         char *name, struct list_head *head_config)
 {
        struct perf_event_attr attr;
@@ -664,6 +666,7 @@ void parse_events__set_leader(char *name, struct list_head *list)
        leader->group_name = name ? strdup(name) : NULL;
 }
 
+/* list_event is assumed to point to malloc'ed memory */
 void parse_events_update_lists(struct list_head *list_event,
                               struct list_head *list_all)
 {
@@ -820,6 +823,32 @@ int parse_events_name(struct list_head *list, char *name)
        return 0;
 }
 
+static int parse_events__scanner(const char *str, void *data, int start_token);
+
+static int parse_events_fixup(int ret, const char *str, void *data,
+                             int start_token)
+{
+       char *o = strdup(str);
+       char *s = NULL;
+       char *t = o;
+       char *p;
+       int len = 0;
+
+       if (!o)
+               return ret;
+       while ((p = strsep(&t, ",")) != NULL) {
+               if (s)
+                       str_append(&s, &len, ",");
+               str_append(&s, &len, "cpu/");
+               str_append(&s, &len, p);
+               str_append(&s, &len, "/");
+       }
+       free(o);
+       if (!s)
+               return -ENOMEM;
+       return parse_events__scanner(s, data, start_token);
+}
+
 static int parse_events__scanner(const char *str, void *data, int start_token)
 {
        YY_BUFFER_STATE buffer;
@@ -840,6 +869,8 @@ static int parse_events__scanner(const char *str, void *data, int start_token)
        parse_events__flush_buffer(buffer, scanner);
        parse_events__delete_buffer(buffer, scanner);
        parse_events_lex_destroy(scanner);
+       if (ret && !strchr(str, '/'))
+               ret = parse_events_fixup(ret, str, data, start_token);
        return ret;
 }
 
@@ -1079,6 +1110,8 @@ int print_hwcache_events(const char *event_glob, bool name_only)
                }
        }
 
+       if (printed)
+               printf("\n");
        return printed;
 }
 
@@ -1133,11 +1166,12 @@ void print_events(const char *event_glob, bool name_only)
 
        print_hwcache_events(event_glob, name_only);
 
+       print_pmu_events(event_glob, name_only);
+
        if (event_glob != NULL)
                return;
 
        if (!name_only) {
-               printf("\n");
                printf("  %-50s [%s]\n",
                       "rNNN",
                       event_type_descriptors[PERF_TYPE_RAW]);
@@ -1237,6 +1271,4 @@ void parse_events__free_terms(struct list_head *terms)
 
        list_for_each_entry_safe(term, h, terms, list)
                free(term);
-
-       free(terms);
 }
index 8a4859315fd97266fa592ea775d993b9c003a48d..f1cb4c4b3c70acad8ae4e9febfa2a3c6b4681b6c 100644 (file)
@@ -23,6 +23,7 @@ struct tracepoint_path {
 };
 
 extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
+extern struct tracepoint_path *tracepoint_name_to_path(const char *name);
 extern bool have_tracepoints(struct list_head *evlist);
 
 const char *event_type(int type);
@@ -84,16 +85,16 @@ void parse_events__free_terms(struct list_head *terms);
 int parse_events__modifier_event(struct list_head *list, char *str, bool add);
 int parse_events__modifier_group(struct list_head *list, char *event_mod);
 int parse_events_name(struct list_head *list, char *name);
-int parse_events_add_tracepoint(struct list_head **list, int *idx,
+int parse_events_add_tracepoint(struct list_head *list, int *idx,
                                char *sys, char *event);
-int parse_events_add_numeric(struct list_head **list, int *idx,
+int parse_events_add_numeric(struct list_head *list, int *idx,
                             u32 type, u64 config,
                             struct list_head *head_config);
-int parse_events_add_cache(struct list_head **list, int *idx,
+int parse_events_add_cache(struct list_head *list, int *idx,
                           char *type, char *op_result1, char *op_result2);
-int parse_events_add_breakpoint(struct list_head **list, int *idx,
+int parse_events_add_breakpoint(struct list_head *list, int *idx,
                                void *ptr, char *type);
-int parse_events_add_pmu(struct list_head **list, int *idx,
+int parse_events_add_pmu(struct list_head *list, int *idx,
                         char *pmu , struct list_head *head_config);
 void parse_events__set_leader(char *name, struct list_head *list);
 void parse_events_update_lists(struct list_head *list_event,
index afc44c18dfe17b054fe01e10c779dbe747373558..4eb67ec333f19ce05f3c7ded7e6999e97af99f04 100644 (file)
@@ -22,6 +22,13 @@ do { \
                YYABORT; \
 } while (0)
 
+#define ALLOC_LIST(list) \
+do { \
+       list = malloc(sizeof(*list)); \
+       ABORT_ON(!list);              \
+       INIT_LIST_HEAD(list);         \
+} while (0)
+
 static inc_group_count(struct list_head *list,
                       struct parse_events_evlist *data)
 {
@@ -196,9 +203,10 @@ event_pmu:
 PE_NAME '/' event_config '/'
 {
        struct parse_events_evlist *data = _data;
-       struct list_head *list = NULL;
+       struct list_head *list;
 
-       ABORT_ON(parse_events_add_pmu(&list, &data->idx, $1, $3));
+       ALLOC_LIST(list);
+       ABORT_ON(parse_events_add_pmu(list, &data->idx, $1, $3));
        parse_events__free_terms($3);
        $$ = list;
 }
@@ -212,11 +220,12 @@ event_legacy_symbol:
 value_sym '/' event_config '/'
 {
        struct parse_events_evlist *data = _data;
-       struct list_head *list = NULL;
+       struct list_head *list;
        int type = $1 >> 16;
        int config = $1 & 255;
 
-       ABORT_ON(parse_events_add_numeric(&list, &data->idx,
+       ALLOC_LIST(list);
+       ABORT_ON(parse_events_add_numeric(list, &data->idx,
                                          type, config, $3));
        parse_events__free_terms($3);
        $$ = list;
@@ -225,11 +234,12 @@ value_sym '/' event_config '/'
 value_sym sep_slash_dc
 {
        struct parse_events_evlist *data = _data;
-       struct list_head *list = NULL;
+       struct list_head *list;
        int type = $1 >> 16;
        int config = $1 & 255;
 
-       ABORT_ON(parse_events_add_numeric(&list, &data->idx,
+       ALLOC_LIST(list);
+       ABORT_ON(parse_events_add_numeric(list, &data->idx,
                                          type, config, NULL));
        $$ = list;
 }
@@ -238,27 +248,30 @@ event_legacy_cache:
 PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
 {
        struct parse_events_evlist *data = _data;
-       struct list_head *list = NULL;
+       struct list_head *list;
 
-       ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, $5));
+       ALLOC_LIST(list);
+       ABORT_ON(parse_events_add_cache(list, &data->idx, $1, $3, $5));
        $$ = list;
 }
 |
 PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
 {
        struct parse_events_evlist *data = _data;
-       struct list_head *list = NULL;
+       struct list_head *list;
 
-       ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, NULL));
+       ALLOC_LIST(list);
+       ABORT_ON(parse_events_add_cache(list, &data->idx, $1, $3, NULL));
        $$ = list;
 }
 |
 PE_NAME_CACHE_TYPE
 {
        struct parse_events_evlist *data = _data;
-       struct list_head *list = NULL;
+       struct list_head *list;
 
-       ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, NULL, NULL));
+       ALLOC_LIST(list);
+       ABORT_ON(parse_events_add_cache(list, &data->idx, $1, NULL, NULL));
        $$ = list;
 }
 
@@ -266,9 +279,10 @@ event_legacy_mem:
 PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
 {
        struct parse_events_evlist *data = _data;
-       struct list_head *list = NULL;
+       struct list_head *list;
 
-       ABORT_ON(parse_events_add_breakpoint(&list, &data->idx,
+       ALLOC_LIST(list);
+       ABORT_ON(parse_events_add_breakpoint(list, &data->idx,
                                             (void *) $2, $4));
        $$ = list;
 }
@@ -276,9 +290,10 @@ PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
 PE_PREFIX_MEM PE_VALUE sep_dc
 {
        struct parse_events_evlist *data = _data;
-       struct list_head *list = NULL;
+       struct list_head *list;
 
-       ABORT_ON(parse_events_add_breakpoint(&list, &data->idx,
+       ALLOC_LIST(list);
+       ABORT_ON(parse_events_add_breakpoint(list, &data->idx,
                                             (void *) $2, NULL));
        $$ = list;
 }
@@ -287,9 +302,10 @@ event_legacy_tracepoint:
 PE_NAME ':' PE_NAME
 {
        struct parse_events_evlist *data = _data;
-       struct list_head *list = NULL;
+       struct list_head *list;
 
-       ABORT_ON(parse_events_add_tracepoint(&list, &data->idx, $1, $3));
+       ALLOC_LIST(list);
+       ABORT_ON(parse_events_add_tracepoint(list, &data->idx, $1, $3));
        $$ = list;
 }
 
@@ -297,9 +313,10 @@ event_legacy_numeric:
 PE_VALUE ':' PE_VALUE
 {
        struct parse_events_evlist *data = _data;
-       struct list_head *list = NULL;
+       struct list_head *list;
 
-       ABORT_ON(parse_events_add_numeric(&list, &data->idx, (u32)$1, $3, NULL));
+       ALLOC_LIST(list);
+       ABORT_ON(parse_events_add_numeric(list, &data->idx, (u32)$1, $3, NULL));
        $$ = list;
 }
 
@@ -307,9 +324,10 @@ event_legacy_raw:
 PE_RAW
 {
        struct parse_events_evlist *data = _data;
-       struct list_head *list = NULL;
+       struct list_head *list;
 
-       ABORT_ON(parse_events_add_numeric(&list, &data->idx,
+       ALLOC_LIST(list);
+       ABORT_ON(parse_events_add_numeric(list, &data->idx,
                                          PERF_TYPE_RAW, $1, NULL));
        $$ = list;
 }
index 4c6f9c490a8d79d0cc7f2367efd05440de735a7c..bc9d8069d37637835758d02e13ec3bc751d0f5e3 100644 (file)
@@ -73,7 +73,7 @@ int perf_pmu__format_parse(char *dir, struct list_head *head)
  * located at:
  * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes.
  */
-static int pmu_format(char *name, struct list_head *format)
+static int pmu_format(const char *name, struct list_head *format)
 {
        struct stat st;
        char path[PATH_MAX];
@@ -162,7 +162,7 @@ static int pmu_aliases_parse(char *dir, struct list_head *head)
  * Reading the pmu event aliases definition, which should be located at:
  * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes.
  */
-static int pmu_aliases(char *name, struct list_head *head)
+static int pmu_aliases(const char *name, struct list_head *head)
 {
        struct stat st;
        char path[PATH_MAX];
@@ -208,7 +208,7 @@ static int pmu_alias_terms(struct perf_pmu_alias *alias,
  * located at:
  * /sys/bus/event_source/devices/<dev>/type as sysfs attribute.
  */
-static int pmu_type(char *name, __u32 *type)
+static int pmu_type(const char *name, __u32 *type)
 {
        struct stat st;
        char path[PATH_MAX];
@@ -266,7 +266,7 @@ static void pmu_read_sysfs(void)
        closedir(dir);
 }
 
-static struct cpu_map *pmu_cpumask(char *name)
+static struct cpu_map *pmu_cpumask(const char *name)
 {
        struct stat st;
        char path[PATH_MAX];
@@ -293,7 +293,7 @@ static struct cpu_map *pmu_cpumask(char *name)
        return cpus;
 }
 
-static struct perf_pmu *pmu_lookup(char *name)
+static struct perf_pmu *pmu_lookup(const char *name)
 {
        struct perf_pmu *pmu;
        LIST_HEAD(format);
@@ -330,7 +330,7 @@ static struct perf_pmu *pmu_lookup(char *name)
        return pmu;
 }
 
-static struct perf_pmu *pmu_find(char *name)
+static struct perf_pmu *pmu_find(const char *name)
 {
        struct perf_pmu *pmu;
 
@@ -356,7 +356,7 @@ struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu)
        return NULL;
 }
 
-struct perf_pmu *perf_pmu__find(char *name)
+struct perf_pmu *perf_pmu__find(const char *name)
 {
        struct perf_pmu *pmu;
 
@@ -564,3 +564,76 @@ void perf_pmu__set_format(unsigned long *bits, long from, long to)
        for (b = from; b <= to; b++)
                set_bit(b, bits);
 }
+
+static char *format_alias(char *buf, int len, struct perf_pmu *pmu,
+                         struct perf_pmu_alias *alias)
+{
+       snprintf(buf, len, "%s/%s/", pmu->name, alias->name);
+       return buf;
+}
+
+static char *format_alias_or(char *buf, int len, struct perf_pmu *pmu,
+                            struct perf_pmu_alias *alias)
+{
+       snprintf(buf, len, "%s OR %s/%s/", alias->name, pmu->name, alias->name);
+       return buf;
+}
+
+static int cmp_string(const void *a, const void *b)
+{
+       const char * const *as = a;
+       const char * const *bs = b;
+       return strcmp(*as, *bs);
+}
+
+void print_pmu_events(const char *event_glob, bool name_only)
+{
+       struct perf_pmu *pmu;
+       struct perf_pmu_alias *alias;
+       char buf[1024];
+       int printed = 0;
+       int len, j;
+       char **aliases;
+
+       pmu = NULL;
+       len = 0;
+       while ((pmu = perf_pmu__scan(pmu)) != NULL)
+               list_for_each_entry(alias, &pmu->aliases, list)
+                       len++;
+       aliases = malloc(sizeof(char *) * len);
+       if (!aliases)
+               return;
+       pmu = NULL;
+       j = 0;
+       while ((pmu = perf_pmu__scan(pmu)) != NULL)
+               list_for_each_entry(alias, &pmu->aliases, list) {
+                       char *name = format_alias(buf, sizeof(buf), pmu, alias);
+                       bool is_cpu = !strcmp(pmu->name, "cpu");
+
+                       if (event_glob != NULL &&
+                           !(strglobmatch(name, event_glob) ||
+                             (!is_cpu && strglobmatch(alias->name,
+                                                      event_glob))))
+                               continue;
+                       aliases[j] = name;
+                       if (is_cpu && !name_only)
+                               aliases[j] = format_alias_or(buf, sizeof(buf),
+                                                             pmu, alias);
+                       aliases[j] = strdup(aliases[j]);
+                       j++;
+               }
+       len = j;
+       qsort(aliases, len, sizeof(char *), cmp_string);
+       for (j = 0; j < len; j++) {
+               if (name_only) {
+                       printf("%s ", aliases[j]);
+                       continue;
+               }
+               printf("  %-50s [Kernel PMU event]\n", aliases[j]);
+               free(aliases[j]);
+               printed++;
+       }
+       if (printed)
+               printf("\n");
+       free(aliases);
+}
index 32fe55b659fa93ed17e921c0bed99a07b99f09f6..6b2cbe2d4cc3a6d59a3d692770793c19ea984930 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/bitops.h>
 #include <linux/perf_event.h>
+#include <stdbool.h>
 
 enum {
        PERF_PMU_FORMAT_VALUE_CONFIG,
@@ -21,7 +22,7 @@ struct perf_pmu {
        struct list_head list;
 };
 
-struct perf_pmu *perf_pmu__find(char *name);
+struct perf_pmu *perf_pmu__find(const char *name);
 int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
                     struct list_head *head_terms);
 int perf_pmu__config_terms(struct list_head *formats,
@@ -40,5 +41,7 @@ int perf_pmu__format_parse(char *dir, struct list_head *head);
 
 struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu);
 
+void print_pmu_events(const char *event_glob, bool name_only);
+
 int perf_pmu__test(void);
 #endif /* __PMU_H */
index eacec859f2996143a7fda07e4c96544db1057e1d..a85e4ae5f3ac582381740f8b29460e6f83ae6bd6 100644 (file)
@@ -261,7 +261,8 @@ static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused,
                                    struct perf_sample *sample,
                                    struct perf_evsel *evsel,
                                    struct machine *machine __maybe_unused,
-                                   struct addr_location *al)
+                                   struct thread *thread,
+                                       struct addr_location *al)
 {
        struct format_field *field;
        static char handler[256];
@@ -272,7 +273,6 @@ static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused,
        int cpu = sample->cpu;
        void *data = sample->raw_data;
        unsigned long long nsecs = sample->time;
-       struct thread *thread = al->thread;
        char *comm = thread->comm;
 
        dSP;
@@ -351,7 +351,8 @@ static void perl_process_event_generic(union perf_event *event,
                                       struct perf_sample *sample,
                                       struct perf_evsel *evsel,
                                       struct machine *machine __maybe_unused,
-                                      struct addr_location *al __maybe_unused)
+                                      struct thread *thread __maybe_unused,
+                                          struct addr_location *al __maybe_unused)
 {
        dSP;
 
@@ -377,10 +378,11 @@ static void perl_process_event(union perf_event *event,
                               struct perf_sample *sample,
                               struct perf_evsel *evsel,
                               struct machine *machine,
-                              struct addr_location *al)
+                              struct thread *thread,
+                                  struct addr_location *al)
 {
-       perl_process_tracepoint(event, sample, evsel, machine, al);
-       perl_process_event_generic(event, sample, evsel, machine, al);
+       perl_process_tracepoint(event, sample, evsel, machine, thread, al);
+       perl_process_event_generic(event, sample, evsel, machine, thread, al);
 }
 
 static void run_start_sub(void)
index e87aa5d9696b41cca90c23bc9ba81529e449eab8..cc75a3cef388065f3164fe270487d2b06d394c72 100644 (file)
@@ -225,6 +225,7 @@ static void python_process_tracepoint(union perf_event *perf_event
                                 struct perf_sample *sample,
                                 struct perf_evsel *evsel,
                                 struct machine *machine __maybe_unused,
+                                struct thread *thread,
                                 struct addr_location *al)
 {
        PyObject *handler, *retval, *context, *t, *obj, *dict = NULL;
@@ -238,7 +239,6 @@ static void python_process_tracepoint(union perf_event *perf_event
        int cpu = sample->cpu;
        void *data = sample->raw_data;
        unsigned long long nsecs = sample->time;
-       struct thread *thread = al->thread;
        char *comm = thread->comm;
 
        t = PyTuple_New(MAX_FIELDS);
@@ -345,12 +345,12 @@ static void python_process_general_event(union perf_event *perf_event
                                         struct perf_sample *sample,
                                         struct perf_evsel *evsel,
                                         struct machine *machine __maybe_unused,
+                                        struct thread *thread,
                                         struct addr_location *al)
 {
        PyObject *handler, *retval, *t, *dict;
        static char handler_name[64];
        unsigned n = 0;
-       struct thread *thread = al->thread;
 
        /*
         * Use the MAX_FIELDS to make the function expandable, though
@@ -404,17 +404,18 @@ static void python_process_event(union perf_event *perf_event,
                                 struct perf_sample *sample,
                                 struct perf_evsel *evsel,
                                 struct machine *machine,
+                                struct thread *thread,
                                 struct addr_location *al)
 {
        switch (evsel->attr.type) {
        case PERF_TYPE_TRACEPOINT:
                python_process_tracepoint(perf_event, sample, evsel,
-                                         machine, al);
+                                         machine, thread, al);
                break;
        /* Reserve for future process_hw/sw/raw APIs */
        default:
                python_process_general_event(perf_event, sample, evsel,
-                                            machine, al);
+                                            machine, thread, al);
        }
 }
 
index cf1fe01b7e8989570991e88c8216211d30ee039e..272c9cf571229b45e09fa6af26d9471a6e61ac00 100644 (file)
@@ -1,4 +1,5 @@
 #include <linux/kernel.h>
+#include <traceevent/event-parse.h>
 
 #include <byteswap.h>
 #include <unistd.h>
@@ -12,7 +13,6 @@
 #include "sort.h"
 #include "util.h"
 #include "cpumap.h"
-#include "event-parse.h"
 #include "perf_regs.h"
 #include "vdso.h"
 
@@ -24,7 +24,7 @@ static int perf_session__open(struct perf_session *self, bool force)
                self->fd_pipe = true;
                self->fd = STDIN_FILENO;
 
-               if (perf_session__read_header(self, self->fd) < 0)
+               if (perf_session__read_header(self) < 0)
                        pr_err("incompatible file format (rerun with -v to learn more)");
 
                return 0;
@@ -56,7 +56,7 @@ static int perf_session__open(struct perf_session *self, bool force)
                goto out_close;
        }
 
-       if (perf_session__read_header(self, self->fd) < 0) {
+       if (perf_session__read_header(self) < 0) {
                pr_err("incompatible file format (rerun with -v to learn more)");
                goto out_close;
        }
@@ -193,7 +193,9 @@ void perf_session__delete(struct perf_session *self)
        vdso__exit();
 }
 
-static int process_event_synth_tracing_data_stub(union perf_event *event
+static int process_event_synth_tracing_data_stub(struct perf_tool *tool
+                                                __maybe_unused,
+                                                union perf_event *event
                                                 __maybe_unused,
                                                 struct perf_session *session
                                                __maybe_unused)
@@ -202,7 +204,8 @@ static int process_event_synth_tracing_data_stub(union perf_event *event
        return 0;
 }
 
-static int process_event_synth_attr_stub(union perf_event *event __maybe_unused,
+static int process_event_synth_attr_stub(struct perf_tool *tool __maybe_unused,
+                                        union perf_event *event __maybe_unused,
                                         struct perf_evlist **pevlist
                                         __maybe_unused)
 {
@@ -238,13 +241,6 @@ static int process_finished_round_stub(struct perf_tool *tool __maybe_unused,
        return 0;
 }
 
-static int process_event_type_stub(struct perf_tool *tool __maybe_unused,
-                                  union perf_event *event __maybe_unused)
-{
-       dump_printf(": unhandled!\n");
-       return 0;
-}
-
 static int process_finished_round(struct perf_tool *tool,
                                  union perf_event *event,
                                  struct perf_session *session);
@@ -271,8 +267,6 @@ static void perf_tool__fill_defaults(struct perf_tool *tool)
                tool->unthrottle = process_event_stub;
        if (tool->attr == NULL)
                tool->attr = process_event_synth_attr_stub;
-       if (tool->event_type == NULL)
-               tool->event_type = process_event_type_stub;
        if (tool->tracing_data == NULL)
                tool->tracing_data = process_event_synth_tracing_data_stub;
        if (tool->build_id == NULL)
@@ -921,16 +915,14 @@ static int perf_session__process_user_event(struct perf_session *session, union
        /* These events are processed right away */
        switch (event->header.type) {
        case PERF_RECORD_HEADER_ATTR:
-               err = tool->attr(event, &session->evlist);
+               err = tool->attr(tool, event, &session->evlist);
                if (err == 0)
                        perf_session__set_id_hdr_size(session);
                return err;
-       case PERF_RECORD_HEADER_EVENT_TYPE:
-               return tool->event_type(tool, event);
        case PERF_RECORD_HEADER_TRACING_DATA:
                /* setup for reading amidst mmap */
                lseek(session->fd, file_offset, SEEK_SET);
-               return tool->tracing_data(event, session);
+               return tool->tracing_data(tool, event, session);
        case PERF_RECORD_HEADER_BUILD_ID:
                return tool->build_id(tool, event, session);
        case PERF_RECORD_FINISHED_ROUND:
@@ -1091,8 +1083,10 @@ more:
                perf_event_header__bswap(&event->header);
 
        size = event->header.size;
-       if (size == 0)
-               size = 8;
+       if (size < sizeof(struct perf_event_header)) {
+               pr_err("bad event header size\n");
+               goto out_err;
+       }
 
        if (size > cur_size) {
                void *new = realloc(buf, size);
@@ -1161,8 +1155,12 @@ fetch_mmaped_event(struct perf_session *session,
        if (session->header.needs_swap)
                perf_event_header__bswap(&event->header);
 
-       if (head + event->header.size > mmap_size)
+       if (head + event->header.size > mmap_size) {
+               /* We're not fetching the event so swap back again */
+               if (session->header.needs_swap)
+                       perf_event_header__bswap(&event->header);
                return NULL;
+       }
 
        return event;
 }
@@ -1242,7 +1240,7 @@ more:
 
        size = event->header.size;
 
-       if (size == 0 ||
+       if (size < sizeof(struct perf_event_header) ||
            perf_session__process_event(session, event, tool, file_pos) < 0) {
                pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
                       file_offset + head, event->header.size,
@@ -1397,9 +1395,8 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
 
        if (symbol_conf.use_callchain && sample->callchain) {
 
-
                if (machine__resolve_callchain(machine, evsel, al.thread,
-                                              sample, NULL) != 0) {
+                                              sample, NULL, NULL) != 0) {
                        if (verbose)
                                error("Failed to resolve callchain. Skipping\n");
                        return;
index f3b235ec7bf445f4beb3f8481255c6786c2d3e35..ad8d3d4ef14ea83eaf13f0f2c56ad21bb2ab1660 100644 (file)
@@ -37,7 +37,6 @@ struct perf_session {
        int                     fd;
        bool                    fd_pipe;
        bool                    repipe;
-       char                    *cwd;
        struct ordered_samples  ordered_samples;
        char                    filename[1];
 };
index 313a5a730112fda631d4286308056bf1bfbddfe2..5f118a089519a46bb6b370536660476bc6880eda 100644 (file)
@@ -7,6 +7,8 @@ const char      default_parent_pattern[] = "^sys_|^do_page_fault";
 const char     *parent_pattern = default_parent_pattern;
 const char     default_sort_order[] = "comm,dso,symbol";
 const char     *sort_order = default_sort_order;
+regex_t                ignore_callees_regex;
+int            have_ignore_callees = 0;
 int            sort__need_collapse = 0;
 int            sort__has_parent = 0;
 int            sort__has_sym = 0;
@@ -55,14 +57,14 @@ static int64_t cmp_null(void *l, void *r)
 static int64_t
 sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
 {
-       return right->thread->pid - left->thread->pid;
+       return right->thread->tid - left->thread->tid;
 }
 
 static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
                                       size_t size, unsigned int width)
 {
        return repsep_snprintf(bf, size, "%*s:%5d", width - 6,
-                             self->thread->comm ?: "", self->thread->pid);
+                             self->thread->comm ?: "", self->thread->tid);
 }
 
 struct sort_entry sort_thread = {
@@ -77,7 +79,7 @@ struct sort_entry sort_thread = {
 static int64_t
 sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
 {
-       return right->thread->pid - left->thread->pid;
+       return right->thread->tid - left->thread->tid;
 }
 
 static int64_t
@@ -872,6 +874,8 @@ static struct sort_dimension common_sort_dimensions[] = {
        DIM(SORT_PARENT, "parent", sort_parent),
        DIM(SORT_CPU, "cpu", sort_cpu),
        DIM(SORT_SRCLINE, "srcline", sort_srcline),
+       DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
+       DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
 };
 
 #undef DIM
@@ -891,8 +895,6 @@ static struct sort_dimension bstack_sort_dimensions[] = {
 #define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
 
 static struct sort_dimension memory_sort_dimensions[] = {
-       DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
-       DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
        DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
        DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
        DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
index 45ac84c1e037595a9a0070142ef68a9f067aa422..4e80dbd271e77e245d41f2f36afdffdf8ae7ab4e 100644 (file)
@@ -29,6 +29,8 @@ extern const char *sort_order;
 extern const char default_parent_pattern[];
 extern const char *parent_pattern;
 extern const char default_sort_order[];
+extern regex_t ignore_callees_regex;
+extern int have_ignore_callees;
 extern int sort__need_collapse;
 extern int sort__has_parent;
 extern int sort__has_sym;
@@ -87,6 +89,9 @@ struct hist_entry {
 
        struct hist_entry_diff  diff;
 
+       /* We are added by hists__add_dummy_entry. */
+       bool                    dummy;
+
        /* XXX These two should move to some tree widget lib */
        u16                     row_offset;
        u16                     nr_rows;
@@ -138,6 +143,8 @@ enum sort_type {
        SORT_PARENT,
        SORT_CPU,
        SORT_SRCLINE,
+       SORT_LOCAL_WEIGHT,
+       SORT_GLOBAL_WEIGHT,
 
        /* branch stack specific sort keys */
        __SORT_BRANCH_STACK,
@@ -149,9 +156,7 @@ enum sort_type {
 
        /* memory mode specific sort keys */
        __SORT_MEMORY_MODE,
-       SORT_LOCAL_WEIGHT = __SORT_MEMORY_MODE,
-       SORT_GLOBAL_WEIGHT,
-       SORT_MEM_DADDR_SYMBOL,
+       SORT_MEM_DADDR_SYMBOL = __SORT_MEMORY_MODE,
        SORT_MEM_DADDR_DSO,
        SORT_MEM_LOCKED,
        SORT_MEM_TLB,
@@ -183,4 +188,6 @@ int setup_sorting(void);
 extern int sort_dimension__add(const char *);
 void sort__setup_elide(FILE *fp);
 
+int report_parse_ignore_callees_opt(const struct option *opt, const char *arg, int unset);
+
 #endif /* __PERF_SORT_H */
index 29c7b2cb252192b8cb9d184ef320c32265de832e..f0b0c008c5075005b562a2a5a2e938dd2644ea51 100644 (file)
@@ -387,3 +387,27 @@ void *memdup(const void *src, size_t len)
 
        return p;
 }
+
+/**
+ * str_append - reallocate string and append another
+ * @s: pointer to string pointer
+ * @len: pointer to len (initialized)
+ * @a: string to append.
+ */
+int str_append(char **s, int *len, const char *a)
+{
+       int olen = *s ? strlen(*s) : 0;
+       int nlen = olen + strlen(a) + 1;
+       if (*len < nlen) {
+               *len = *len * 2;
+               if (*len < nlen)
+                       *len = nlen;
+               *s = realloc(*s, *len);
+               if (!*s)
+                       return -ENOMEM;
+               if (olen == 0)
+                       **s = 0;
+       }
+       strcat(*s, a);
+       return 0;
+}
index d5528e1cc03a0d72a3676597897bdfd6bb6a811e..02718e728d59f9b199d0adf15d809d91de8204ca 100644 (file)
@@ -888,8 +888,11 @@ int dso__load_vmlinux(struct dso *dso, struct map *map,
        char symfs_vmlinux[PATH_MAX];
        enum dso_binary_type symtab_type;
 
-       snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s",
-                symbol_conf.symfs, vmlinux);
+       if (vmlinux[0] == '/')
+               snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s", vmlinux);
+       else
+               snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s",
+                        symbol_conf.symfs, vmlinux);
 
        if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
                symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
index 40399cbcca775c253b0c691fca69346af40fe7f3..6feeb88eb5b0165f86c535601f0250553df4aaba 100644 (file)
@@ -7,17 +7,17 @@
 #include "util.h"
 #include "debug.h"
 
-struct thread *thread__new(pid_t pid)
+struct thread *thread__new(pid_t tid)
 {
        struct thread *self = zalloc(sizeof(*self));
 
        if (self != NULL) {
                map_groups__init(&self->mg);
-               self->pid = pid;
+               self->tid = tid;
                self->ppid = -1;
                self->comm = malloc(32);
                if (self->comm)
-                       snprintf(self->comm, 32, ":%d", self->pid);
+                       snprintf(self->comm, 32, ":%d", self->tid);
        }
 
        return self;
@@ -57,7 +57,7 @@ int thread__comm_len(struct thread *self)
 
 size_t thread__fprintf(struct thread *thread, FILE *fp)
 {
-       return fprintf(fp, "Thread %d %s\n", thread->pid, thread->comm) +
+       return fprintf(fp, "Thread %d %s\n", thread->tid, thread->comm) +
               map_groups__fprintf(&thread->mg, verbose, fp);
 }
 
@@ -84,7 +84,7 @@ int thread__fork(struct thread *self, struct thread *parent)
                if (map_groups__clone(&self->mg, &parent->mg, i) < 0)
                        return -ENOMEM;
 
-       self->ppid = parent->pid;
+       self->ppid = parent->tid;
 
        return 0;
 }
index eeb7ac62b9e3ce99ad796a62a628010dd2dce927..0fe1f9c05865623e054430b50c7b79b7ec986429 100644 (file)
@@ -12,7 +12,7 @@ struct thread {
                struct list_head node;
        };
        struct map_groups       mg;
-       pid_t                   pid;
+       pid_t                   tid;
        pid_t                   ppid;
        char                    shortname[3];
        bool                    comm_set;
@@ -24,7 +24,7 @@ struct thread {
 
 struct machine;
 
-struct thread *thread__new(pid_t pid);
+struct thread *thread__new(pid_t tid);
 void thread__delete(struct thread *self);
 
 int thread__set_comm(struct thread *self, const char *comm);
@@ -47,4 +47,14 @@ void thread__find_addr_location(struct thread *thread, struct machine *machine,
                                u8 cpumode, enum map_type type, u64 addr,
                                struct addr_location *al,
                                symbol_filter_t filter);
+
+static inline void *thread__priv(struct thread *thread)
+{
+       return thread->priv;
+}
+
+static inline void thread__set_priv(struct thread *thread, void *p)
+{
+       thread->priv = p;
+}
 #endif /* __PERF_THREAD_H */
index b0e1aadba8d5b3dcfa044668baa46918dff83e5d..62b16b6165bafae5fd80cb79d1670628f1d81847 100644 (file)
@@ -18,12 +18,9 @@ typedef int (*event_sample)(struct perf_tool *tool, union perf_event *event,
 typedef int (*event_op)(struct perf_tool *tool, union perf_event *event,
                        struct perf_sample *sample, struct machine *machine);
 
-typedef int (*event_attr_op)(union perf_event *event,
+typedef int (*event_attr_op)(struct perf_tool *tool,
+                            union perf_event *event,
                             struct perf_evlist **pevlist);
-typedef int (*event_simple_op)(struct perf_tool *tool, union perf_event *event);
-
-typedef int (*event_synth_op)(union perf_event *event,
-                             struct perf_session *session);
 
 typedef int (*event_op2)(struct perf_tool *tool, union perf_event *event,
                         struct perf_session *session);
@@ -39,8 +36,7 @@ struct perf_tool {
                        throttle,
                        unthrottle;
        event_attr_op   attr;
-       event_synth_op  tracing_data;
-       event_simple_op event_type;
+       event_op2       tracing_data;
        event_op2       finished_round,
                        build_id;
        bool            ordered_samples;
index 3917eb9a8479f7a4b11e6bd1f6e39f146f159523..f3c9e551bd353f39cd68bf52ec4c1c4ea6892a2f 100644 (file)
 static int output_fd;
 
 
-static const char *find_debugfs(void)
-{
-       const char *path = perf_debugfs_mount(NULL);
-
-       if (!path)
-               pr_debug("Your kernel does not support the debugfs filesystem");
-
-       return path;
-}
-
-/*
- * Finds the path to the debugfs/tracing
- * Allocates the string and stores it.
- */
-static const char *find_tracing_dir(void)
-{
-       static char *tracing;
-       static int tracing_found;
-       const char *debugfs;
-
-       if (tracing_found)
-               return tracing;
-
-       debugfs = find_debugfs();
-       if (!debugfs)
-               return NULL;
-
-       tracing = malloc(strlen(debugfs) + 9);
-       if (!tracing)
-               return NULL;
-
-       sprintf(tracing, "%s/tracing", debugfs);
-
-       tracing_found = 1;
-       return tracing;
-}
-
-static char *get_tracing_file(const char *name)
-{
-       const char *tracing;
-       char *file;
-
-       tracing = find_tracing_dir();
-       if (!tracing)
-               return NULL;
-
-       file = malloc(strlen(tracing) + strlen(name) + 2);
-       if (!file)
-               return NULL;
-
-       sprintf(file, "%s/%s", tracing, name);
-       return file;
-}
-
-static void put_tracing_file(char *file)
-{
-       free(file);
-}
-
 int bigendian(void)
 {
        unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0};
@@ -160,7 +101,7 @@ out:
        return err;
 }
 
-static int read_header_files(void)
+static int record_header_files(void)
 {
        char *path;
        struct stat st;
@@ -299,7 +240,7 @@ out:
        return err;
 }
 
-static int read_ftrace_files(struct tracepoint_path *tps)
+static int record_ftrace_files(struct tracepoint_path *tps)
 {
        char *path;
        int ret;
@@ -328,7 +269,7 @@ static bool system_in_tp_list(char *sys, struct tracepoint_path *tps)
        return false;
 }
 
-static int read_event_files(struct tracepoint_path *tps)
+static int record_event_files(struct tracepoint_path *tps)
 {
        struct dirent *dent;
        struct stat st;
@@ -403,7 +344,7 @@ out:
        return err;
 }
 
-static int read_proc_kallsyms(void)
+static int record_proc_kallsyms(void)
 {
        unsigned int size;
        const char *path = "/proc/kallsyms";
@@ -421,7 +362,7 @@ static int read_proc_kallsyms(void)
        return record_file(path, 4);
 }
 
-static int read_ftrace_printk(void)
+static int record_ftrace_printk(void)
 {
        unsigned int size;
        char *path;
@@ -473,12 +414,27 @@ get_tracepoints_path(struct list_head *pattrs)
                if (pos->attr.type != PERF_TYPE_TRACEPOINT)
                        continue;
                ++nr_tracepoints;
+
+               if (pos->name) {
+                       ppath->next = tracepoint_name_to_path(pos->name);
+                       if (ppath->next)
+                               goto next;
+
+                       if (strchr(pos->name, ':') == NULL)
+                               goto try_id;
+
+                       goto error;
+               }
+
+try_id:
                ppath->next = tracepoint_id_to_path(pos->attr.config);
                if (!ppath->next) {
+error:
                        pr_debug("No memory to alloc tracepoints list\n");
                        put_tracepoints_path(&path);
                        return NULL;
                }
+next:
                ppath = ppath->next;
        }
 
@@ -520,8 +476,6 @@ static int tracing_data_header(void)
        else
                buf[0] = 0;
 
-       read_trace_init(buf[0], buf[0]);
-
        if (write(output_fd, buf, 1) != 1)
                return -1;
 
@@ -583,19 +537,19 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs,
        err = tracing_data_header();
        if (err)
                goto out;
-       err = read_header_files();
+       err = record_header_files();
        if (err)
                goto out;
-       err = read_ftrace_files(tps);
+       err = record_ftrace_files(tps);
        if (err)
                goto out;
-       err = read_event_files(tps);
+       err = record_event_files(tps);
        if (err)
                goto out;
-       err = read_proc_kallsyms();
+       err = record_proc_kallsyms();
        if (err)
                goto out;
-       err = read_ftrace_printk();
+       err = record_ftrace_printk();
 
 out:
        /*
index 4454835a9ebccd5d826d3f054d8d3f1a25ffc109..fe7a27d67d2b7af23a596683509769a4f1bd6e38 100644 (file)
 #include "util.h"
 #include "trace-event.h"
 
-int header_page_size_size;
-int header_page_ts_size;
-int header_page_data_offset;
-
-bool latency_format;
-
 struct pevent *read_trace_init(int file_bigendian, int host_bigendian)
 {
        struct pevent *pevent = pevent_alloc();
index af215c0d2379bb1440e9bd43fd19ca09f0e6d50b..f2112270c663d1c09f201272b7d348e5f6cf220d 100644 (file)
 
 static int input_fd;
 
-int file_bigendian;
-int host_bigendian;
-static int long_size;
-
 static ssize_t trace_data_size;
 static bool repipe;
 
@@ -216,7 +212,7 @@ static int read_ftrace_printk(struct pevent *pevent)
 static int read_header_files(struct pevent *pevent)
 {
        unsigned long long size;
-       char *header_event;
+       char *header_page;
        char buf[BUFSIZ];
        int ret = 0;
 
@@ -229,13 +225,26 @@ static int read_header_files(struct pevent *pevent)
        }
 
        size = read8(pevent);
-       skip(size);
 
-       /*
-        * The size field in the page is of type long,
-        * use that instead, since it represents the kernel.
-        */
-       long_size = header_page_size_size;
+       header_page = malloc(size);
+       if (header_page == NULL)
+               return -1;
+
+       if (do_read(header_page, size) < 0) {
+               pr_debug("did not read header page");
+               free(header_page);
+               return -1;
+       }
+
+       if (!pevent_parse_header_page(pevent, header_page, size,
+                                     pevent_get_long_size(pevent))) {
+               /*
+                * The commit field in the page is of type long,
+                * use that instead, since it represents the kernel.
+                */
+               pevent_set_long_size(pevent, pevent->header_page_size_size);
+       }
+       free(header_page);
 
        if (do_read(buf, 13) < 0)
                return -1;
@@ -246,14 +255,8 @@ static int read_header_files(struct pevent *pevent)
        }
 
        size = read8(pevent);
-       header_event = malloc(size);
-       if (header_event == NULL)
-               return -1;
-
-       if (do_read(header_event, size) < 0)
-               ret = -1;
+       skip(size);
 
-       free(header_event);
        return ret;
 }
 
@@ -349,6 +352,10 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
        int show_funcs = 0;
        int show_printk = 0;
        ssize_t size = -1;
+       int file_bigendian;
+       int host_bigendian;
+       int file_long_size;
+       int file_page_size;
        struct pevent *pevent;
        int err;
 
@@ -391,12 +398,15 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
 
        if (do_read(buf, 1) < 0)
                goto out;
-       long_size = buf[0];
+       file_long_size = buf[0];
 
-       page_size = read4(pevent);
-       if (!page_size)
+       file_page_size = read4(pevent);
+       if (!file_page_size)
                goto out;
 
+       pevent_set_long_size(pevent, file_long_size);
+       pevent_set_page_size(pevent, file_page_size);
+
        err = read_header_files(pevent);
        if (err)
                goto out;
index 8715a1006d004b2c12e21d386b34ffae0165e17d..95199e4eea978c3961a86e5e2439e61b6a3ef8a1 100644 (file)
@@ -39,7 +39,8 @@ static void process_event_unsupported(union perf_event *event __maybe_unused,
                                      struct perf_sample *sample __maybe_unused,
                                      struct perf_evsel *evsel __maybe_unused,
                                      struct machine *machine __maybe_unused,
-                                     struct addr_location *al __maybe_unused)
+                                     struct thread *thread __maybe_unused,
+                                         struct addr_location *al __maybe_unused)
 {
 }
 
index 1978c398ad8745f873cbfd2ab732315bbd34e26a..fafe1a40444a2b0785e4d41b048ee0926786fcf9 100644 (file)
@@ -1,32 +1,18 @@
 #ifndef _PERF_UTIL_TRACE_EVENT_H
 #define _PERF_UTIL_TRACE_EVENT_H
 
+#include <traceevent/event-parse.h>
 #include "parse-events.h"
-#include "event-parse.h"
 #include "session.h"
 
 struct machine;
 struct perf_sample;
 union perf_event;
 struct perf_tool;
+struct thread;
 
-extern int header_page_size_size;
-extern int header_page_ts_size;
-extern int header_page_data_offset;
-
-extern bool latency_format;
 extern struct pevent *perf_pevent;
 
-enum {
-       RINGBUF_TYPE_PADDING            = 29,
-       RINGBUF_TYPE_TIME_EXTEND        = 30,
-       RINGBUF_TYPE_TIME_STAMP         = 31,
-};
-
-#ifndef TS_SHIFT
-#define TS_SHIFT               27
-#endif
-
 int bigendian(void);
 
 struct pevent *read_trace_init(int file_bigendian, int host_bigendian);
@@ -83,7 +69,8 @@ struct scripting_ops {
                               struct perf_sample *sample,
                               struct perf_evsel *evsel,
                               struct machine *machine,
-                              struct addr_location *al);
+                              struct thread *thread,
+                                  struct addr_location *al);
        int (*generate_script) (struct pevent *pevent, const char *outfile);
 };
 
index 59d868add275d4cc5d23800c691f7e4e758a9a3d..9a0658405760e1158d1ca1f51ead1472b651058c 100644 (file)
@@ -269,3 +269,62 @@ void perf_debugfs_set_path(const char *mntpt)
        snprintf(debugfs_mountpoint, strlen(debugfs_mountpoint), "%s", mntpt);
        set_tracing_events_path(mntpt);
 }
+
+static const char *find_debugfs(void)
+{
+       const char *path = perf_debugfs_mount(NULL);
+
+       if (!path)
+               fprintf(stderr, "Your kernel does not support the debugfs filesystem");
+
+       return path;
+}
+
+/*
+ * Finds the path to the debugfs/tracing
+ * Allocates the string and stores it.
+ */
+const char *find_tracing_dir(void)
+{
+       static char *tracing;
+       static int tracing_found;
+       const char *debugfs;
+
+       if (tracing_found)
+               return tracing;
+
+       debugfs = find_debugfs();
+       if (!debugfs)
+               return NULL;
+
+       tracing = malloc(strlen(debugfs) + 9);
+       if (!tracing)
+               return NULL;
+
+       sprintf(tracing, "%s/tracing", debugfs);
+
+       tracing_found = 1;
+       return tracing;
+}
+
+char *get_tracing_file(const char *name)
+{
+       const char *tracing;
+       char *file;
+
+       tracing = find_tracing_dir();
+       if (!tracing)
+               return NULL;
+
+       file = malloc(strlen(tracing) + strlen(name) + 2);
+       if (!file)
+               return NULL;
+
+       sprintf(file, "%s/%s", tracing, name);
+       return file;
+}
+
+void put_tracing_file(char *file)
+{
+       free(file);
+}
index 2732fad039088ab97369bbe6e727b950ef6a0dcb..cc1574edcd9abbe2554c5f3d986af7427c255485 100644 (file)
@@ -80,6 +80,9 @@ extern char buildid_dir[];
 extern char tracing_events_path[];
 extern void perf_debugfs_set_path(const char *mountpoint);
 const char *perf_debugfs_mount(const char *mountpoint);
+const char *find_tracing_dir(void);
+char *get_tracing_file(const char *name);
+void put_tracing_file(char *file);
 
 /* On most systems <limits.h> would have given us this, but
  * not on some systems (e.g. GNU/Hurd).
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
index 1580dd4ace4eac20b37043c2f5c882349204ed4a..c6c8bbea174851b613f4b14365af2314f489af5d 100644 (file)
@@ -731,7 +731,10 @@ static struct kvm_memslots *install_new_memslots(struct kvm *kvm,
        update_memslots(slots, new, kvm->memslots->generation);
        rcu_assign_pointer(kvm->memslots, slots);
        synchronize_srcu_expedited(&kvm->srcu);
-       return old_memslots; 
+
+       kvm_arch_memslots_updated(kvm);
+
+       return old_memslots;
 }
 
 /*
@@ -2812,11 +2815,9 @@ static void kvm_io_bus_destroy(struct kvm_io_bus *bus)
        kfree(bus);
 }
 
-static int kvm_io_bus_sort_cmp(const void *p1, const void *p2)
+static inline int __kvm_io_bus_sort_cmp(const struct kvm_io_range *r1,
+                                        const struct kvm_io_range *r2)
 {
-       const struct kvm_io_range *r1 = p1;
-       const struct kvm_io_range *r2 = p2;
-
        if (r1->addr < r2->addr)
                return -1;
        if (r1->addr + r1->len > r2->addr + r2->len)
@@ -2824,6 +2825,11 @@ static int kvm_io_bus_sort_cmp(const void *p1, const void *p2)
        return 0;
 }
 
+static int kvm_io_bus_sort_cmp(const void *p1, const void *p2)
+{
+       return __kvm_io_bus_sort_cmp(p1, p2);
+}
+
 static int kvm_io_bus_insert_dev(struct kvm_io_bus *bus, struct kvm_io_device *dev,
                          gpa_t addr, int len)
 {
@@ -2857,17 +2863,54 @@ static int kvm_io_bus_get_first_dev(struct kvm_io_bus *bus,
 
        off = range - bus->range;
 
-       while (off > 0 && kvm_io_bus_sort_cmp(&key, &bus->range[off-1]) == 0)
+       while (off > 0 && __kvm_io_bus_sort_cmp(&key, &bus->range[off-1]) == 0)
                off--;
 
        return off;
 }
 
+static int __kvm_io_bus_write(struct kvm_io_bus *bus,
+                             struct kvm_io_range *range, const void *val)
+{
+       int idx;
+
+       idx = kvm_io_bus_get_first_dev(bus, range->addr, range->len);
+       if (idx < 0)
+               return -EOPNOTSUPP;
+
+       while (idx < bus->dev_count &&
+               __kvm_io_bus_sort_cmp(range, &bus->range[idx]) == 0) {
+               if (!kvm_iodevice_write(bus->range[idx].dev, range->addr,
+                                       range->len, val))
+                       return idx;
+               idx++;
+       }
+
+       return -EOPNOTSUPP;
+}
+
 /* kvm_io_bus_write - called under kvm->slots_lock */
 int kvm_io_bus_write(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
                     int len, const void *val)
 {
-       int idx;
+       struct kvm_io_bus *bus;
+       struct kvm_io_range range;
+       int r;
+
+       range = (struct kvm_io_range) {
+               .addr = addr,
+               .len = len,
+       };
+
+       bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu);
+       r = __kvm_io_bus_write(bus, &range, val);
+       return r < 0 ? r : 0;
+}
+
+/* kvm_io_bus_write_cookie - called under kvm->slots_lock */
+int kvm_io_bus_write_cookie(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
+                           int len, const void *val, long cookie)
+{
        struct kvm_io_bus *bus;
        struct kvm_io_range range;
 
@@ -2877,14 +2920,35 @@ int kvm_io_bus_write(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
        };
 
        bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu);
-       idx = kvm_io_bus_get_first_dev(bus, addr, len);
+
+       /* First try the device referenced by cookie. */
+       if ((cookie >= 0) && (cookie < bus->dev_count) &&
+           (__kvm_io_bus_sort_cmp(&range, &bus->range[cookie]) == 0))
+               if (!kvm_iodevice_write(bus->range[cookie].dev, addr, len,
+                                       val))
+                       return cookie;
+
+       /*
+        * cookie contained garbage; fall back to search and return the
+        * correct cookie value.
+        */
+       return __kvm_io_bus_write(bus, &range, val);
+}
+
+static int __kvm_io_bus_read(struct kvm_io_bus *bus, struct kvm_io_range *range,
+                            void *val)
+{
+       int idx;
+
+       idx = kvm_io_bus_get_first_dev(bus, range->addr, range->len);
        if (idx < 0)
                return -EOPNOTSUPP;
 
        while (idx < bus->dev_count &&
-               kvm_io_bus_sort_cmp(&range, &bus->range[idx]) == 0) {
-               if (!kvm_iodevice_write(bus->range[idx].dev, addr, len, val))
-                       return 0;
+               __kvm_io_bus_sort_cmp(range, &bus->range[idx]) == 0) {
+               if (!kvm_iodevice_read(bus->range[idx].dev, range->addr,
+                                      range->len, val))
+                       return idx;
                idx++;
        }
 
@@ -2895,9 +2959,9 @@ int kvm_io_bus_write(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
 int kvm_io_bus_read(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
                    int len, void *val)
 {
-       int idx;
        struct kvm_io_bus *bus;
        struct kvm_io_range range;
+       int r;
 
        range = (struct kvm_io_range) {
                .addr = addr,
@@ -2905,18 +2969,36 @@ int kvm_io_bus_read(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
        };
 
        bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu);
-       idx = kvm_io_bus_get_first_dev(bus, addr, len);
-       if (idx < 0)
-               return -EOPNOTSUPP;
+       r = __kvm_io_bus_read(bus, &range, val);
+       return r < 0 ? r : 0;
+}
 
-       while (idx < bus->dev_count &&
-               kvm_io_bus_sort_cmp(&range, &bus->range[idx]) == 0) {
-               if (!kvm_iodevice_read(bus->range[idx].dev, addr, len, val))
-                       return 0;
-               idx++;
-       }
+/* kvm_io_bus_read_cookie - called under kvm->slots_lock */
+int kvm_io_bus_read_cookie(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
+                          int len, void *val, long cookie)
+{
+       struct kvm_io_bus *bus;
+       struct kvm_io_range range;
 
-       return -EOPNOTSUPP;
+       range = (struct kvm_io_range) {
+               .addr = addr,
+               .len = len,
+       };
+
+       bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu);
+
+       /* First try the device referenced by cookie. */
+       if ((cookie >= 0) && (cookie < bus->dev_count) &&
+           (__kvm_io_bus_sort_cmp(&range, &bus->range[cookie]) == 0))
+               if (!kvm_iodevice_read(bus->range[cookie].dev, addr, len,
+                                      val))
+                       return cookie;
+
+       /*
+        * cookie contained garbage; fall back to search and return the
+        * correct cookie value.
+        */
+       return __kvm_io_bus_read(bus, &range, val);
 }
 
 /* Caller must hold slots_lock. */